Get Character value from KeyCode in JavaScript... then trim
In my experience String.fromCharCode(e.keyCode)
is unreliable. String.fromCharCode
expects unicode charcodes as an argument; e.keyCode
returns javascript keycodes. Javascript keycodes and unicode charcodes are not the same thing! In particular, the numberpad keys return a different keycode
from the ordinary number keys (since they are different keys) while the same keycode
is returned for both upper
and lowercase
letters (you pressed the same key in both cases), despite them having different charcodes
.
For example, the ordinary number key 1 generates an event with keycode
49 while numberpad key 1 (with Numlock on) generates keycode
97. Used with String.fromCharCode
we get the following:
String.fromCharCode(49) returns "1"
String.fromCharCode(97) returns "a"
String.fromCharCode
expects unicode charcodes, not javascript keycodes. The key a generates an event with a keycode
of 65, independentant of the case of the character it would generate (there is also a modifier for if the Shift key is pressed, etc. in the event). The character a has a unicode charcode
of 61 while the character A has a charcode
of 41 (according to, for example, http://www.utf8-chartable.de/). However, those are hex
values, converting to decimal gives us a charcode
of 65 for "A" and 97 for "a".[1] This is consistent with what we get from String.fromCharCode
for these values.
My own requirement was limited to processing numbers and ordinary letters (accepting or rejecting depending on the position in the string) and letting control characters (F-keys, Ctrl-something) through. Thus I can check for the control characters, if it's not a control character I check against a range and only then do I need to get the actual character. Given I'm not worried about case (I change all letters to uppercase anyway) and have already limited the range of keycodes, I only have to worry about the numberpad keys. The following suffices for that:
String.fromCharCode((96 <= key && key <= 105)? key-48 : key)
More generally, a function to reliably return the character from a charcode
would be great (maybe as a jQuery plugin), but I don't have time to write it just now. Sorry.
I'd also mention e.which
(if you're using jQuery) which normalizes e.keyCode
and e.charCode
, so that you don't need to worry about what sort of key was pressed. The problem with combining it with String.fromCharCode
remains.
[1] I was confused for a while -. all the docs say that String.fromCharCode
expects a unicode charcode
, while in practice it seemed to work for ASCII charcodes, but that was I think due to the need to convert to decimal from hex, combined with the fact that ASCII charcodes and unicode decimal charcodes overlap for ordinary latin letters.
Maybe I didn't understand the question correctly, but can you not use keyup
if you want to capture both inputs?
$("input").bind("keyup",function(e){
var value = this.value + String.fromCharCode(e.keyCode);
});
Readable key names indexed by key code
There are relatively few key codes so I simply listed all the corresponding values in a static array so I could simply convert the number 65
into A
using keyboardMap[65]
Not all key codes map to a printable character so some other identifiable string is returned.
You may need to modify the array to suit your needs and can simply return empty strings for all the characters you don't care to translate. The following array allows me to quickly and reliably determine which key was pressed in any environment. Enjoy!
// names of known key codes (0-255)
var keyboardMap = [
"", // [0]
"", // [1]
"", // [2]
"CANCEL", // [3]
"", // [4]
"", // [5]
"HELP", // [6]
"", // [7]
"BACK_SPACE", // [8]
"TAB", // [9]
"", // [10]
"", // [11]
"CLEAR", // [12]
"ENTER", // [13]
"ENTER_SPECIAL", // [14]
"", // [15]
"SHIFT", // [16]
"CONTROL", // [17]
"ALT", // [18]
"PAUSE", // [19]
"CAPS_LOCK", // [20]
"KANA", // [21]
"EISU", // [22]
"JUNJA", // [23]
"FINAL", // [24]
"HANJA", // [25]
"", // [26]
"ESCAPE", // [27]
"CONVERT", // [28]
"NONCONVERT", // [29]
"ACCEPT", // [30]
"MODECHANGE", // [31]
"SPACE", // [32]
"PAGE_UP", // [33]
"PAGE_DOWN", // [34]
"END", // [35]
"HOME", // [36]
"LEFT", // [37]
"UP", // [38]
"RIGHT", // [39]
"DOWN", // [40]
"SELECT", // [41]
"PRINT", // [42]
"EXECUTE", // [43]
"PRINTSCREEN", // [44]
"INSERT", // [45]
"DELETE", // [46]
"", // [47]
"0", // [48]
"1", // [49]
"2", // [50]
"3", // [51]
"4", // [52]
"5", // [53]
"6", // [54]
"7", // [55]
"8", // [56]
"9", // [57]
"COLON", // [58]
"SEMICOLON", // [59]
"LESS_THAN", // [60]
"EQUALS", // [61]
"GREATER_THAN", // [62]
"QUESTION_MARK", // [63]
"AT", // [64]
"A", // [65]
"B", // [66]
"C", // [67]
"D", // [68]
"E", // [69]
"F", // [70]
"G", // [71]
"H", // [72]
"I", // [73]
"J", // [74]
"K", // [75]
"L", // [76]
"M", // [77]
"N", // [78]
"O", // [79]
"P", // [80]
"Q", // [81]
"R", // [82]
"S", // [83]
"T", // [84]
"U", // [85]
"V", // [86]
"W", // [87]
"X", // [88]
"Y", // [89]
"Z", // [90]
"OS_KEY", // [91] Windows Key (Windows) or Command Key (Mac)
"", // [92]
"CONTEXT_MENU", // [93]
"", // [94]
"SLEEP", // [95]
"NUMPAD0", // [96]
"NUMPAD1", // [97]
"NUMPAD2", // [98]
"NUMPAD3", // [99]
"NUMPAD4", // [100]
"NUMPAD5", // [101]
"NUMPAD6", // [102]
"NUMPAD7", // [103]
"NUMPAD8", // [104]
"NUMPAD9", // [105]
"MULTIPLY", // [106]
"ADD", // [107]
"SEPARATOR", // [108]
"SUBTRACT", // [109]
"DECIMAL", // [110]
"DIVIDE", // [111]
"F1", // [112]
"F2", // [113]
"F3", // [114]
"F4", // [115]
"F5", // [116]
"F6", // [117]
"F7", // [118]
"F8", // [119]
"F9", // [120]
"F10", // [121]
"F11", // [122]
"F12", // [123]
"F13", // [124]
"F14", // [125]
"F15", // [126]
"F16", // [127]
"F17", // [128]
"F18", // [129]
"F19", // [130]
"F20", // [131]
"F21", // [132]
"F22", // [133]
"F23", // [134]
"F24", // [135]
"", // [136]
"", // [137]
"", // [138]
"", // [139]
"", // [140]
"", // [141]
"", // [142]
"", // [143]
"NUM_LOCK", // [144]
"SCROLL_LOCK", // [145]
"WIN_OEM_FJ_JISHO", // [146]
"WIN_OEM_FJ_MASSHOU", // [147]
"WIN_OEM_FJ_TOUROKU", // [148]
"WIN_OEM_FJ_LOYA", // [149]
"WIN_OEM_FJ_ROYA", // [150]
"", // [151]
"", // [152]
"", // [153]
"", // [154]
"", // [155]
"", // [156]
"", // [157]
"", // [158]
"", // [159]
"CIRCUMFLEX", // [160]
"EXCLAMATION", // [161]
"DOUBLE_QUOTE", // [162]
"HASH", // [163]
"DOLLAR", // [164]
"PERCENT", // [165]
"AMPERSAND", // [166]
"UNDERSCORE", // [167]
"OPEN_PAREN", // [168]
"CLOSE_PAREN", // [169]
"ASTERISK", // [170]
"PLUS", // [171]
"PIPE", // [172]
"HYPHEN_MINUS", // [173]
"OPEN_CURLY_BRACKET", // [174]
"CLOSE_CURLY_BRACKET", // [175]
"TILDE", // [176]
"", // [177]
"", // [178]
"", // [179]
"", // [180]
"VOLUME_MUTE", // [181]
"VOLUME_DOWN", // [182]
"VOLUME_UP", // [183]
"", // [184]
"", // [185]
"SEMICOLON", // [186]
"EQUALS", // [187]
"COMMA", // [188]
"MINUS", // [189]
"PERIOD", // [190]
"SLASH", // [191]
"BACK_QUOTE", // [192]
"", // [193]
"", // [194]
"", // [195]
"", // [196]
"", // [197]
"", // [198]
"", // [199]
"", // [200]
"", // [201]
"", // [202]
"", // [203]
"", // [204]
"", // [205]
"", // [206]
"", // [207]
"", // [208]
"", // [209]
"", // [210]
"", // [211]
"", // [212]
"", // [213]
"", // [214]
"", // [215]
"", // [216]
"", // [217]
"", // [218]
"OPEN_BRACKET", // [219]
"BACK_SLASH", // [220]
"CLOSE_BRACKET", // [221]
"QUOTE", // [222]
"", // [223]
"META", // [224]
"ALTGR", // [225]
"", // [226]
"WIN_ICO_HELP", // [227]
"WIN_ICO_00", // [228]
"", // [229]
"WIN_ICO_CLEAR", // [230]
"", // [231]
"", // [232]
"WIN_OEM_RESET", // [233]
"WIN_OEM_JUMP", // [234]
"WIN_OEM_PA1", // [235]
"WIN_OEM_PA2", // [236]
"WIN_OEM_PA3", // [237]
"WIN_OEM_WSCTRL", // [238]
"WIN_OEM_CUSEL", // [239]
"WIN_OEM_ATTN", // [240]
"WIN_OEM_FINISH", // [241]
"WIN_OEM_COPY", // [242]
"WIN_OEM_AUTO", // [243]
"WIN_OEM_ENLW", // [244]
"WIN_OEM_BACKTAB", // [245]
"ATTN", // [246]
"CRSEL", // [247]
"EXSEL", // [248]
"EREOF", // [249]
"PLAY", // [250]
"ZOOM", // [251]
"", // [252]
"PA1", // [253]
"WIN_OEM_CLEAR", // [254]
"" // [255]
];
Note: The position of each value in the array above is important. The
""
are placeholders for codes with unknown values.
Try the following code snippet using this static array lookup approach...
var keyCodes = [];
$("#reset").click(function() {
keyCodes = [];
$("#in").val("");
$("#key-codes").html("var keyCodes = [ ];");
$("#key-names").html("var keyNames = [ ];");
});
$(document).keydown(function(e) {
keyCodes.push(e.which);
updateOutput();
});
function updateOutput() {
var kC = "var keyCodes = [ ";
var kN = "var keyNames = [ ";
var len = keyCodes.length;
for (var i = 0; i < len; i++) {
kC += keyCodes[i];
kN += "'"+keyboardMap[keyCodes[i]]+"'";
if (i !== (len - 1)) {
kC += ", ";
kN += ", ";
}
}
kC += " ];";
kN += " ];";
$("#key-codes").html(kC);
$("#key-names").html(kN);
}
var keyboardMap = [
"", // [0]
"", // [1]
"", // [2]
"CANCEL", // [3]
"", // [4]
"", // [5]
"HELP", // [6]
"", // [7]
"BACK_SPACE", // [8]
"TAB", // [9]
"", // [10]
"", // [11]
"CLEAR", // [12]
"ENTER", // [13]
"ENTER_SPECIAL", // [14]
"", // [15]
"SHIFT", // [16]
"CONTROL", // [17]
"ALT", // [18]
"PAUSE", // [19]
"CAPS_LOCK", // [20]
"KANA", // [21]
"EISU", // [22]
"JUNJA", // [23]
"FINAL", // [24]
"HANJA", // [25]
"", // [26]
"ESCAPE", // [27]
"CONVERT", // [28]
"NONCONVERT", // [29]
"ACCEPT", // [30]
"MODECHANGE", // [31]
"SPACE", // [32]
"PAGE_UP", // [33]
"PAGE_DOWN", // [34]
"END", // [35]
"HOME", // [36]
"LEFT", // [37]
"UP", // [38]
"RIGHT", // [39]
"DOWN", // [40]
"SELECT", // [41]
"PRINT", // [42]
"EXECUTE", // [43]
"PRINTSCREEN", // [44]
"INSERT", // [45]
"DELETE", // [46]
"", // [47]
"0", // [48]
"1", // [49]
"2", // [50]
"3", // [51]
"4", // [52]
"5", // [53]
"6", // [54]
"7", // [55]
"8", // [56]
"9", // [57]
"COLON", // [58]
"SEMICOLON", // [59]
"LESS_THAN", // [60]
"EQUALS", // [61]
"GREATER_THAN", // [62]
"QUESTION_MARK", // [63]
"AT", // [64]
"A", // [65]
"B", // [66]
"C", // [67]
"D", // [68]
"E", // [69]
"F", // [70]
"G", // [71]
"H", // [72]
"I", // [73]
"J", // [74]
"K", // [75]
"L", // [76]
"M", // [77]
"N", // [78]
"O", // [79]
"P", // [80]
"Q", // [81]
"R", // [82]
"S", // [83]
"T", // [84]
"U", // [85]
"V", // [86]
"W", // [87]
"X", // [88]
"Y", // [89]
"Z", // [90]
"OS_KEY", // [91] Windows Key (Windows) or Command Key (Mac)
"", // [92]
"CONTEXT_MENU", // [93]
"", // [94]
"SLEEP", // [95]
"NUMPAD0", // [96]
"NUMPAD1", // [97]
"NUMPAD2", // [98]
"NUMPAD3", // [99]
"NUMPAD4", // [100]
"NUMPAD5", // [101]
"NUMPAD6", // [102]
"NUMPAD7", // [103]
"NUMPAD8", // [104]
"NUMPAD9", // [105]
"MULTIPLY", // [106]
"ADD", // [107]
"SEPARATOR", // [108]
"SUBTRACT", // [109]
"DECIMAL", // [110]
"DIVIDE", // [111]
"F1", // [112]
"F2", // [113]
"F3", // [114]
"F4", // [115]
"F5", // [116]
"F6", // [117]
"F7", // [118]
"F8", // [119]
"F9", // [120]
"F10", // [121]
"F11", // [122]
"F12", // [123]
"F13", // [124]
"F14", // [125]
"F15", // [126]
"F16", // [127]
"F17", // [128]
"F18", // [129]
"F19", // [130]
"F20", // [131]
"F21", // [132]
"F22", // [133]
"F23", // [134]
"F24", // [135]
"", // [136]
"", // [137]
"", // [138]
"", // [139]
"", // [140]
"", // [141]
"", // [142]
"", // [143]
"NUM_LOCK", // [144]
"SCROLL_LOCK", // [145]
"WIN_OEM_FJ_JISHO", // [146]
"WIN_OEM_FJ_MASSHOU", // [147]
"WIN_OEM_FJ_TOUROKU", // [148]
"WIN_OEM_FJ_LOYA", // [149]
"WIN_OEM_FJ_ROYA", // [150]
"", // [151]
"", // [152]
"", // [153]
"", // [154]
"", // [155]
"", // [156]
"", // [157]
"", // [158]
"", // [159]
"CIRCUMFLEX", // [160]
"EXCLAMATION", // [161]
"DOUBLE_QUOTE", // [162]
"HASH", // [163]
"DOLLAR", // [164]
"PERCENT", // [165]
"AMPERSAND", // [166]
"UNDERSCORE", // [167]
"OPEN_PAREN", // [168]
"CLOSE_PAREN", // [169]
"ASTERISK", // [170]
"PLUS", // [171]
"PIPE", // [172]
"HYPHEN_MINUS", // [173]
"OPEN_CURLY_BRACKET", // [174]
"CLOSE_CURLY_BRACKET", // [175]
"TILDE", // [176]
"", // [177]
"", // [178]
"", // [179]
"", // [180]
"VOLUME_MUTE", // [181]
"VOLUME_DOWN", // [182]
"VOLUME_UP", // [183]
"", // [184]
"", // [185]
"SEMICOLON", // [186]
"EQUALS", // [187]
"COMMA", // [188]
"MINUS", // [189]
"PERIOD", // [190]
"SLASH", // [191]
"BACK_QUOTE", // [192]
"", // [193]
"", // [194]
"", // [195]
"", // [196]
"", // [197]
"", // [198]
"", // [199]
"", // [200]
"", // [201]
"", // [202]
"", // [203]
"", // [204]
"", // [205]
"", // [206]
"", // [207]
"", // [208]
"", // [209]
"", // [210]
"", // [211]
"", // [212]
"", // [213]
"", // [214]
"", // [215]
"", // [216]
"", // [217]
"", // [218]
"OPEN_BRACKET", // [219]
"BACK_SLASH", // [220]
"CLOSE_BRACKET", // [221]
"QUOTE", // [222]
"", // [223]
"META", // [224]
"ALTGR", // [225]
"", // [226]
"WIN_ICO_HELP", // [227]
"WIN_ICO_00", // [228]
"", // [229]
"WIN_ICO_CLEAR", // [230]
"", // [231]
"", // [232]
"WIN_OEM_RESET", // [233]
"WIN_OEM_JUMP", // [234]
"WIN_OEM_PA1", // [235]
"WIN_OEM_PA2", // [236]
"WIN_OEM_PA3", // [237]
"WIN_OEM_WSCTRL", // [238]
"WIN_OEM_CUSEL", // [239]
"WIN_OEM_ATTN", // [240]
"WIN_OEM_FINISH", // [241]
"WIN_OEM_COPY", // [242]
"WIN_OEM_AUTO", // [243]
"WIN_OEM_ENLW", // [244]
"WIN_OEM_BACKTAB", // [245]
"ATTN", // [246]
"CRSEL", // [247]
"EXSEL", // [248]
"EREOF", // [249]
"PLAY", // [250]
"ZOOM", // [251]
"", // [252]
"PA1", // [253]
"WIN_OEM_CLEAR", // [254]
"" // [255]
];
#key-codes,
#key-names {
font-family: courier, serif;
font-size: 1.2em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input id="in" placeholder="Type here..." />
<button id="reset">Reset</button>
<br/>
<br/>
<div id="key-codes">var keyCodes = [ ];</div>
<div id="key-names">var keyNames = [ ];</div>
Key codes worth noting
Letters A-Z: (65-90)
keyboardMap[65]; // A
...
keyboardMap[90]; // Z
Digits 0-9: (48-57)
keyboardMap[48]; // 0
...
keyboardMap[57]; // 9
Number Pad 0-9: (96-105)
keyboardMap[96]; // NUMPAD0
...
keyboardMap[105]; // NUMPAD9
Arrow Keys: (37-40)
keyboardMap[37]; // LEFT
keyboardMap[38]; // UP
keyboardMap[39]; // RIGHT
keyboardMap[40]; // DOWN
Tab Key: (9)
keyboardMap[9]; // TAB
Enter Key: (13)
keyboardMap[13]; // ENTER
Spacebar Key: (32)
keyboardMap[32]; // SPACE
OS Specific Key (91) Windows Key (Windows) or Command Key (Mac)
keyboardMap[91]; // OS_KEY
Alt Key: (18)
keyboardMap[18]; // ALT
Control Key: (17)
keyboardMap[17]; // CONTROL
Shift Key: (16)
keyboardMap[16]; // SHIFT
Caps Lock Key: (20)
keyboardMap[20]; // CAPS_LOCK
Just an important note: the accepted answer above will not work correctly for keyCode >= 144, i.e. period, comma, dash, etc. For those you should use a more general algorithm:
let chrCode = keyCode - 48 * Math.floor(keyCode / 48);
let chr = String.fromCharCode((96 <= keyCode) ? chrCode: keyCode);
If you're curious as to why, this is apparently necessary because of the behavior of the built-in JS function String.fromCharCode()
. For values of keyCode <= 96
it seems to map using the function:
chrCode = keyCode - 48 * Math.floor(keyCode / 48)
For values of keyCode > 96
it seems to map using the function:
chrCode = keyCode
If this seems like odd behavior then well..I agree. Sadly enough, it would be very far from the weirdest thing I've seen in the JS core.
document.onkeydown = function(e) {
let keyCode = e.keyCode;
let chrCode = keyCode - 48 * Math.floor(keyCode / 48);
let chr = String.fromCharCode((96 <= keyCode) ? chrCode: keyCode);
console.log(chr);
};
<input type="text" placeholder="Focus and Type"/>
I'm assuming this is for a game or for a fast-responding type of application hence the use of KEYDOWN than KEYPRESS.
Edit: Dang! I stand corrected (thank you Crescent Fresh and David): JQuery (or even rather the underlying DOM hosts) do not expose the detail of the WM_KEYDOWN and of other events. Rather they pre-digest this data and, in the case of keyDown even in JQuery, we get:
- event.keyCode for non-character keys
- event.charCode for character keys
Note that these properties are the UniCode values.
Note, I wasn't able to find an authorititative reference to that in JQuery docs, but many reputable examples on the net refer to these two properties.
The following code, adapted from some java (not javascript) of mine, is therefore totally wrong...
The following will give you the "interesting" parts of the keycode:
value = e.KeyCode;
repeatCount = value & 0xFF;
scanCode = (value >> 16) & 0xFF; // note we take the "extended bit" deal w/ it later.
wasDown = ((value & 0x4000) != 0); // indicate key was readily down (auto-repeat)
if (scanCode > 127)
// deal with extended
else
// "regular" character