Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Keydown Simulation in Chrome fires normally but not the correct key

I want to simulate keydown events on a given textarea element in an html page. Since I am using Chrome, I called initKeyboardEvent on my variable and I passed the keyCode I want to type into the textarea. Here is what I tried:

var keyEvent = document.createEvent('KeyboardEvent');
keyEvent.initKeyboardEvent('keydown', true, false, null, 0, false, 0, false, 77, 0);
inputNode.dispatchEvent(keyEvent);

In this code I'm typing the letter m however the textarea is only getting the keyCode 13 which is the Enter key. So, I tried an override code I saw online that sets the value to keyCodeVal, but with no success.

var keyEvent = document.createEvent('KeyboardEvent');
Object.defineProperty(keyEvent, 'keyCode', { 
                         get : function() {
                                 return this.keyCodeVal;
                         }
                        });
keyEvent.initKeyboardEvent('keydown', true, false, null, 0, false, 0, false, 77, 0);
keyEvent.keyCodeVal = 77;
inputNode.dispatchEvent(keyEvent);

Does anyone have an idea how to set the keyCode value?

like image 560
fabricemarcelin Avatar asked May 04 '12 20:05

fabricemarcelin


4 Answers

So very very close...

You just needed to override the 'which' property. Here's some sample code:

Podium = {};
Podium.keydown = function(k) {
    var oEvent = document.createEvent('KeyboardEvent');

    // Chromium Hack
    Object.defineProperty(oEvent, 'keyCode', {
                get : function() {
                    return this.keyCodeVal;
                }
    });     
    Object.defineProperty(oEvent, 'which', {
                get : function() {
                    return this.keyCodeVal;
                }
    });     

    if (oEvent.initKeyboardEvent) {
        oEvent.initKeyboardEvent("keydown", true, true, document.defaultView, false, false, false, false, k, k);
    } else {
        oEvent.initKeyEvent("keydown", true, true, document.defaultView, false, false, false, false, k, 0);
    }

    oEvent.keyCodeVal = k;

    if (oEvent.keyCode !== k) {
        alert("keyCode mismatch " + oEvent.keyCode + "(" + oEvent.which + ")");
    }

    document.dispatchEvent(oEvent);
}

Sample usage:

Podium.keydown(65);

Note: this code is not designed to work in IE, Safari, or other browsers. Well, maybe with Firefox. YMMV.

like image 102
Orwellophile Avatar answered Oct 13 '22 17:10

Orwellophile


Orwellophile's solution does work.

  • First: 'keyCode', 'charCode' and 'which' is readonly in Safari and IE9+ (at least).
  • Second: initKeyboardEvent is kind of messy. All browsers implement it in a different way. Even in webkit's there are several different implementation of initKeyboardEvent. And there is no "good" way to initKeyboardEvent in Opera.
  • Third: initKeyboardEvent is deprecated. You need to use initKeyEvent or KeyboardEvent constructor.

Here I wrote a cross-browser initKeyboardEvent function (gist):

Example:

var a = window.crossBrowser_initKeyboardEvent("keypress", {"key": 1, "char": "!", shiftKey: true})
alert(a.type + " | " + a.key + " | " + a.char + " | " + a.shiftKey)

And here is my DOM Keyboard Event Level 3 polyfill with cross-browser KeyboardEvent constructor.

Example:

var a = new KeyboardEvent("keypress", {"key": 1, "char": "!", shiftKey: true})
alert(a.type + " | " + a.key + " | " + a.char + " | " + a.shiftKey)

Example 2

Example 3

Important Note 1: charCode, keyCode and which properties is deprecated. So neither my crossBrowser_initKeyboardEvent no KeyboardEvent constructor is absolutely guaranteed right values of that properties in some browsers. You can using properties "key" and "char" instead or edit my gist to force using initEvent in browsers with read-only charCode, keyCode and which properties.

Important Note 2: keypress event is deprecated and for now unsupported in my Keyboard Event Level 3 polyfill. That's mean that key and char properties in keypress event can have random values. I am working to fix that problem to backward compatibility.

like image 40
termi Avatar answered Oct 13 '22 16:10

termi


In order to get @Orwellophile's script to work on Google Chrome 26.0.1410.65 (on Mac OS X 10.7.5, if that matters), I had to change one line: his script appears to have the paramaters of initKeyboardEvent in different order than the MDN documentation for initKeyboardEvent.

The changed line looks like this:

oEvent.initKeyboardEvent("keydown", true, true, document.defaultView, k, k, "", "", false, "");
like image 4
Dave Land Avatar answered Oct 13 '22 16:10

Dave Land


Well the above solutions did work, also thanks to @dland for the parameter tip. Here is something I found useful, if you are not able to get the events firing at the right place.

The @Orwellophile's script fires the event on document. It may be possible that the event listener is not always registered on document. I changed the last line to following and now it pretty much works every time.

document.activeElement.dispatchEvent(oEvent);

The document.activeElement always fires the event on the element where the user is currently focusing on.

like image 3
Ankit Avatar answered Oct 13 '22 18:10

Ankit