CHROME (52):
When turning caps lock ON - only keydown is fired (no event in keyUp or keyPress)
When turning caps lock OFF - only keyup is fired (no event in keyDown or keyPress)
FIREFOX (46):
Only keyDown event is fired for both caps lock ON & OFF (no keyUp or keyPress)
I've read about the keyCodes and events here http://www.quirksmode.org/js/keys.html and in MDN here https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode, aaaand here http://unixpapa.com/js/key.html
But none of the above links talks about this weird behaviour.
Is this expected? If so, any easier way to handle it?
Yes, this is expected.
Chrome treats the CAPS ON as keydown because it treats the on/off as press and hold, like we hold shift key, which turns on caps on behaviour and turns off when we release it. This Caps Lock button also. When you turn on Caps Lock, chrome handles the 'turn on' as a keypress and when you 'turn off' it handles it as a keyup. But, firefox handles everything as keydown which doesn't make sense to me when compared to how chrome handles the same.
Solution
You should use getModifierState() to get the state of the Caps Lock. This is supported in chrome and firefox.
Hope it helps!
$(function() {
$(window).on("keydown", function(e){
if (e.which === 20)
console.log(e.originalEvent.getModifierState('CapsLock'))
});
$(window).on("keyup", function(e) {
if (e.which === 20)
console.log(e.originalEvent.getModifierState('CapsLock'))
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Focus here and press 'Caps Lock'
I had been looking for an answer to a very similar issue. Pranesh's answer pointed me in a direction.
In my case, I wanted to warn users that their capslock is on when they go to log in. Ultimately I settled on the following solution.
Angular Component:
export class AuthenticateComponent {
public capslockOn: boolean;
constructor() {
this.capslockOn = false;
}
public keyup(event: KeyboardEvent): void {
if (event.key === 'CapsLock') {
// Checks / sets when the Caps Lock key is specifically pressed.
this.capslockOn = (!this.capslockOn && event.getModifierState('CapsLock'));
} else {
// Checks all other conditions like the Caps Lock was on before the user
// loaded the form and began typing in it.
this.capslockOn = event.getModifierState('CapsLock');
}
}
}
Then I just call the keyup function from my form:
<form ... (keyup)="keyup($event)">
Any keypress in the form - username or password - will check / set the boolean capslockOn and I can *ngIf that to show an icon or message or both.
Thanks for the explanation Pranesh. It helped quite a bit.
Related
I have tried the W3 Schools example code for handling the enter key for input text. I copied the source code from that site's page and pasted below.
The problem is that on FireFox, if I press the enter key to finish Japanese input mode, the code is also triggered. On Edge, it did not. Is this a FireFox bug, or just a different behaviour? Anyway, how can I circumvent this?
var input = document.getElementById("myInput");
// Execute a function when the user presses a key on the keyboard
input.addEventListener("keypress", function(event) {
// If the user presses the "Enter" key on the keyboard
if (event.key === "Enter") {
// Cancel the default action, if needed
event.preventDefault();
// Trigger the button element with a click
document.getElementById("myBtn").click();
}
});
You should rather use KeyDown event. KeyPress is reporting every keycode from keyboard. Some keys on keyboard are not only putting one keycode but multiple keycodes. KeyDown event should pack all keycode from one actual pressed key into one event.
KeyPress is meant to do more low level approach
I have some simple code which logs the pressed key code, like this:
window.addEventListener('keypress', function(e) {
console.log(e.keyCode);
})
It seems to work for Alt + pretty much every other on my keyboard. Except for Alt + N.
It seems to not be registering the event at all! Just N (without the Alt) seems to work, and so do other combinations like Ctrl + N. When I type Alt + N nothing else happens, so it's not been reserved by the system as far as I know. I am using Chrome on a Mac.
Is this just something wrong with my computer or does it happen for others too? If it does happen for others, why does it do this and are there ways to detect it?
Try :
window.addEventListener('keydown', function(e) {
if (e.altKey == true && e.keyCode == 78)
console.log('Alt + N');
});
Using keypress event doesn't work for me for Alt+N and for any combination with Alt for that matter. Some combinations are working with Ctrl and some aren't.
However, when I listen for keydown and keyup events, I am able to log these events. So, I guess you could listen for keydown event on Alt and if there is a keydown event for N before Alt generates keyup, you have successfully detected a Alt+N combo.
I am not sure about why this happens though.
EDIT
According to Mozilla documentation,
The keypress event is fired when a key that produces a character value is pressed down. Examples of keys that produce a character value are alphabetic, numeric, and punctuation keys.
Examples of keys that don't produce a character value are modifier keys such as Alt, Shift, Ctrl, or Meta.
As for why some shortcuts work in Chrome, while some do not, Mozilla says
Chrome does not fire the keypress event for known keyboard shortcuts. Which keyboard shortcuts are known depends on the user's system. Use the keydown event to implement keyboard shortcuts.
Some clients have been reporting issues when using their iPad Bluetooth keyboards for entering text into one of our internal sites. Mainly pressing enter on a certain input would work fine when using desktop or the iPad on screen keyboard, but not when using a Bluetooth keyboard connected to the iPad.
Upon investigation it appears that any input to an onKeyUp returns 0 as the keycode when connected to a Bluetooth keyboard on the iPad. The demo works fine, however when using the onscreen keyboard it doesn't work because of the keycode returning 0. I created this jsFiddle to demonstrate. It was tested on both Chrome and Safari for iPad with the same results of working fine with onKeyPress but returning only 0 with onKeyUp.
$('#inputKeyUp').keyup(function (event){
$("#outputKeyUp").text("Key Up Key: " + event.which);
});
$('#inputKeyPress').keypress(function (event){
$("#outputKeyPress").text("Key Press Key: " + event.which);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="inputKeyUp">keyup</textarea>
<div id="outputKeyUp">Key Up Key:</div>
<b/>
<textarea id="inputKeyPress">keypress</textarea>
<div id="outputKeyPress">Key Press Key:</div>
EDIT: just reported the bug to Apple. We will see if anything comes of it.
Testing study
I did some testing on this just now and discovered that on the keyUp event when using a Bluetooth keyboard on iOS Safari, the only keys that give any sort of proper feedback in terms of the properties e.key, e.charCode, e.keyCode and e.which are the following keys:
Escape
Up arrow
Left arrow
Right arrow
Down arrow
All other keys return the following:
{
key: "Dead",
charCode: 0,
keyCode: 0,
which: 0
}
These special keys (escape and arrow keys) only return a different value on the e.key property according to the syntax UIKeyInput{PascalCasedKeyName}:
UIKeyInputEscape
UIKeyInputUpArrow
UIKeyInputLeftArrow
UIKeyInputRightArrow
UIKeyInputDownArrow
Summary
On iOS, the only keys you can identify on the keyUp event, based on my quick study, are Escape and the four Arrow keys, by matching their name on the e.key property. These values also appear on the keyDown event.
If you still need to wait until the keyUp event fires for your applications, and you need to match keys other than these special ones, the only solution I can come up with is to use a keyDown event for capturing the key, but then listen for the keyUp event inside that keyDown event like so:
el.addEventListener("keydown", e => {
if (e.which === 13) // Enter key, or which ever key code you'd like
el.addEventListener("keyup", function keyUp(e) {
el.removeEventListener("keyup", keyUp, false) // Memory clean-up
// Your code here
}, false)
}, false)
Furthermore
After a quick search for "UIKeyInput" I discovered that UIKeyInput is "a set of methods a subclass of UIResponder uses to implement simple text entry". (Apple's Developer Documentation) This would explain the special syntax of these key names.
This is a workaround for the enter key in the keyup event.
if (event.type === 'keyup') {
//this is to handle the enter button on an ipad bluetooth keyboard
if (event.key === 'Enter') {
event.which = event.keyCode = 13;
}
}
I was fiddling with preventDefault() and must be doing something wrong.
$("#input").bind("keypress", function(event) {
if(event.which == 9) {
event.preventDefault();
alert("You pressed tab.");
}
});
The tab functionality isn't prevented. What's wrong with this?
Try this FIDDLE. The input loses focus when you tab. Binding to the body fixes this.
$("body").on("keydown", function(event) {
if(event.which == 9) {
event.preventDefault();
alert("You pressed tab.");
}
});
The keypress event is simply not fired when the Tab is pressed - this also explains why there is no alert, independent of what preventing the default may do.
Changing the code to use keydown allows the Tab to be caught and prevents the default focus-change (in Chrome1, anyway).
$("#input").bind("keydown", function(event) {
if(event.which == 9) {
event.preventDefault();
}
});
1 I tested the above in Chrome 35 with jQuery 1.6-2.1; it does not work under the KO 3.0 library.
From the documentation on JQuery,
Note: as the keypress event isn't covered by any official specification, the actual behavior encountered when using it may differ across browsers, browser versions, and platforms.
This method is a shortcut for .on( "keypress", handler ) in the first two variations, and .trigger( "keypress" ) in the third.
The keypress event is sent to an element when the browser registers keyboard input. This is similar to the keydown event, except that modifier and non-printing keys such as Shift, Esc, and delete trigger keydown events but not keypress events. Other differences between the two events may arise depending on platform and browser.
So in this case you are using the wrong event. Also it might have browser compatibility issues.
I'm using this to disable the 'scrolling' effect the spacebar has in a browser. Will this affect other keypress events too?
window.onkeydown = function(e) {
return !(e.keyCode == 32);
};
Could someone please explain what this is doing? I'm not sure if this code is bad, but it seems to disable other keypress related codes in my page, and I want to make sure this isn't the reason.
Thanks!
ASCII code 32 is the ASCII value that represents the spacebar key, and your code is essentially telling the browser to return false whenever that keycode is detected. Since false is returned, the scrollbar effect you speak of is in fact successfully disabled.
However, the unfortunate side effect of this convenient spacebar-scroll-disabling function is that it disables spacebar keypresses everywhere on the page.
Instead of returning false, if the keycode is detected, pass the current scrollTop value into a closure that returns a function to a setTimeout event. When the setTimeout fires, the scrollTop position is reset back to the value it was in when the setTimeout event was first registered.
window.onkeydown = function(e) {
if(event.keyCode == 32) { // alert($(document).scrollTop() );
setTimeout(
(function(scrollval) {
return function() {
$(document).scrollTop(scrollval);
};
})( $(document).scrollTop() ), 0);
}
};
Your users can still conveniently make use of spacebars in input textboxes and textareas, and at the same time, pressing the spacebar key while not focused on a text element will no longer result in the page scrolling.
Under the hood, the scroll is still taking place. It's just being reset at a rate fast enough to where the user doesn't notice.
If you increase this value to 100 or 1000, it will give you a better idea of what is going on under the hood. You'll actually see the page scroll and then get set back to the previous scroll position.
This was only tested in Chrome and Firefox 13! So you may have to adjust the setTimeout duration -- currently 0 -- to a different value in browsers like Internet Explorer. Be prepared to gracefully degrade -- by supporting this feature only in modern browsers -- if necessary.
UPDATE:
For reference, below is the method to use to make this compatible in the major browsers. It has been tested in Chrome, Firefox, IE8, IE9, and Safari.
While it does work in IE8/IE9, it isn't very smooth.
// put the eventhandler in a named function so it can be easily assigned
// to other events.
function noScrollEvent(e) {
e = e || window.event;
if(e.keyCode == 32) {
setTimeout(
(function(scrollval) {
return function() {
$(document).scrollTop(scrollval);
};
})( $(document).scrollTop() ), 0);
}
}
// Chrome and Firefox must use onkeydown
window.onkeydown = noScrollEvent;
// Internet Explorer 8 and 9 and Safari must use onkeypress
window.document.onkeypress = noScrollEvent;
If another element is bound to the keydown event it will not be effected by this code
See my fiddle and try adding and remove the textarea listening to the keydown event
window.onkeydown = function(e) {
return !(e.keyCode == 32);
};
document.getElementsByTagName("textarea")[0].onkeydown = function(e) {
alert("hi");
}
http://jsfiddle.net/HnD4Y/
The answer above with the setTimeout did not work for me at all on Chome with a delay of 0. With a delay bumped above 50ms, it began to work, but that caused a noticeable page jump. I believe that setTimeout was scrolling the page up too early, then Chrome moved it down later.
Below is my solution that is working well. It returns false on the keydown event to prevent the browser from doing a page-down. Then you make sure event you set up on your button etc. to use the keyup event instead.
$(mySelector).keyup(eventHandlerFunction);
[dom element].onkeydown = function(event) {
if (event.keyCode == 32) {return false;}
};
Note: input fields will not reflect spacebar key events if they or their parent are covered by this onkeydown handler