consistent keyCode for `#` - javascript

While I know that capturing keys due to the e.keyCode vs e.charCode is not trivial, I thought that jQuery would pretty much be able to normalize most of those inconsistencies.
However while answering this question I found out that the character # seems to have very inconsistent keyCodes (and of course this is true for several other codes also, mostly depending on the browser and keyboardlayout I guess).
Chrome and IE yielded 191, Firefox 163 on my computer, another user reported 222. Chromes window.event even reported U+00BF as keyIdentifier - which according to unicode tables should be ¿.
Do you know any consistent way to determine such symbols like the # with inconsistent keyCodes without doing something nasty like the following:
$('input').keydown(function (e) {
if (e.which == 191 || e.which == 163 || e.which == 222){
// hope you got the right key
e.preventDefault();
}
});
Fiddle for your pleasure.

This works for me in Chrome and Firefox with a US keyboard:
$('[id$=txtClient]').keypress(function (e) {
if (String.fromCharCode(e.which) == '#') {
e.preventDefault();
}
});
keypress is the only event that will give you reliable info on the character that was entered.
Demo: http://jsfiddle.net/elclanrs/ebcet/9/

Have you tried using the keypress event ?
The documentation warns about possible differences in behavior between platforms.
In Firefox at least, e.which corresponds to the ascii code of the typed character after transformation :
$('#txtClient').keypress(function (e) {
console.log('keypress:', e.which);
if (e.which == 35) {
return false;
}
});
updated fiddle

Related

Confused by javascript Keyboard events

I'm confused at how I'm supposed to handle keyboard events in Javascript. I'm trying to detect meta-z and meta-shift-z to implement undo/redo. What is currently working is to use
let key = String.fromCharCode(e.which || e.keyCode);
if (e.ctrlKey || e.metaKey) {
// Handle ctrl/cmd keypress
if ((key === 'Z' && e.shiftKey) || key === 'Y') {
// Ctrl/Cmd-shift Z or Cmd-Y => Redo
redoGraph();
e.stopPropagation();
}
else if (key === 'Z') { // lower-case z, no shift
// Ctrl/Cmd-Z => Undo
undoGraph();
e.stopPropagation();
}
}
However, both "which" and "keyCode" are deprecated. Though, as usual, the notice I found for the deprecation didn't say what to use instead. If I use "e.key", then according to W3Schools, Safari doesn't support that, so then it seems like I'd need to do both or something. Is there a best practice for detecting keyboard events?
Also, "e.key" always returns lower-case. So then if you wanted to detect typing, do you have to do your own manual conversion from lower to upper (including all diacritics, etc.)? Or is there a way to get a key event that says what the typed character should look like?

Numbers-only JavaScript Firefox solution

