I'm not very satisfied with the key events in javascript. I need to capture both letters for writing (I'm writing text on <canvas>
) and functional keys (escape) for other commands.
In Firefox it works, because Firefox fires keypress
event for any key. It's very comfortable but specification directly permits it:
If supported by a user agent, this event MUST be dispatched when a key is pressed down, if and only if that key normally produces a character value.
I disagree with that specification as I see no reason for it. But as it is now, I can't do anything about it.
Problem is that Google Chrome follows that specification and doesn't fire keypress
for functional keys. It does, however, notmally fire keydown
for all keys.
My program has only one key event handler. It expects event containing keyCode
(the ID of the physical key and optionally charCode
, the equivalent character value (for keys where it makes sense).
keydown
event does not contain any character values in neither browser! It only contains the keyCode
. So if you define a Ctrl+Z combination and listen for keydown
event, your program will be broken for users that have QWERTZ layout - because the physical location of the key (keyCode
) is still the same.
If you listen for both keydown
and keypress
, character events will fire twice (beacuse character first fires keydown
and then keypress
with proper charCode
property)
Based on the above, I need to ignore keydown
event for keys that will cause keypress
. Doing so, I'll be able to capture Esc in keydown
and characters in keypress
.
How could I possibly do it?
//Keypress for character codes
div.addEventListener("keypress", function(event) {
console.log(event);
if(_this.editor.event(event)) {
console.log("Event canceled.");
event.preventDefault();
event.cancelBubble = true;
return false;
}
return true;
});
//Keydown for Esc and the likes
div.addEventListener("keydown", function(event) {
//Character events are handled by keypress
if(event.charCode!=0) //Does NOT work - in keydown, charCode is ALLWAYS 0
return true;
console.log(event);
if(_this.editor.event(event)) {
console.log("Event canceled.");
event.preventDefault();
event.cancelBubble = true;
return false;
}
return true;
});
I figured I spend a lot of time making JSFiddles and it doesn't really increase the odds of getting an answer, so I instead uploaded the actual project.
Click into the white square in Firefox, press T, type text, press Esc, press Esc. After seconds Esc, cursor should get back to normal. Try to draw and press Ctrl+Z.
Repeat the process in Google Chrome. The Escape will not work because it doesn't fire keypress
. For some reason, the Ctrl+Z fires event with keyCode
26.
@someDoge has created a fiddle which I have expanded and which now nicely shows the situation. As you can see, you can know that a key isn't character and ignore it in keypress. But you can't know that tab isn't character and cancel it in keydown
(unless you have fixed array of keycode values as @someDoge sugests in comments).
The KeyDown event occurs prior to the KeyPress event. Raised when a character generating key is pressed. The KeyPress event occurs after the KeyDown event and before the KeyUp event. Raised when a key is released.
The keydown event is fired when a key is pressed. Unlike the keypress event, the keydown event is fired for all keys, regardless of whether they produce a character value. The keydown and keyup events provide a code indicating which key is pressed, while keypress indicates which character was entered.
Both are used as per the need of your program and as per the convenience of the user. keyup Fires when the user releases a key, after the default action of that key has been performed. keydown Fires when the user depresses a key.
keypress – fires when a key that produces a character value is pressed down, fires after keydown , and before the browser processes the key. keyup – fires when any key is released, fires last, and the browser processes the key.
You need to listen for keyup
events instead of keydown
, this way you won't get two separate events generated.
Then you can handle the 2 event types with the same handler function which will either get a charCode or not, depending on if the particular key generated a 'keypress' event. As long as you prevent bubbling your handler will only be called once.
Regarding the Chrome CTRL+Z problem: I don't see how you can get a charCode if the control key is being pressed, since it seems only to generate a keyup event.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With