Firing a Keyboard Event in Safari, using JavaScript
Asked Answered
S

5

88

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.)

Slide answered 7/6, 2009 at 8:49 Comment(7)
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.Inainability
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.Slide
Your code solved my problem :)Amputee
This might be helpful: jquery.keymasher.Rattan
Duplicate of Simulate JavaScript Key EventsPoorly
According to the spec., only key and code are supported.Catherincatherina
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 reviewAvner
C
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

Cablegram answered 9/8, 2012 at 14:44 Comment(5)
Doesn't seem to work for making a scrollable area scroll down using arrow or page up/down keys...Poulos
Changed your jsfiddle to dispatch the event on textbox instead of document @ jsfiddle.net/vnathalye/yjc5F/974. Though it fires the keypress handler, the text doesn't get displayed in textbox. Any idea?Undertrump
@Cablegram Your demo link is deadAbrupt
Doesn't seem to work for changing the value of an input (text) element either.Poulos
The operand of a delete operator cannot be a read-only property.Thither
H
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) });
}
Helianthus answered 7/5, 2011 at 9:26 Comment(12)
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.initKeyboardEventJagged
Is it possible to simulate control + C (copy shortcut) with this?Alage
@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 postHansiain
@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...Blindfish
@Blindfish Yes, you are correct it should be (evt.initKeyEvent || evt.initKeyboardEvent).call(evt, // etc.Helianthus
The initKeyboardEvent doesn't work in Chromium either. event.keyCode and event.whichalways return 0. It's a known bug and the workaround is to use a regular event var event = document.createEvent('Event'); event.initEvent('keydown', true, true); event.keyCode = 76;Winger
whatever you do, don't paste that code into typescriptCoryza
Downvoted: initKeyEvent and initKeyboardEvent are DEPRECATED.Stays
@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 #962032 uses the modern KeyboardEvent developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/…Pskov
@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.Stays
Uncaught TypeError: Illegal invocation at simulateKeyEvent (<anonymous>:3:46)Knapp
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.Pentha
C
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.

Collide answered 22/1, 2013 at 21:43 Comment(0)
B
9

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...

Be answered 7/6, 2009 at 8:57 Comment(2)
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!)Slide
.initKeyEvent is now deprecatedZofiazoha
I
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" />
Intellectualism answered 15/2, 2015 at 12:48 Comment(2)
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 :(Madeira
It should be: var kEvent = document.createEvent("KeyboardEvent"); kEvent.initKeyboardEvent("keypress", true, true, null, false, false, false, false, 74, 74); document.dispatchEvent(kEvent);Tigre

© 2022 - 2024 — McMap. All rights reserved.