29

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?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
fabricemarcelin
  • 1,719
  • 6
  • 25
  • 34
  • 2
    Note: manually firing an event does not generate the default action associated with that event. For example, manually firing a key event does not cause that letter to appear in a focused text input. In the case of UI events, this is important for security reasons, as it prevents scripts from simulating user actions that interact with the browser itself. https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent – Will Resond Nov 09 '16 at 02:58
  • **EDITED**: Orwellophile's solution does work. Check out this demo to see it in action + a generic event alternative : http://jsbin.com/awenaq/4 – Philip Nuzhnyy Sep 21 '12 at 00:26

6 Answers6

79

So very very close...

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

document.addEventListener('keydown', e => console.log(
'altKey                : ' + e.altKey + '\n' +
'charCode (Deprecated) : ' + e.charCode + '\n' +
'code                  : ' + e.code + '\n' +
'ctrlKey               : ' + e.ctrlKey + '\n' +
'isComposing           : ' + e.isComposing + '\n' +
'key                   : ' + e.key + '\n' +
'keyCode (Deprecated)  : ' + e.keyCode + '\n' +
'location              : ' + e.location + '\n' +
'metaKey               : ' + e.metaKey + '\n' +
'repeat                : ' + e.repeat + '\n' +
'shiftKey              : ' + e.shiftKey + '\n' +
'which (Deprecated)    : ' + e.which + '\n' +
'isTrusted             : ' + e.isTrusted + '\n' +
'type                  : ' + e.type
));

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.

Orwellophile
  • 13,235
  • 3
  • 69
  • 45
  • I used this in a Chrome extension to trigger a keydown event on a textarea (on Facebook). For some reason the site's handler is never fired, so it doesn't seem to respond. Any idea why? – freeall Sep 17 '12 at 13:57
  • 2
    It works fine for me, Version 21.0.1180.89. Note depressed key in virtual keyboard - http://nt4.com/ss/keydown-65.png. Perhaps you misunderstand exactly what it's doing. Whilst I appreciate your concerns, they are outside the scope of the original question. @sunglim:thanks for noticing :) freeall: where to begin... "Facebook Automation", "TextArea vs Input", "KeyX Events vs Changing HTML Content"... all out of scope. everyone else - this triggers events, it doesn't type for you. – Orwellophile Sep 24 '12 at 13:35
  • Works in Chrome 28 (so far). – Don Rhummy Jun 25 '13 at 06:47
  • 1
    The getters can simply return `k`. There's no need to attach a `keyCodeVal` property to the event object. – davidchambers Jul 31 '13 at 23:19
  • can someone post a non-jquery version of this? Don't need the keydown method, since it doesn't work in chrome 44.x. – johny why Aug 30 '15 at 14:14
  • That is a non-jquery version. You can tell because there aren't any `$` and it works fine in chrome 48. Check the jsbin link above. – Orwellophile Sep 10 '15 at 18:02
  • I like the chromium hack – Ramsharan Dec 27 '15 at 16:35
  • Still working in Chrome 49 on Windows 10 (unlike other "solutions" on SO). Brilliant! – Velojet Apr 28 '16 at 03:19
  • On my OSX Chrome 58, `oEvent.metaKey` would always be `true` for some reason, so I had to use the `defineProperty` hack to override it to `false`, see https://gist.github.com/ejoubaud/a6667323763eeeadaa38a26ec051cb1d For my use case, I also had to dispatch the event from `document.body` instead of `document` – ejoubaud Oct 14 '16 at 11:24
14

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.

termi
  • 946
  • 9
  • 8
  • Best description of the problem I've seen so far. +1 –  May 29 '13 at 20:04
  • @termi, I have tried to use your source to simulate event on Chrome 36, but does not work !! – Akash Kava Jul 21 '14 at 17:39
  • 1
    @AkashKava, do you try "cross-browser initKeyboardEvent function (gist)" or polyfill? Polyfill is out-of-date. I don't have much free time to fix it. But "cross-browser initKeyboardEvent function (gist)" is working for me. Can you provide an example? – termi Jul 22 '14 at 13:00
  • great stuff, @termi! if you have a chance, plz see if you can solve http://stackoverflow.com/questions/32298753/how-to-send-f11-to-chrome-with-javascript-to-switch-to-fullscreen – johny why Aug 30 '15 at 17:30
4

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, "");
Dave Land
  • 2,257
  • 1
  • 18
  • 21
3

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.

Ankit
  • 61
  • 1
  • 5
  • I think you're missing the point of SO. If you have a suggestion, put it in the comment to the answer. If you have a change, then modify the code. If you don't have the permissions to do these things, then you should most definitely not be posting your experiences and one-line changes as "Answers." Now, it may very well be that what you say is correct, but this piece of code has been online and heavily referenced since 2012, almost 5 years ago. From the amount of people who have used this, and commented on it, I know it works. If I make this edge-case change now, what then? – Orwellophile Jun 08 '16 at 09:11
0

All the solutions above are working, but I've found one case they won't.

If Dart is being used, Dart code that uses KeyboardEvents won't work on a general Event.

You'll get something like get$keyCode is undefined.

after banging my head for hours on this, I've found the following trick:

function __triggerKeyboardEvent(el, keyCode)
{
   var eventObj = document.createEventObject ?
       document.createEventObject() : document.createEvent("Events");

   var tempKeyboardObj = document.createEvent("KeyboardEvents");

   if(eventObj.initEvent){
      eventObj.initEvent("keydown", true, true);
   }
   eventObj.___dart_dispatch_record_ZxYxX_0_ = tempKeyboardObj.___dart_dispatch_record_ZxYxX_0_
   eventObj.keyCode = keyCode;
   eventObj.which = keyCode;

   el.dispatchEvent ? el.dispatchEvent(eventObj) : el.fireEvent("onkeydown", eventObj);

} 

Fooling Dart interceptor to thing our Event is actually a KeyboardEvent, did the trick.

Leaving it here, for the poor guy that is trying to test Dart app on a webkit based browser.

Fruch
  • 408
  • 5
  • 18
0

I have not managed to get it to work for me, but I found why in this thread, apparently it is no longer allowed for security reasons, some events are not reliable

JavaScript trigger an InputEvent.isTrusted = true