I need some help cleaning up a popular piece of vanilla JavaScript code that causes issues in Firefox.
The following which/keyCode check seems to be about the most popular vanilla JS solution to allow only numbers into an input or textarea.
var charCode = (e.which) ? e.which : e.keyCode;
if (charCode > 31 && ( charCode < 48 || charCode > 57)) {
return false;
}
return true;
Called via onkeypress="return function(event);" on the tag.
However, Firefox apparently binds arrow keys to onkeypress calls, rather than just to onkeyup and onkeydown like other browsers. This means that e.g. the left arrow key's charCode is 37, but so is the charCode for % (shift+5). Even more importantly, it means that the arrow keys can't be used for navigation (moving the caret/text cursor left or right).
However, the difference is that the left arrow key has keyCode 37, while % has the charCode and which of 37 (as shown on http://www.asquare.net/javascript/tests/KeyCode.html). So I was able to make the arrow keys work just fine by doing the following:
if (charcode > 31 && (charcode < 48 || charcode > 57)) {
if (e.keycode && e.keyCode > 36 && e.keyCode < 41) {
return true;
}
return false;
}
return true;
However, I feel like this is not the best or cleanest way to do it, and that there might be more keys handled differently by Firefox than just the arrow keys. What would be a cleaner vanilla JS solution or way to check for at least the arrow keys within this function?
Many thanks!
EDIT: I just figured that even though the code solves it for Firefox, it introduces a new problem for all other browsers, in that these now allow charCodes 37-40 (i.e. %) to be entered. Seems that instead of checking the keyCode, it would need to check the charCode or which, in otherwise the same manner.
I would advise against blocking certain keys, as I feel it degrades the user experience. But given that this is what you need, I would suggest to not rely on the keyCode property. Not only are there compatibility problems related to it, it also does not cover all ways input can be made, like with the mouse and context menu, and is deprecated:
This feature has been removed from the Web standards.
The KeyboardEvent.keyCode read-only property represents a system and implementation dependent numerical code
Instead I propose to use the input event, which triggers on every change to the input value, and then to clean the value of non-digits, while putting the cursor at the place where the first offending character was found. This gives about the same user-experience, and has no bad effect on how arrow keys, backspace, delete, selection, ... etc work:
document.querySelector('#num').addEventListener('input', function() {
var badCharPos = this.value.search(/\D/);
if (badCharPos == -1) return; // all OK
// remove offending characters:
this.value = this.value.replace(/\D/g, '');
this.setSelectionRange(badCharPos, badCharPos);
});
<input id="num">

JavaScript KeyCode Values are "undefined" in Internet Explorer 8

I'm having trouble with some JavaScript that I've written, but only with Internet Explorer 8. I have no problem executing this on Internet Explorer 7 or earlier or on Mozilla Firefox 3.5 or earlier. It also executes properly when I use compatibility mode on Internet Explorer 8.
What I'm doing is overriding the Enter keystroke when a user enters a value into a textbox. So on my element I have this:
<asp:TextBox ID="ddPassword" runat="server" TextMode="Password" onkeypress="doSubmit(event)" Width="325"></asp:TextBox>
And then I have the following JavaScript method:
function doSubmit(e)
{
var keyCode = (window.Event) ? e.which : e.keyCode;
if (keyCode == 13)
document.getElementById("ctl00_ContentPlaceHolder1_Login").click();
}
Again, this all works fine with almost every other browser. Internet Explorer 8 is just giving me a hard time.
Any help you might have is greatly appreciated.
UPDATE: Thanks everyone for your quick feedback. Both Chris Pebble and Bryan Kyle assisted with this solution. I have awarded Bryan the "answer" to help with his reputation. Thanks everyone!
It looks like under IE8 the keyCode property of window.Event is undefined but that same property of window.event (note the lowercase e) has the value. You might try using window.event.
function doSubmit(e)
{
var keyCode = (window.event) ? e.which : e.keyCode;
if (keyCode == 13)
document.getElementById("ctl00_ContentPlaceHolder1_Login").click();
}
Just a hunch, try this:
var keyCode = e.keyCode ? e.keyCode : e.which;
It's worked on this way on my code:
var kcode = (window.event) ? event.keyCode : event.which;
try this:
function checkKeyCode(e){
if (!e) e = window.event; var kCd = e.which || e.keyCode;
return kCd;
}
I personally prefer the multi-key approach. This allows multiple keys to be detected, but also a single key just the same, and it works in every browser I've tested.
map={}//declare object to hold data
onkeydown=onkeyup=function(e){
e=e||event//if e doesn't exist (like in IE), replace it with window.event
map[e.keyCode]=e.type=='keydown'?true:false
//Check for keycodes
}
An alternative method would be to separate the onkeydown and onkeyup events and explicitly define the map subitems in each event:
map={}
onkeydown=function(e){
e=e||event
map[e.keyCode]=true
}
onkeyup=function(e){
e=e||event
map[e.keyCode]=false
}
Either way works fine. Now, to actually detect keystrokes, the method, including bug fixes, is:
//[in onkeydown or onkeyup function, after map[e.keyCode] has been decided...]
if(map[keycode]){
//do something
map={}
return false
}
map[keycode] constitutes a specific keycode, like 13 for Enter, or 17 for CTRL.
The map={} line clears the map object to keep it from "holding" onto keys in cases of unfocusing, while return false prevents, for example, the Bookmarks dialog from popping up when you check for CTRL+D. In some cases, you might want to replace it with e.preventDefault(), but I've found return false to be more efficient in most cases. Just to get a clear perspective, try it with CTRL+D. Ctrl is 17, and D is 68. Notice that without the return false line, the Bookmarks dialog will pop up.
Some examples follow:
if(map[17]&&map[13]){//CTRL+ENTER
alert('CTRL+ENTER was pressed')
map={}
return false
}else if(map[13]){//ENTER
alert('Enter was pressed')
map={}
return false
}
One thing to keep in mind is that smaller combinations should come last. Always put larger combinations first in the if..else chain, so you don't get an alert for both Enter and CTRL+ENTER at the same time.
Now, a full example to "put it all together". Say you want to alert a message that contains instructions for logging in when the user presses SHIFT+? and log in when the user presses ENTER. This example is also cross-browser compatible, meaning it works in IE, too:
map={}
keydown=function(e){
e=e||event
map[e.keyCode]=true
if(map[16]&&map[191]){//SHIFT+?
alert('1) Type your username and password\n\n2) Hit Enter to log in')
map={}
return false
}else if(map[13]){//Enter
alert('Logging in...')
map={}
return false
}
}
keyup=function(e){
e=e||event
map[e.keyCode]=false
}
onkeydown=keydown
onkeyup=keyup//For Regular browsers
try{//for IE
document.attachEvent('onkeydown',keydown)
document.attachEvent('onkeyup',keyup)
}catch(e){
//do nothing
}
Note that some special keys have different codes for different engines. But as I've tested, this works in every browser I currently have on my computer, including Maxthon 3, Google Chrome, Internet Explorer (9 and 8), and Firefox.
I hope this was helpful.
Try adding onkeyup event as well and call the same function.
TIP:
You can add debugger; at beginning of doSubmit to set a break, then you can examine keyCode.
I think window.Event.keyCode works in IE8 (I can't test right now though)
Or something like that.
var keyCode = e.which || e.keyCode;

Which keycode for escape key with jQuery

I have two functions. When enter is pressed the functions runs correctly but when escape is pressed it doesn't. What's the correct number for the escape key?
$(document).keypress(function(e) {
if (e.which == 13) $('.save').click(); // enter (works as expected)
if (e.which == 27) $('.cancel').click(); // esc (does not work)
});
Try with the keyup event:
$(document).on('keyup', function(e) {
if (e.key == "Enter") $('.save').click();
if (e.key == "Escape") $('.cancel').click();
});
Rather than hardcode the keycode values in your function, consider using named constants to better convey your meaning:
var KEYCODE_ENTER = 13;
var KEYCODE_ESC = 27;
$(document).keyup(function(e) {
if (e.keyCode == KEYCODE_ENTER) $('.save').click();
if (e.keyCode == KEYCODE_ESC) $('.cancel').click();
});
Some browsers (like FireFox, unsure of others) define a global KeyEvent object that exposes these types of constants for you. This SO question shows a nice way of defining that object in other browsers as well.
(Answer extracted from my previous comment)
You need to use keyup rather than keypress. e.g.:
$(document).keyup(function(e) {
if (e.which == 13) $('.save').click(); // enter
if (e.which == 27) $('.cancel').click(); // esc
});
keypress doesn't seem to be handled consistently between browsers (try out the demo at http://api.jquery.com/keypress in IE vs Chrome vs Firefox. Sometimes keypress doesn't register, and the values for both 'which' and 'keyCode' vary) whereas keyup is consistent.
Since there was some discussion of e.which vs e.keyCode: Note that e.which is the jquery-normalized value and is the one recommended for use:
The event.which property normalizes event.keyCode and event.charCode. It is recommended to watch event.which for keyboard key input.
(from http://api.jquery.com/event.which/)
To find the keycode for any key, use this simple function:
document.onkeydown = function(evt) {
console.log(evt.keyCode);
}
27 is the code for the escape key. :)
Your best bet is
$(document).keyup(function(e) {
if (e.which === 13) $('.save').click(); // enter
if (e.which === 27) $('.cancel').click(); // esc
/* OPTIONAL: Only if you want other elements to ignore event */
e.preventDefault();
e.stopPropagation();
});
Summary
which is more preferable than keyCode because it is normalized
keyup is more preferable than keydown because keydown may occur multiple times if user keeps it pressed.
Do not use keypress unless you want to capture actual characters.
Interestingly Bootstrap uses keydown and keyCode in its dropdown component (as of 3.0.2)! I think it's probably poor choice there.
Related snippet from JQuery doc
While browsers use differing
properties to store this information, jQuery normalizes the .which
property so you can reliably use it to retrieve the key code. This
code corresponds to a key on the keyboard, including codes for special
keys such as arrows. For catching actual text entry, .keypress() may
be a better choice.
Other item of interest: JavaScript Keypress Library
Try the jEscape plugin (download from google drive)
$(document).escape(function() {
alert('ESC button pressed');
});
or get keycode for cross browser
var code = (e.keyCode ? e.keyCode : e.which);
if (code === 27) alert('ESC');
if (code === 13) alert('ENTER');
maybe you can use switch
var code = (e.keyCode ? e.keyCode : e.which);
switch (code) {
case 27:
alert('ESC');
break;
case 13:
alert('ENTER');
break;
}
Just posting an updated answer than e.keyCode is considered DEPRECATED on MDN.
Rather you should opt for e.key instead which supports clean names for everything. Here is the relevant copy pasta
window.addEventListener("keydown", function (event) {
if (event.defaultPrevented) {
return; // Do nothing if the event was already processed
}
switch (event.key) {
case "ArrowDown":
// Do something for "down arrow" key press.
break;
case "ArrowUp":
// Do something for "up arrow" key press.
break;
case "ArrowLeft":
// Do something for "left arrow" key press.
break;
case "ArrowRight":
// Do something for "right arrow" key press.
break;
case "Enter":
// Do something for "enter" or "return" key press.
break;
case "Escape":
// Do something for "esc" key press.
break;
default:
return; // Quit when this doesn't handle the key event.
}
// Cancel the default action to avoid it being handled twice
event.preventDefault();
}, true);
Your code works just fine. It's most likely the window thats not focused. I use a similar function to close iframe boxes etc.
$(document).ready(function(){
// Set focus
setTimeout('window.focus()',1000);
});
$(document).keypress(function(e) {
// Enable esc
if (e.keyCode == 27) {
parent.document.getElementById('iframediv').style.display='none';
parent.document.getElementById('iframe').src='/views/view.empty.black.html';
}
});
I'm was trying to do the same thing and it was bugging the crap out of me. In firefox, it appears that if you try to do some things when the escape key is pressed, it continues processing the escape key which then cancels whatever you were trying to do. Alert works fine. But in my case, I wanted to go back in the history which did not work. Finally figured out that I had to force the propagation of the event to stop as shown below...
if (keyCode == 27)
{
history.back();
if (window.event)
{
// IE works fine anyways so this isn't really needed
e.cancelBubble = true;
e.returnValue = false;
}
else if (e.stopPropagation)
{
// In firefox, this is what keeps the escape key from canceling the history.back()
e.stopPropagation();
e.preventDefault();
}
return (false);
}
To explain where other answers haven't; the problem is your use of keypress.
Perhaps the event is just mis-named but keypress is defined to fire when when an actualcharacteris being inserted. I.e. text.
Whereas what you want is keydown/keyup, which fires whenever (before or after, respectively) the user depresses akey. I.e. those things on the keyboard.
The difference appears here because esc is a control character (literally 'non-printing character') and so doesn't write any text, thus not even firing keypress.
enter is weird, because even though you are using it as a control character (i.e. to control the UI), it is still inserting a new-line character, which will fire keypress.
Source: quirksmode
To get the hex code for all the characters: http://asciitable.com/
A robust Javascript library for capturing keyboard input and key combinations entered. It has no dependencies.
http://jaywcjlove.github.io/hotkeys/
hotkeys('enter,esc', function(event,handler){
switch(handler.key){
case "enter":$('.save').click();break;
case "esc":$('.cancel').click();break;
}
});
hotkeys understands the following modifiers: ⇧,shiftoption⌥altctrlcontrolcommand, and ⌘.
The following special keys can be used for shortcuts:backspacetab,clear,enter,return,esc,escape,space,up,down,left,right,home,end,pageup,pagedown,del,delete andf1 throughf19.
I have always used keyup and e.which to catch escape key.
I know this question is asking about jquery, but for those people using jqueryui, there are constants for many of the keycodes:
$.ui.keyCode.ESCAPE
http://api.jqueryui.com/jQuery.ui.keyCode/
$(document).on('keydown', function(event) {
if (event.key == "Escape") {
alert('Esc key pressed.');
}
});

event is not defined in mozilla firefox for javascript function?

function onlyNumeric() {
if (event.keyCode < 48 || event.keyCode > 57) {
event.returnValue = false;
}
}
onkeypress=onlyNumneric();
In IE, this code is working fine. However, in Mozilla Firefox, the event is an undefined error.
In FF/Mozilla the event is passed to your event handler as a parameter. Use something like the following to get around the missing event argument in IE.
function onlyNumeric(e)
{
if (!e) {
e = window.event;
}
...
}
You'll find that there are some other differences between the two as well. This link has some information on how to detect which key is pressed in a cross-browser way.
Or quite simply, name the parameter event and it will work in all browsers. Here is a jQueryish example:
$('#' + _aYearBindFlds[i]).on('keyup', function(event) {
if(! ignoreKey({szKeyCodeList: gvk_kcToIgnore, nKeyCode: event.keyCode })) this.value = this.value.replace(/\D/g, '');
});
This example allows digits only to be entered for year fields (inside a for each loop selector) where ingoreKey() takes a keyCode list/array and compares the event keyCode and determines if it should be ignored before firing the bind event.
Keys I typically ingore for masks/other are arrow, backspace, tabs, depending on context/desired behaviour.
You can also typically use event.which instead of event.keyCode in most browsers, at least when you are using jQuery which depends on event.which to normalize the key and mouse events.
I don't know for sure what happens under the covers in the js engines, but it seems Mozilla FF respects a stricter scope, wherein, other browsers may be automatically addressing the window.event.keyCode scope on their own when the event is not explicitly passed in to a function or closure.
In FF, you can also address the event by window.event (as shown in some examples here) which would support this thought.
Some browsers may not support keyCode you have to use keyChar
function onlyNumeric() {
var chars = event.keyCode | event.keyChar;
if (chars < 48 || chars > 57) {
event.returnValue = false;
}
}
onkeypress=onlyNumneric();

Categories

Resources