87

I'm trying to simulate a keyboard event in Safari using JavaScript.

I have tried this:

var event = document.createEvent("KeyboardEvent");
event.initKeyboardEvent("keypress", true, true, null, false, false, false, false, 115, 0);

...and also this:

var event = document.createEvent("UIEvents");
event.initUIEvent("keypress", true, true, window, 1);
event.keyCode = 115;

After trying both approaches, however, I have the same problem: after the code has been executed, the keyCode/which properties of the event object are set to 0, not 115.

Does anyone know how to reliably create and dispatch a keyboard event in Safari? (I'd prefer to achieve it in plain JavaScript if possible.)

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
Steve Harrison
  • 121,227
  • 16
  • 87
  • 72
  • Are you trying to execute code you have defined or some key-combination the browser understands? If it's your own code, it might be best to setup an event wrapper that you can either call via a "real" keyboard interface or via some other event generator, as you have described here. Refactoring as appropriate. – Nolte Jun 07 '09 at 08:55
  • 2
    In this example, I'm trying to simulate the user pressing "s". Ultimately, I'm trying to simulate the user pressing Command-R in an Apple Dashboard Widget. – Steve Harrison Jun 07 '09 at 09:08
  • 2
    Your code solved my problem :) –  Jan 18 '11 at 14:45
  • This might be helpful: [jquery.keymasher](https://github.com/digitalBush/jquery.keymasher). – Majid Fouladpour May 07 '11 at 06:17
  • 4
    Duplicate of [Simulate JavaScript Key Events](http://stackoverflow.com/questions/596481/simulate-javascript-key-events) – Dan Dascalescu Sep 02 '15 at 06:12
  • According to the **[spec.](https://w3c.github.io/uievents/#interface-keyboardevent)**, only `key` and `code` are supported. – Scott Marcus Dec 18 '17 at 18:04
  • To those voting to close this question. It doesn't not make sense to close this question, when the other question does not have an accepted answer and this question is specific to Safari. From [review](https://stackoverflow.com/review/close/24177623) – Trenton McKinney Sep 29 '19 at 21:56

5 Answers5

44

I am working on DOM Keyboard Event Level 3 polyfill . In latest browsers or with this polyfill you can do something like this:

element.addEventListener("keydown", 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})

UPDATE:

Now my polyfill supports legacy properties "keyCode", "charCode" and "which"

var e = new KeyboardEvent("keydown", {
    bubbles : true,
    cancelable : true,
    char : "Q",
    key : "q",
    shiftKey : true,
    keyCode : 81
});

Examples here

Additionally here is cross-browser initKeyboardEvent separately from my polyfill: (gist)

Polyfill demo

termi
  • 946
  • 9
  • 8
31

Did you dispatch the event correctly?

function simulateKeyEvent(character) {
  var evt = document.createEvent("KeyboardEvent");
  (evt.initKeyEvent || evt.initKeyboardEvent)("keypress", true, true, window,
                    0, 0, 0, 0,
                    0, character.charCodeAt(0)) 
  var canceled = !body.dispatchEvent(evt);
  if(canceled) {
    // A handler called preventDefault
    alert("canceled");
  } else {
    // None of the handlers called preventDefault
    alert("not canceled");
  }
}

If you use jQuery, you could do:

function simulateKeyPress(character) {
  jQuery.event.trigger({ type : 'keypress', which : character.charCodeAt(0) });
}
tyronegcarter
  • 3,876
  • 4
  • 21
  • 24
  • Seems to be there's a mistake in the line: `evt.initKeyEvent`. In Chromium I don't have method initKeyEvent in KeyboardEvent.prototype. For me it has to be: `evt.initKeyboardEvent` – gvlasov Jul 23 '12 at 03:24
  • 4
    Is it possible to simulate control + C (copy shortcut) with this? – John John Pichler Jan 22 '13 at 23:23
  • @EdPichler There is a special API for interacting with the pasteboard, I would't do it the hard way by simulating a keyboard event. [Related SO post](http://stackoverflow.com/questions/400212/how-to-copy-to-the-clipboard-in-javascript) – 11684 Jan 30 '13 at 15:47
  • @tarun-chaudhry did you mean: `(evt.initKeyEvent || evt.initKeyboardEvent).call(evt, // etc.` I'd preserve the context of the method invocation, just in case methods are using `this` internally... – claudiopro Feb 16 '14 at 23:13
  • 1
    @claudiopro Yes, you are correct it should be `(evt.initKeyEvent || evt.initKeyboardEvent).call(evt, // etc.` – tyronegcarter Feb 18 '14 at 18:57
  • 15
    The initKeyboardEvent doesn't work in Chromium either. `event.keyCode` and `event.which`always return 0. It's a [known bug](https://code.google.com/p/chromium/issues/detail?id=327853) and the workaround is to use a regular event `var event = document.createEvent('Event'); event.initEvent('keydown', true, true); event.keyCode = 76;` – lluft Jan 06 '15 at 20:38
  • whatever you do, don't paste that code into typescript – SuperUberDuper Apr 17 '17 at 18:53
  • 9
    **Downvoted**: `initKeyEvent` and `initKeyboardEvent` are **DEPRECATED**. – Константин Ван Nov 07 '17 at 23:59
  • 4
    @K._ instead of downvoting for a previously functioning answer, stating that it's deprecated should be sufficient to give everyone a heads-up without negatively affecting tyronegcarter. This answer https://stackoverflow.com/questions/961532/firing-a-keyboard-event-in-javascript/5920206#answer-11885974 uses the modern KeyboardEvent https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/KeyboardEvent – Modular Sep 06 '18 at 10:09
  • @bit-less You're right. I didn't have to capitalize and highlight everything in bold. I feel I was overstepping a bit. That being said, I believe this is how the voting system works. Downvoting does not mean to be a total evil to someone, but to tell him what can get better in his question or answer and let the best answers at the moment float up. – Константин Ван Sep 08 '18 at 04:21
  • 1
    `Uncaught TypeError: Illegal invocation at simulateKeyEvent (:3:46)` – avalanche1 Sep 17 '20 at 11:50
  • Note that since posting this answer, the way to init an event has changed in favour of the much more sensible "passing the values into the constructor" so it's just `document.dispatchEvent(new Keyboard(`keypress`, { options : here }));` now. – Mike 'Pomax' Kamermans Mar 20 '22 at 19:08
18

This is due to a bug in Webkit.

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.

Community
  • 1
  • 1
John
  • 29,546
  • 11
  • 78
  • 79
8

The Mozilla Developer Network provides the following explanation:

  1. Create an event using event = document.createEvent("KeyboardEvent")
  2. Init the keyevent

using:

event.initKeyEvent (type, bubbles, cancelable, viewArg, 
       ctrlKeyArg, altKeyArg, shiftKeyArg, metaKeyArg, 
           keyCodeArg, charCodeArg)
  1. Dispatch the event using yourElement.dispatchEvent(event)

I don't see the last one in your code, maybe that's what you're missing. I hope this works in IE as well...

ibrahim mahrir
  • 31,174
  • 5
  • 48
  • 73
Javache
  • 3,398
  • 3
  • 21
  • 25
  • 3
    Unfortunately, Mozilla's implementation is non-standard. As for point 3, my problem is creating the correct event—dispatching the event comes after this. Also, since I'm developing for Apple's Dashboard, I don't have to worry about IE at all! (Whoopee!) – Steve Harrison Jun 08 '09 at 01:19
  • 7
    `.initKeyEvent` is now deprecated – Hampus Ahlgren Aug 18 '16 at 19:56
1

I am not very good with this but KeyboardEvent => see KeyboardEvent is initialized with initKeyEvent .
Here is an example for emitting event on <input type="text" /> element

document.getElementById("txbox").addEventListener("keypress", function(e) {
  alert("Event " + e.type + " emitted!\nKey / Char Code: " + e.keyCode + " / " + e.charCode);
}, false);

document.getElementById("btn").addEventListener("click", function(e) {
  var doc = document.getElementById("txbox");
  var kEvent = document.createEvent("KeyboardEvent");
  kEvent.initKeyEvent("keypress", true, true, null, false, false, false, false, 74, 74);
  doc.dispatchEvent(kEvent);
}, false);
<input id="txbox" type="text" value="" />
<input id="btn" type="button" value="CLICK TO EMIT KEYPRESS ON TEXTBOX" />
vutar
  • 29
  • 4
  • 7
    it shows `js:21TypeError: kEvent.initKeyEvent is not a function. (In 'kEvent.initKeyEvent("keypress", true, true, null, false, false, false, false, 74, 74)', 'kEvent.initKeyEvent' is undefined)` in safari :( – He Yifei 何一非 Oct 20 '15 at 11:50
  • It should be: var kEvent = document.createEvent("KeyboardEvent"); kEvent.initKeyboardEvent("keypress", true, true, null, false, false, false, false, 74, 74); document.dispatchEvent(kEvent); – BaseScript Jun 03 '19 at 04:16