Capture key press without placing an input element on the page? - javascript

How to capture key press, e.g., Ctrl+Z, without placing an input element on the page in JavaScript? Seems that in IE, keypress and keyup events can only be bound to input elements (input boxes, textareas, etc)

For non-printable keys such as arrow keys and shortcut keys such as Ctrl-z, Ctrl-x, Ctrl-c that may trigger some action in the browser (for instance, inside editable documents or elements), you may not get a keypress event in all browsers. For this reason you have to use keydown instead, if you're interested in suppressing the browser's default action. If not, keyup will do just as well.
Attaching a keydown event to document works in all the major browsers:
document.onkeydown = function(evt) {
evt = evt || window.event;
if (evt.ctrlKey && evt.keyCode == 90) {
alert("Ctrl-Z");
}
};
For a complete reference, I strongly recommend Jan Wolter's article on JavaScript key handling.

jQuery also has an excellent implementation that's incredibly easy to use. Here's how you could implement this functionality across browsers:
$(document).keypress(function(e){
var checkWebkitandIE=(e.which==26 ? 1 : 0);
var checkMoz=(e.which==122 && e.ctrlKey ? 1 : 0);
if (checkWebkitandIE || checkMoz) $("body").append("<p>ctrl+z detected!</p>");
});
Tested in IE7,Firefox 3.6.3 & Chrome 4.1.249.1064
Another way of doing this is to use the keydown event and track the event.keyCode. However, since jQuery normalizes keyCode and charCode using event.which, their spec recommends using event.which in a variety of situations:
$(document).keydown(function(e){
if (e.keyCode==90 && e.ctrlKey)
$("body").append("<p>ctrl+z detected!</p>");
});

For modern JS, use event.key!
document.addEventListener("keypress", function onPress(event) {
if (event.key === "z" && event.ctrlKey) {
// Do something awesome
}
});
NOTE: The old properties (.keyCode and .which) are Deprecated.
Mozilla Docs
Supported Browsers

Detect key press, including key combinations:
window.addEventListener('keydown', function (e) {
if (e.ctrlKey && e.keyCode == 90) {
// Ctrl + z pressed
}
});
Benefit here is that you are not overwriting any global properties, but instead merely introducing a side effect. Not good, but definitely a whole lot less nefarious than other suggestions on here.

Code & detects ctrl+z
document.onkeyup = function(e) {
if(e.ctrlKey && e.keyCode == 90) {
// ctrl+z pressed
}
}

Attach a listener to the keydown event instead of keypress, since the latter is now deprecated.
window.addEventListener('keydown', keyDownHandler);
The keydown event triggers continuously while the key is pressed. If you wanna have it fire only once, inside the handler use the event.repeat property as so:
keyDownHandler(event) {
if (!event.repeat) {
<code here will only be executed once while the key is pressed>
}
}
Remember to remove the listener when not needed anymore.
window.removeEventListener('keydown', keyDownHandler);

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?

Using keyCode to pair keydown and keyup events

I want to keep track of which keys are pressed at a given time, like so:
var keys = {};
$(document.body).on('keydown', function(e) {
keys[e.keyCode] = true;
});
$(document.body).on('keyup', function(e) {
delete keys[e.keyCode];
});
However, from MDN it looks like keyCode is deprecated, and suggests key. From testing on Chrome, it looks like key is undefined. The documentation also describes which but I am unsure as to what the differences are.
Is keyCode the right thing to use here? I don't care which keys are down, only that I know that some keys are pressed. I also can't use the input event.
I would suggest to use a fallback mechanism which handles the advise from MDN first and than falls back to the older solutions.
But if you are using jQuery you should use the provided methods to get the key-code
// jquery
$(document.body).on('keyup', function(e) {
delete keys[e.which];
});
// vanilla
document.body.addEventListener('keyup', function (e) {
delete keys[(e.key && e.keyCode.charCodeAt(0)) || e.which || e.keyCode];
}, true);
However this will only be true for printable characters and needs a deeper investigation of the problem usually.

jQuery not detecting modifiers on keyup

When I run the following code and press the command key on my Mac (using Chrome), metaKey is set for keydown but not for keyup. Am I doing something wrong? I'm just trying to track the meta key being pressed so I can use it inside my JavaScript - if there's a better way please let me know :-)
var metaPressed = false;
$(document).keydown(function(e) {
console.log('keydown ' + e.keyCode);
if (e.metaKey || e.ctrlKey) {
console.log('meta pressed');
metaPressed = true;
}
});
$(document).keyup(function(e) {
console.log('keyup ' + e.keyCode);
if (e.metaKey || e.ctrlKey) {
console.log('meta unpressed');
metaPressed = false;
}
});
Here's the console output for the relevant keys
// Pressing cmd
keydown 91
meta pressed
keyup 91
// Pressing control
keydown 17
meta pressed
keyup 17
// Pressing non-meta like spacebar
keydown 32
keyup 32
I get it now, I was misunderstanding how jQuery handles modifier keys. Thanks to #adeneo for the prompt that got me thinking correctly.
Also, if you press keys while holding a meta character, e.g. press M-x, jQuery doesn't send the keyup for 'x' until it the 'M' is also released. So you don't have to worry about things like "meta down, x down, x up, meta up" happening
You won't be able to retrieve that information from the keyup. I would recommend to use this (e.keyCode === 17 || e.keyCode === 91) as test case (which are CTRL and META respectively)
I'm using React and noticing the same issue. e.metaKey works on keydown but not keyup. e.keyCode is 93 for both, however.

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