Firing a keyboard event on Chrome

I've tracked this down to a bug on Webkit where created events only contain KeyIdentifier but no keyCode/charCode as can be seen on the browser source code. There seems to be a patch going on to solve this. So I guess this is not a proper question anymore...


If you want do it in the right way, you can use DOM Keyboard Event Level 4 KeyboardEvent construct and key property.

In latest browsers or with DOM Keyboard Event Level 3/4 polyfill you can do something like this:

element.addEventListener(function(e){ console.log(e.key, e.char, e.keyCode) })

var e = new KeyboardEvent("keydown", {bubbles : true, cancelable : true, key : "Q", char : "Q", shiftKey : true});
element.dispatchEvent(e);

//If you need legacy property "keyCode".
// Note: In some browsers you can't overwrite "keyCode" property. (At least in Safari)
delete e.keyCode;
Object.defineProperty(e, "keyCode", {"value" : 666})

Example

"map event.key to character values of a normal QUERTY (en-US) layout" proposal demo

Note that keyCode and charCode are deprecated in latest Spec (www.w3.org/TR/DOM-Level-3-Events/). So the is no chance to Chrome to implement initKeyEvent with keyCode support. But you can always override this value: UPDATE: bad method:

var evt = document.createEvent('KeyboardEvent');
evt.initKeyEvent("keypress", false, true, null, false, false,
               shift, false, keyCode(key), key.charCodeAt(0));
if(evt.keyCode != keyCode(key)) {
    delete evt.keyCode;
    // Note: In some browsers you can't overwrite "keyCode" property. (At least in Safari)
    Object.defineProperty(evt, "keyCode", { keyCode(key) });
}

Or you can update event prototype: UPDATE: bad method:

// Note: In some browsers you can't overwrite "keyCode" property. (At least in Safari)
var _native_keyCode_getter = Object.getOwnPropertyDescriptor(KeyboardEvent.prototype, "keyCode");
Object.defineProperty(KeyboardEvent.prototype, "keyCode", {
    "enumerable" : true,
    "configurable" : true,
    "get" : function() {
        if("__keyCode" in this)return this["__keyCode"];

        return _native_keyCode_getter.call(this);
    },
    "set" : function(newValue) {
        return this["__keyCode"] = isNaN(newValue) ? 0 : newValue;
    }
});    

Update There are various implementation of initKeyboardEvent. In my KeyboardEvent polyfill I detect it somehow like this (gist):

var _initKeyboardEvent_type = (function( e ) {
    try {
        e.initKeyboardEvent(
            "keyup" // in DOMString typeArg
            , false // in boolean canBubbleArg
            , false // in boolean cancelableArg
            , global // in views::AbstractView viewArg
            , "+" // [test]in DOMString keyIdentifierArg | webkit event.keyIdentifier | IE9 event.key
            , 3 // [test]in unsigned long keyLocationArg | webkit event.keyIdentifier | IE9 event.location
            , true // [test]in boolean ctrlKeyArg | webkit event.shiftKey | old webkit event.ctrlKey | IE9 event.modifiersList
            , false // [test]shift | alt
            , true // [test]shift | alt
            , false // meta
            , false // altGraphKey
        );
        return ((e["keyIdentifier"] || e["key"]) == "+" && (e["keyLocation"] || e["location"]) == 3) && (
            e.ctrlKey ?
                e.altKey ? // webkit
                    1
                    :
                    3
                :
                e.shiftKey ?
                    2 // webkit
                    :
                    4 // IE9
            ) || 9 // FireFox|w3c
            ;
    }
    catch ( __e__ ) { alert("browser do not support KeyboardEvent") }
})( document.createEvent( "KeyboardEvent" ) );

var e = document.createEvent( "KeyboardEvent" );
...
if( "initKeyEvent" in e ) {//FF
    //https://developer.mozilla.org/en/DOM/event.initKeyEvent
    e.initKeyEvent( type, _bubbles, _cancelable, _view, _ctrlKey, _altKey, _shiftKey, _metaKey, _keyCode, _keyCode );
}
else if( "initKeyboardEvent" in e ) {//https://developer.mozilla.org/en/DOM/KeyboardEvent#initKeyboardEvent()
    if( _try_initKeyboardEvent ) {
        if( _initKeyboardEvent_type == 1 ) { // webkit
            //http://stackoverflow.com/a/8490774/1437207
            //https://bugs.webkit.org/show_bug.cgi?id=13368
            e.initKeyboardEvent( type, _bubbles, _cancelable, _view, _key, _location, _ctrlKey, _shiftKey, _altKey, _metaKey, _altGraphKey );
        }
        else if( _initKeyboardEvent_type == 2 ) { // old webkit
            //http://code.google.com/p/chromium/issues/detail?id=52408
            e.initKeyboardEvent( type, _bubbles, _cancelable, _view, _ctrlKey, _altKey, _shiftKey, _metaKey, _keyCode, _keyCode );
        }
        else if( _initKeyboardEvent_type == 3 ) { // webkit
            e.initKeyboardEvent( type, _bubbles, _cancelable, _view, _key, _location, _ctrlKey, _altKey, _shiftKey, _metaKey, _altGraphKey );
        }
        else if( _initKeyboardEvent_type == 4 ) { // IE9
            //http://msdn.microsoft.com/en-us/library/ie/ff975297(v=vs.85).aspx
            e.initKeyboardEvent( type, _bubbles, _cancelable, _view, _key, _location, _modifiersListArg, _repeat, _locale );
        }
        else { // FireFox|w3c
            //http://www.w3.org/TR/DOM-Level-3-Events/#events-KeyboardEvent-initKeyboardEvent
            //https://developer.mozilla.org/en/DOM/KeyboardEvent#initKeyboardEvent()
            e.initKeyboardEvent( type, _bubbles, _cancelable, _view, _char, _key, _location, _modifiersListArg, _repeat, _locale );
        }
    }
}

I just want to throw this basic snippet out there. It works in Chrome and is based on the hack mentioned by Paul Irish.
It uses charCode instead of keyCode (which can be useful in certain situation), but adapt to keyCode if you so please.

var keyboardEvent = new KeyboardEvent('keypress', {bubbles:true}); 
Object.defineProperty(keyboardEvent, 'charCode', {get:function(){return this.charCodeVal;}}); 
keyboardEvent.charCodeVal = [your char code];
document.body.dispatchEvent(keyboardEvent);

Depending on your needs, a TextEvent might work. (It worked for me for my needs - for chrome. This is not cross-browser tested, but then, the question was specifically about chrome.)

// get a reference to the DOM element you want to affect
var input = document.getElementsByTagName('input')[0];
// create a TextEvent
var textEvent = document.createEvent('TextEvent');
// initialize the TextEvent
textEvent.initTextEvent('textInput', true, true, null, String.fromCharCode(13)+"\r\n", 9, "en-US");
// dispatch ('fire') the TextEvent
input.dispatchEvent(textEvent);

You can work around the Webkit bug using createEvent('Event') rather than createEvent('KeyboardEvent'), and then assigning the keyCode property. See this answer and this example.