70

I'd just like to know the range(s) of JavaScript keyCodes that correspond to typeable characters; or alternatively, the range of non-typeable (control) characters like backspace, escape, command, shift, etc. so I can ignore them.

The reason I ask is calling String.fromCharCode() is resulting in odd characters for control keys. For example I get "[" for left command, "%" for left arrow. Weirdness like that.

devios1
  • 36,899
  • 45
  • 162
  • 260
  • 14
    You don't think I googled it first? Come on. Did you even check those results or just assume I'm an idiot? – devios1 Sep 17 '12 at 21:23
  • The word you are looking for is *printable*, most likely. Also, it seems `keyCode` is [system and implementation-dependent](https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent#Key_values), which only traduces to problems – Alexander Sep 17 '12 at 21:25
  • Do you mean "printable"? Surely by definition every key code is "typeable"... – nnnnnn Sep 17 '12 at 21:26
  • Sure, printable. I'm thinking "typeable" in the sense of it resulting in something typed, as opposed to just pressing a key that has some effect. – devios1 Sep 17 '12 at 21:27
  • 7
    I'm sure somebody has already done this. Why a) waste time, and b) increase the possibility of error? – devios1 Sep 17 '12 at 21:34
  • You can test the typed char with regex to verify if it matches the Character classes needed – willy wonka Feb 06 '17 at 19:58

6 Answers6

96

Keydown will give you the keyCode of the key pressed, without any modifications.

$("#keypresser").keydown(function(e){
    var keycode = e.keyCode;

    var valid = 
        (keycode > 47 && keycode < 58)   || // number keys
        keycode == 32 || keycode == 13   || // spacebar & return key(s) (if you want to allow carriage returns)
        (keycode > 64 && keycode < 91)   || // letter keys
        (keycode > 95 && keycode < 112)  || // numpad keys
        (keycode > 185 && keycode < 193) || // ;=,-./` (in order)
        (keycode > 218 && keycode < 223);   // [\]' (in order)

    return valid;
});

Only the number keys, letter keys, and spacebar will have keycodes correlating to String.fromCharCode as it uses Unicode values.

Keypress will be the charCode representation of the text entered. Note that this event won't fire if no text is "printed" as a result of the keypress.

$("#keypresser").keypress(function(e){
    var charcode = e.charCode;
    var char = String.fromCharCode(charcode);
    console.log(char);
});

http://jsfiddle.net/LZs2D/1/ Will demonstrate how these work.

KeyUp behaves similarly to KeyDown.

Shmiddty
  • 13,847
  • 1
  • 35
  • 52
  • 6
    Many characters are missed e.g. `,` or `%` – Alexander Elgin Feb 19 '16 at 11:47
  • 1
    @AlexanderElgin Comma is there, keycode 190. % is the same as 5, keycode 52, with the shift key pressed. – BobRodes Jun 03 '16 at 07:49
  • You should also check `e.ctrlKey === e.altKey`, because if precisely one of them is pressed then it is hotkey – Somnium Oct 26 '16 at 15:48
  • 3
    Does the first solution work well internationally? Also wouldn't it be better to check for non-valid keys? – Quentin Engles Oct 28 '17 at 00:27
  • ctrlKey and altKey properites should be considered too as the "output" character might not be anything printable – sKopheK Jun 15 '18 at 15:49
  • 3
    @QuentinEngles - I'm almost positive that it does not work internationally: http://daniel-hug.github.io/characters/#k_49 – William Oct 10 '18 at 06:14
  • @William Thanks. That makes me wonder what the international solution would be. Probably much more complicated. Something using utf8 maybe. – Quentin Engles Dec 26 '18 at 13:16
  • if (typeof evt.which === 'undefined') { // This is IE, which only fires keypress events for printable keys return true } // filter out backspace and ctrl/alt/meta key combinations if (evt.ctrlKey || evt.metaKey || evt.altKey || evt.which === 8) return false – Mohammad Javidi Jan 19 '19 at 11:35
  • 1
    Sadly, keyPress is getting deprecated – Daniel Jun 05 '19 at 22:10
24

I noticed that all characters with length of 1 ('A','B',number,symbol) is printable so I use only. I use this solution for non-english characters too:

if(e.key.length==1)
    print();
Nico Griffioen
  • 5,143
  • 2
  • 27
  • 36
Teu
  • 341
  • 3
  • 3
  • 1
    I frowned when looking at this answer as it seems to simple to work... And yet. It seems to be just what the doctor ordered! – Alexandre Roger Feb 12 '20 at 16:56
  • I realized the same and was going to post to SO and saw someone thought of it already (of course). Strangely simple and yet not widely posted. Hopefully I don't find out why in some negative edge case sometime in the future. As for now, it seems to work great! – Sean Jul 18 '20 at 23:18
  • 1
    This is almost 100% true (https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values has a list of non-character keys, all of which are >1 character long), but isn't totally true for non-latin languages. JS strings don't do unicode well (https://mathiasbynens.be/notes/javascript-unicode) and for some single inputtable printable unicode chars, `key.length` will be >1. This should work correctly if you do `[...e.key].length` though, to count characters explicitly. – Tim Perry Nov 13 '20 at 17:31
  • 2
    Oh also: in most cases you want to ignore events where ctrl/alt/meta are pressed too - Ctrl+C does not input a printable character even though `c` is printable. – Tim Perry Nov 13 '20 at 17:54
23

Just for background, the "keypress" event will give you a charCode property whenever you press a character key.

Editor.addEventListener('keypress', function(event){
    if (event.charCode) {
        //// character key
        console.log( String.fromCharCode(event.charCode) ); /// convert charCode to intended character.
    } else {
        //// control key
    }

However, the "keypress" event doesn't capture every keystroke - several keys fire before the "keypress" event.

In contrast, the "keydown" event will capture every keystroke, but it doesn't have a charCode property. So how can we tell if it's a character key? Checking on every key stroke whether the keyCode is within the lower and upper bounds for multiple ranges isn't optimally efficient. I suspect that there are also issues for characters outside of the ASCII range.

My approach is the check the length of the event "key" property. The "key" property is an alternative to "keyCode" to determine which key was pressed. For control keys, the "key" property is descriptive (e.g. "rightArrow", "F12", "return", etc.). For character keys, the "key" property for a character key is just the character (e.g "a", "A", "~", "\", etc.). Therefore, for every character key, the length of the "key" property will have length of 1; whereas control characters will have length greater than 1.

Editor.addEventListener('keydown', function(event){
    if (event.key.length == 1){ 
        //// character key
    } else {
        //// control key
    }
})
iamio
  • 1,171
  • 10
  • 8
  • 1
    That would have been brilliant but according to w3schools, Safari does not support it: https://www.w3schools.com/jsref/event_key_key.asp – Robbert May 30 '18 at 06:18
  • In my testing, Chrome does not appear to support this – gillonba Mar 22 '19 at 23:07
  • Robbert is right that Safari is still the only browser that doesn't support it - it works on Chrome for me. That's weird that it's not working for you gillonba. I am genuinely curious, so I just want to check that you are using the 'keydown' event instead of 'keypress'. The 'keypress' event won't have a 'key' property for control characters. – iamio Mar 24 '19 at 01:13
4

This article has a list of the keyCodes in Javascript:

http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes

Dave Zych
  • 21,581
  • 7
  • 51
  • 66
1

You can also use RegEx for this:

$(".input").keyup(function (event) {
    if (event.key.match(/^[\d\w]$/i)) {
      // put function to trigger when a digit or a word character is pressed here
    }

the i flag makes the expression case insensitive.

tlt
  • 358
  • 4
  • 10
  • 1
    It doesn't work like that. The character ^ has the key value "Dead" for combining characters. – Dennis Dec 05 '19 at 16:00
1

As of 2021, an easy way to do this is, through InputEvent's.

This only works for <input>, <select>, and <textarea>, which should be the majority of cases:

function handleInput(event) {
  if (event.inputType === 'insertText' || event.inputType === 'insertCompositionText') {
    console.log('Input Detected', event.data)
  }
}

element.oninput = handleInput
// or
element.addEventListener('input', handleInput)

The insertCompositionText property allows us to detect some precomposed characters.

For tags other than <input>, <select> and <textarea>, we can use keydown event with event.key.length with the fixes mentioned by Tim Perry:

function handleKeydown(event) {
  if([...event.key].length === 1 && !event.ctrlKey && !event.metaKey) {
    console.log('Key Detected', event.key)
  }
}
element.onkeydown = handleKeydown
// or
element.addEventListener('keydown', handleKeydown)

Despite this, I believe both struggle when it comes to recognising some precomposed characters and other quirks.

ryan f
  • 111
  • 1