5

I have the following:

<textarea id="text"></textarea>
<textarea id="simulator"></textarea>
<br/>
<div onclick="simulate()">Simulate</div>

keyslog = [];
$('#text').bind('keyup keydown keypress mousedown mouseup', function(e){
  keyslog.push(e);
}

function simulate(){
    for(var i=0;i<keyslog.length;i++){
        var e = keyslog[i];
        // how to fire "e" event again on #simulator?
    }
}

My failed attempts were:

document.getElementById('simulator').dispatchEvent(e);

And

$('#simulator').trigger(e);

The question is how to trigger an event based on an already stored event object. It can be a Mouse or Keyboard event.

P.S. The example is about running a playback of pressed keys with the support of cursor changing/highlighting using mouse.

CodeOverload
  • 47,274
  • 54
  • 131
  • 219
  • http://stackoverflow.com/questions/596481/simulate-javascript-key-events – airportyh Nov 10 '11 at 02:24
  • Not sure if you can use a previous event object. But you can definitely create new ones based on the old ones. – airportyh Nov 10 '11 at 02:25
  • Are you sure that the javascript interpreter must create a new fresh object for each event? I think it can possibly reuse event objects and in that case you cannot just store them away, you need to make a copy. – 6502 Nov 10 '11 at 07:05
  • @Ryan I've been trying to figure it out a bit, I've asked a question over here that is somewhat related, it might help you out: http://stackoverflow.com/questions/8084970/dispatchevent-not-preforming-event-but-returns-true/8085157#8085157 – Incognito Nov 10 '11 at 20:19

3 Answers3

2

I think I got this close to what you wanted. Test it on jsbin here: http://jsbin.com/epaqej/18 or copy the code:

JavaScript code:

jQuery(function() {
  var keyslog = [], ctime = [], counter = 0, when = [], $simulator = $('#simulator'), $log = $('#log');
  $('#text').bind('keyup keydown keypress mousedown mouseup', function(e){
    when[counter] = Date.now(); // get the current time
    // delay_time is 0 for the first element
    // and the difference between the time past since the last event and the current event otherwise
    e.delay_time = (counter) ? (when[counter] - when[counter-1]) : 0;
    keyslog.push(e);
    counter++;
  });

  $('#simulator').bind('keyup keydown keypress mousedown mouseup', function (e) {
    // console.log(e.type + ' called on #simulator');
  });

  function simulate(current) {
    var e, text = '', char_code, simtext = '';
    // console.log('executing event ' + current + ' of  ' + keyslog.length);
    if (current < keyslog.length) {
       e = keyslog[current];
       setTimeout(function() {
         char_code = e.which || e.charCode || e.keyCode;
         text += e.type + ' called after ' + e.delay_time + '<br />';
         if (e.type === 'keypress') { 
           simtext += String.fromCharCode(char_code); 
         } else if (e.type === 'mousedown') { 
           $simulator.focus(); 
         } else if (e.type === 'mouseup') { 
           $simulator.blur(); 
         }
         $log.append(text); // write to logger
         $simulator.append(simtext); // add text to textarea if exists
         $simulator.trigger(e); // trigger the event on $simulator
         current += 1; // increase the iterator variable
         simulate(current);
       }, e.delay_time);
    } else {
        $log.append(' == FINISHED == ');
    }
  }

  $('#simulate').click(function() {
    simulate(0);
  });
});

HTML code:

<!DOCTYPE html>
<html>
<head>
<script class="jsbin" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="events.js"></script>
<meta charset=utf-8 />
<title>JS Bin</title>
<!--[if IE]>
  <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<style>
  article, aside, figure, footer, header, hgroup, 
  menu, nav, section { display: block; }
  #simulate {
    cursor: pointer; border: 2px solid #CCC; width: 80px; text-align: center;
  }
  #container, #log { float: left;}
  #container { width: 25%; }
  #log { width: 50%; }
</style>
</head>
<body>
  <div id="container">
    <h4>Write your text here:</h4>
    <textarea id="text"></textarea>
    <br/><br />
    <div id="simulate">Simulate:</div>
    <br/>
    <textarea id="simulator"></textarea>
  </div>
  <div id="log">
    <h4>Logger here</h4>
  </div>
</body>
</html>
alessioalex
  • 62,577
  • 16
  • 155
  • 122
  • An amazing effort, but are you suggesting that event dispatch cannot be used to do this auto-magically? – Incognito Nov 16 '11 at 14:44
  • To be honest I've searched a while before implementing this, but it seems the event dispatch cannot auto-magically write to a textarea and such... – alessioalex Nov 16 '11 at 14:51
  • That's what I was afraid of. I'm curious if future browser versions do have this behaviour however, or if this re-creation of events is limited to some input types. – Incognito Nov 16 '11 at 16:10
2

Ryan, this may not do exactly what you are looking for - namely, you asked for a way to rethrow events and include highlight/cursor position - but it does allow you to playback the text entry from one textarea on another textarea including the pauses between keypress, deletes, insertions, etc.

HTML

<textarea id="text"></textarea>
<textarea id="simulator"></textarea>
<br />
<div id="simulate" >Simulate</div>

Javascript

var keyslog = [];
var baseTime = 0;

$('#text').bind('keyup keydown keypress', function(e){
    if (baseTime <= 0) baseTime = e.timeStamp;
    keyslog.push({delay:e.timeStamp-baseTime, text:$('#text').val()});
});

$('#simulate').click(function () {
    $simulator = $('#simulator');

    while(keyslog.length > 0) {
        var e = keyslog.shift();

        window.setTimeout(updateText, e.delay, $simulator, e.text);
    }
});

function updateText($s, t) {
    $s.val(t);
}

jsFiddle

http://jsfiddle.net/ZtgME/1/

David Brainer
  • 6,223
  • 3
  • 18
  • 16
0

Use e.originalEvent

You'll enter an infinite loop however so be careful:

You get your events from keyslog fire each one in there.

When the event is fired it's "re-added" to the keyslog in the event handler, then the loop grows by one forever until you run out of computer.

assigning keyslog.length to a local variable before you enter the loop maybe a solution.

Sam Giles
  • 650
  • 6
  • 16