javascript keyboard buffer, part 1

I would like to capture keystrokes in JavaScript, save them to a buffer, and play them back exactly as they were typed.

There are three onkey events that can be assigned event handlers, these are,

  document.onkeydown = eventHandler
  document.onkeypress = eventHandler
  document.onkeyup = eventHandler

When one of these events is triggered, the unicode representation of a keystroke can be captured as follows,

function eventHandler(e) {
  var e = e || event;
  var key = e.keyCode ? e.keyCode : e.charCode;
  BUFFER.push(key);
}

This will add the unicode value from the onkey event to a global array called BUFFER.

Ideally, document.onkeypress would be sufficient to capture all interesting keystrokes, but implementations vary and not all keystrokes are available through onkeypress (e.g., backspace and arrow keys will not be recorded in all browsers).

However, onkeyup and onkeydown do not differentiate between uppercase and lowercase, or any key-combination involving Shift, Ctrl, Alt, etc. A combination of onkeydown and onkeypress can be used to capture the interesting keystrokes.

Some keys; such as Backspace, Space, and arrow keys; will be intercepted by the browser for navigation purposes. Capturing these can be tricky depending on the current focus. For example, when inside a form input or textarea this will be suppressed.

For demonstration sake I’d like to capture all the interesting keys and suppress them from going to the browser (essentially, capturing them in the BUFFER first before they are consumed by other tasks, such as moving the page down).

The following code will (when activated) capture and buffer the keystrokes,

function startCapture() {
  var SPECIAL = [8, 32, 37, 39, 222];
  document.onkeydown = handleKey(function(k) {return SPECIAL.contains(k)});
  document.onkeypress = handleKey(function(k) {return !SPECIAL.contains(k)});
}

//
// closure for onkey event handlers
// * parameter must be a compare function that
// * returns true IFF this events keyCode should be recorded
function handleKey(fcmpkey) { return function(e) {
  var e = e || event;
  var key = e.keyCode ? e.keyCode : e.charCode;
  if (fcmpkey(key)) {
    BUFFER.push(key);
    if (e.preventDefault) {
      e.stopPropagation();
      e.preventDefault();
    } else {
      e.cancelBubble = true;
      e.returnValue = false;
    }
  }
};}

The onkeydown event is used to handle the special characters that wouldn’t otherwise be correctly captured by onkeypress. The e.preventDefault() and e.stopPropagation() will suspend the keystrokes from propagating to the browser (e.g., Backspace navigation). In IE this same behavior is accomplished by the e.cancelBubble and e.returnValue attributes.

Most versions of IE tend to short-circuit onkey events when returnValue is set to false, for example, if onkeydown sets the returnValue to false then onkeypress and onkeyup will never be called for that keystroke. Simply put, you cannot rely on the chain of onkey (i.e., onkeydown -> onkeypress -> onkeyup) events if you are trying to, for example, suppress backspace navigation.

Now that the keystrokes are captured in the buffer you can do anything you’d like with them — you could add browser navigation, edit seemingly non-editable blocks of text, or replay the keystrokes at later times.

Next, I’d like to use the BUFFER to edit static html and replay everything that was typed.