Related: JavaScript KeyCode vs CharCode
Here is some code you can try at home or in a jsfiddle:
el.addEventListener( 'keyup', function( e ) {
console.log( 'Keyup event' );
console.log( e.keyCode );
} );
el.addEventListener( 'keypress', function( e ) {
console.log( 'Keypress event' );
console.log( e.keyCode );
} );
Why is the keyCode different?
I can understand why one should use keypress only, but what I don't understand is how two key events, given the same hit key on the keyboard, give different keyCodes.
PS: I'm not worrying about legacy browsers support, I tried this in Chrome and was surprised, and couldn't find an explanation.
The events are for completely different purposes. Use keyup and keydown for identifying physical keys and keypress for identifying typed characters. The two are fundamentally different tasks with different events; don't try to mix the two. In particular, keyCode on keypress events is usually redundant and shouldn't be used (except in older IE, but see the linked document below for more on that); for printable keypresses it's usually the same as which and charCode, although there is some variation between browsers.
Jan Wolter's article on key events, already linked to in another answer, is the definitive word on this subject for me and has tables describing what each of the different properties returns for each type of key event and each browser.
There is a good article on quirksmode.org answering exactly that question. You might also want to look at Unixpapa's results.
Well, I stumbled upon one difference when i was trying to copy user's entry from one input of the form to some other part of the form , which I had locked for my for users to edit.
What i found was, that whenever a user moved to the next label using key upon completing the input, one last keyboard entry was missed in the copied entry when I used eventListener to keypress and this got resolved on using keyup.
So, in conclusion Keypress listens to the state at the instant when the key was pressed, leaving aside the result of keypress, whereas keyup listens to the system status after the key has been pressed and includes the result of the keypress.
Related
Background:
I am writing a script that does some stuff when a user clears an input type="search" (essentially the same as type=text) using backspace or delete. I want to address the case where user highlights original text and starts typing new text, and also pasting.
Because of this I cannot use keydown (fires before input value is changed). Cannot use keypress (need to fire when backspace/delete is pressed, and it fires too early as well). Using keyup is bad because I can't clear when value === 1 (might already be several characters in the field). I can build in some slop but then it won't clear right away which looks buggy.
Question:
So the DOM input event fires right when the value is updated, which is exactly what I want (tested using jQuery on 'input'). However, I cannot find the captured key (which I need to differentiate between deleting and entering content). I couldn't find great info on the spec. It seems like this is going to be implemented in the data section of the event, which does not yet have any browser support. Does that mean it is currently impossible to get the key from the oninput event? If so, how do most developers handle this? I imagine wanting the key immediately after it is entered is very common, surely there is a decent solution for this?
Current implementation for the curious:
For the time being I am grabbing the value right after keydown by using a setTimeout of 0. This gets me both the key and the updated value, but feels dirty and requires extra handlers for onpaste and such. While writing this it occurs to me I could probably use oninput by keeping track of the last value and comparing to current to differentiate between entering and deleting, but that doesn't seem all that much better, and would still require a separate paste handler since I want my event to fire every time a user pastes, and it doesn't seem to have any flags that would let me know the event was a paste.
I decided the last suggestion of dandavis was the best workaround. I used keydown to grab key info and triggered the action on paste, empty field, or 1 character and last character was not backspace/delete (on input does not fire on enter, modifier keys, etc. so those don't need to be accounted for).
The code looks like this:
var onClear = function(action){
var lastKey;
jQueryObject.keydown(function(e){
lastKey = e.which;
});
jQueryObject.on('input', function(){
if( !this.value.length || (this.value.length === 1 && lastKey !== 46 && lastKey !== 8) ){
action();
}
});
jQueryObject.on('paste', function(){
action();
});
}
When I press a key on my keyboard, I can get the keyCode of that key using e.keyCode. But the keyCode I get does not consider the pressed alt/ctrl/shift keys, wich modify the key code.
Fortunately, I get the properties shiftKey/altKey/ctrlKey with the event so I am able to calculate the "true" key code.
But I don't know how to calculate this correctly. Where can I read about that?
Is it as easy as substracting 32 if shift ist pressed and so on, or are there much exceptions?
You're mistaken, key codes don't change because they refer to a specific key on the keyboard. Regardless of modifier keys, those codes stay the same (and even the modifier keys themselves have a key code).
Capture the keypress event, which will allow you to access character codes.
el.onkeypress = function (evt) {
alert( (evt || window.event).charCode );
}
I don't understand why you would like to calculate the "true" keyCodes. If you are making shortcuts for your site/app/whatever, you could simply check if the button was pressed was (for example) S and that Ctrl was pressed at the same time.
True keyCodes have no meaning by itself (unless you need it for something specific).
Btw, you should consider using jQuery for your project. It normalizes the keyCodes so you don't have any weird behavior in any browser (Windows and OS). I guess that is more important.
In Firefox (8) both the end key and # key have the same charCode (35). Is there a way to tell them apart?
I made a quick demo on jsfiddle. Just type in the input box and it will show you the charCode/key that you pressed.
http://jsfiddle.net/PfAeW/
I'm building a rich text editor where # triggers an autocomplete function. I need to cater to international users (UK keyboards) so looking to see if shift is being pressed would not work.
There are two kinds of codes for key events in the DOM: charCode, which represents the character for printable keys and keyCode which represents the physical key pressed on the keyboard.
It happens that the charCode of '#' is 35 and the keyCode of the end key is also 35, but they come with totally different number-to-meaning mappings.
Mootools exposes a .code on events which conflates the two codes, hence the confusion.
Just so there's an answer...
It looks like Mootools is mis-representing the keypress (which on your test also show mis-mappings of the following as well:
Key Pressed How Moo Sees It
----------- ---------------
end # 35
. (period) delete 46
( (left paren.) down 40
' (apos.) right 39
But, you may be able to use the Keyboard (coupled with the Keys list) and bind to the correct sequence. I'm not fluent in moo-tools, but given the document examples I don't see why the following wouldn't work:
var kb = new Keyboard({
defaultEventType: 'keypress'
});
kb.addEvents({
'end': fnEnd,
});
Disclaimer: More-or-less showing alternative (or so is my understanding based on docs) than solution. I do not know if the above code works, but it should. I am, however, not sure how you'd bind the above to a specific control, so that may be one limitation that Keyboard has over a direct binding.
You can checking for shift (event.code == 16) key in keydown event and preserve value of them and when keypress will be triggered you are sure if code from keydown event was 16 and now is 35 # really is pressed. Uless there is another way to check the shift is pressed:)
I am building a browser interface to a terminal. I need to catch both character (alphanumeric, dot, slash,...) and non-character key presses (arrows, F1-F12,...). Also, if the user holds some key down, it would be nice to get repeated keypresses (the function should be called repeatedly until key is released). The same goes for space key, characters,...
I want this to be as cross-browser as possible (jQuery keypress fails on that account). I have also tried using fork of jquery.hotkeys.js, but if I understand correctly, I can't catch both special and character keys in a single function (one should use keydown for former and keydown for the latter).
Is there a JS library that would allow me to catch both character and special keys?
I hope I'm not missing something obvious. :)
UPDATE To clarify: I am looking for the library that would hide the browser implementation details from me.
The onkeydown it exactly what you need. It captures all keys, even if you are holding a button it is fired repeatedly.
<input type='text' onkeydown='return myFunc(this,event)'>
<script>
function myFunc(Sender,e){
var key = e.which ? e.which : e.keyCode;
if(key == someKey){ // cancel event and do something
ev.returnValue = false;
if(e.preventDefault) e.preventDefault();
return false;
}
}
</script>
UPDATE try and test this with jQuery
$(document).ready(function(){
$('#in').keydown(fn);
});
var cnt = 0;
function fn(e){
var key = e.keyCode ? e.keyCode : e.which;
cnt++;
if(cnt == 10) {
alert('event was fired 10 times. Last time with key: '+key);
cnt = 0;
}
}
The DOM 3 Events spec includes key events, but it's still a working draft so likely not that widely supported yet but should be pretty helpful.
For turning key codes into characters, you might find Quriskmode helpful. Knowing which key was pressed and which modifiers should get you where you want to be. Note that you may have issues mapping all keyboards to the same character sets because some have keys that others don't (e.g. Microsoft "windows" key and Apple command key). A bit of trial and error might be required.
Oh, and you might find the article JavaScript Madness: Keyboard Events interesting.
I ended up using keycode.js, but am building a whole event-managing system around keydown, keypress and keyup events, because just one of the events (keydown) is not enough to determine which character was entered and which key was pressed if there is no corresponding character. Browser incompatibilities are an added bonus to this challenge. :)
Thank you both for your answers, it has helped me understand the problem fully.
I'm trying to intercept the command + keystroke in Safari. I've added an event handler as follows:
document.onkeypress = handleKeyPress;
function handleKeyPress(event) {
if ("+" === String.fromCharCode(event.charCode) && event.metaKey) {
// my code here
return false;
}
return true;
}
When I hit command shift = (shift = is + on my US keyboard), the if statement does not return true.
If I remove the event.metaKey portion of the if statement and hit shift =, the if statement does return true.
Also, if I change the matching string from "+" to "=" and hit command = (with or without the shift key), the if statement does return true.
Is there a way to actually detect the command + keypress (without assuming that the + key is shift = and checking for the event.shiftKey, since this will not be true for some non-US keyboards)?
First of all, I can't necessarily recommend using ⌘+ as a shortcut, since it already means something in Safari (namely, zoom the page). Someone might want that to still work normally. Depending on what you're building, it might make sense, but don't override the default shortcuts unless you're sure.
Anyway: Key events are tricky, often because the keyCode/charCode/which properties don't always match up with the right letter, so String.fromCharCode won't always get you a proper string. keyIdentifier is sometimes a better thing to look at, but not always (for instance, its codes for letter keys are always uppercase letters).
What I've done in the past (and I'm not sure that this is the best way to do it, but it works ok), is to instead listen for keydown and keyup events, and "stack" modifier keys. I.e. whenever a key is depressed, check whether it's a modifier key (i.e. if it's cmd, ctrl, alt, or shift). If it is, add it to the "stack" of modifiers. Do the opposite on keyup; if the released key was a modifier, remove it from the stack.
Now, back in the keydown-handler, if the key wasn't a modifier key, you can send the keydown event (which, unlike a keypress event, will have a pretty reliable keyIdentifier property to check), and the stack of modifiers along to some other callback, that'll take it from there.
In your case, such a callback would check that the cmd-key is in the stack, and that the keyIdentifier for the keydown event is "U+002B" (which is the unicode code for +).
I've put together a jsfiddle example of what I'm talking about. If you click in the "Result" pane (to make sure it's got focus), and press ⌘+, it should show the key combo you used, and write "Success!" below. Otherwise, it'll just show the key combo. On my keyboard, the plus sign is directly accessible, so the key combo I see is just "⌘+". But if you need shift to type a plus sign, you should see "⇧⌘+".
It's a generalized piece of code that's good for handling keyboard shortcuts in Safari/Mac, so you can build on it, if you want. You'll want to add a few event listeners to reset the modifier stack on blur events and such. Ideally, the modifier stack would reset automatically, as you release the keys, but since something might cause the browser, or the observed element/window/document, to lose focus, the keyup events won't be handled, and the released keys won't be removed from the stack. So check for blur events.
Register the event object in a window object level one, event = window.EE for example, then browse it with Firebug or Safari’s Web Developer Tools and see the values that are triggered when you want. So you will know what to compare against.
Sadly, I don't think there is an answer. The problem is, for CMD+SHIFT+= the charCode being pressed is 61 (=), not 43 (+). This appears to be a system-wide design, in that Mac OS X itself interprets CMD+SHIFT+= as = plus two modifiers, not + and COMMAND.
I put together a simple jsFiddle to show this: http://jsfiddle.net/ScuDj/1/
Basically, you are going to have to deal with keyboard layouts if you want to detect COMMAND +.
Alternatively, you could only support the numeric keypad + - that works consistently! (just kidding ;-)
(Also: I tried to attach to the textInput event, but couldn't get it to register globally. I think it only works on domNodes. I've not really used that event much.)