onKeyPress Vs. onKeyUp and onKeyDown - javascript

What is the difference between these three events? Upon googling I found that:
The onKeyDown event is triggered when the user presses a key.
The onKeyUp event is triggered when the user releases a key.
The onKeyPress event is triggered when the user presses & releases a key
(onKeyDown followed by onKeyUp).
I understand the first two, but isn't onKeyPress the same as onKeyUp? Is it possible to release a key (onKeyUp) without pressing it (onKeyDown)?
This is a bit confusing, can someone clear this up for me?

NOTE KeyPress is now deprecated. Use KeyDown instead.
KeyPress, KeyUp and KeyDown are analogous to, respectively: Click, MouseUp, and MouseDown.
Down happens first
Press happens second (when text is entered)
Up happens last (when text input is complete).
The exception is webkit, which has an extra event in there:
keydown
keypress
textInput
keyup
Below is a snippet you can use to see for yourself when the events get fired:
window.addEventListener("keyup", log);
window.addEventListener("keypress", log);
window.addEventListener("keydown", log);
function log(event){
console.log( event.type );
}

Check here for the archived link originally used in this answer.
From that link:
In theory, the onKeyDown and onKeyUp events represent keys being pressed or released, while the onKeyPress event represents a character being typed. The implementation of the theory is not same in all browsers.

Most of the answers here are focused more on theory than practical matters and there's some big differences between keyup and keypress as it pertains to input field values, at least in Firefox (tested in 43).
If the user types 1 into an empty input element:
The value of the input element will be an empty string (old value) inside the keypress handler
The value of the input element will be 1 (new value) inside the keyup handler.
This is of critical importance if you are doing something that relies on knowing the new value after the input rather than the current value such as inline validation or auto tabbing.
Scenario:
The user types 12345 into an input element.
The user selects the text 12345.
The user types the letter A.
When the keypress event fires after entering the letter A, the text box now contains only the letter A.
But:
Field.val() is 12345.
$Field.val().length is 5
The user selection is an empty string (preventing you from determining what was deleted by overwriting the selection).
So it seems that the browser (Firefox 43) erases the user's selection, then fires the keypress event, then updates the fields contents, then fires keyup.

First, they have different meaning: they fire:
KeyDown – when a key was pushed down
KeyUp – when a pushed button was released, and after the value of input/textarea is updated (the only one among these)
KeyPress – between those and doesn't actually mean a key was pushed and released (see below). Not only it has inconsistent semantics, it was deprecated, so one shouldn't probably use it (see also this summary)
Second, some keys fire some of these events and don't fire others. For instance,
KeyPress ignores delete, arrows, PgUp/PgDn, home/end, ctrl, alt, shift etc while KeyDown and KeyUp don't (see details about esc below);
when you switch window via alt+tab in Windows, only KeyDown for alt fires because window switching happens before any other event (and KeyDown for tab is prevented by system, I suppose, at least in Chrome 71).
Also, you should keep in mind that event.keyCode (and event.which) usually have same value for KeyDown and KeyUp but different one for KeyPress. Try the playground I've created. By the way, I've noticed quite a quirk: in Chrome, when I press ctrl+a and the input/textarea is empty, for KeyPress fires with event.keyCode (and event.which) equal to 1! (when the input is not empty, it doesn't fire at all).
Note: these days, using event.key is the most useful option as it is standardized across browsers, OSes and events (afaik).
Finally, there's some pragmatics:
For handling arrows, you'll probably need to use onKeyDown: if user holds ↓, KeyDown fires several times (while KeyUp fires only once when they release the button). Also, in some cases you can easily prevent propagation of KeyDown but can't (or can't that easily) prevent propagation of KeyUp (for instance, if you want to submit on enter without adding newline to the text field).
Suprisingly, when you hold a key, say in textarea, both KeyPress and KeyDown fire multiple times (Chrome 71), I'd use KeyDown if I need the event that fires multiple times and KeyUp for single key release.
KeyDown is usually better for games when you have to provide better responsiveness to their actions.
esc is usually processed via KeyDown: KeyPress doesn't fire and KeyUp behaves differently for inputs and textareas in different browsers (mostly due to loss of focus)
If you'd like to adjust height of a text area to the content, you probably won't use onKeyDown but rather onKeyPress (PS ok, it's actually better to use onChange for this case).
I've used all 3 in my project but unfortunately may have forgotten some of pragmatics. (to be noted: there's also input and change events)

onkeydown is fired when the key is down (like in shortcuts; for example, in Ctrl+A, Ctrl is held 'down'.
onkeyup is fired when the key is released (including modifier/etc keys)
onkeypress is fired as a combination of onkeydown and onkeyup, or depending on keyboard repeat (when onkeyup isn't fired). (this repeat behaviour is something that I haven't tested. If you do test, add a comment!)
textInput (webkit only) is fired when some text is entered (for example, Shift+A would enter uppercase 'A', but Ctrl+A would select text and not enter any text input. In that case, all other events are fired)

This article by Jan Wolter is the best piece I have came across, you can find the archived copy here if link is dead.
It explains all browser key events really well,
The keydown event occurs when the key is pressed, followed immediately by the keypress event. Then the keyup event is generated when the key is released.
To understand the difference between keydown and keypress, it is useful to distinguish between characters and keys. A key is a physical button on the computer's keyboard. A character is a symbol typed by pressing a button. On a US keyboard, hitting the 4 key while holding down the Shift key typically produces a "dollar sign" character. This is not necessarily the case on every keyboard in the world. In theory, the keydown and keyup events represent keys being pressed or released, while the keypress event represents a character being typed. In practice, this is not always the way it is implemented.
For a while, some browers fired an additional event, called textInput, immediately after keypress. Early versions of the DOM 3 standard intended this as a replacement for the keypress event, but the whole notion was later revoked. Webkit supported this between versions 525 and 533, and I'm told IE supported it, but I never detected that, possibly because Webkit required it to be called textInput while IE called it textinput.
There is also an event called input, supported by all browsers, which is fired just after a change is made to to a textarea or input field. Typically keypress will fire, then the typed character will appear in the text area, then input will fire. The input event doesn't actually give any information about what key was typed - you'd have to inspect the textbox to figure it out what changed - so we don't really consider it a key event and don't really document it here. Though it was originally defined only for textareas and input boxes, I believe there is some movement toward generalizing it to fire on other types of objects as well.

It seems that onkeypress and onkeydown do the same (whithin the small difference of shortcut keys already mentioned above).
You can try this:
<textarea type="text" onkeypress="this.value=this.value + 'onkeypress '"></textarea>
<textarea type="text" onkeydown="this.value=this.value + 'onkeydown '" ></textarea>
<textarea type="text" onkeyup="this.value=this.value + 'onkeyup '" ></textarea>
And you will see that the events onkeypress and onkeydown are both triggered while the key is pressed and not when the key is pressed.
The difference is that the event is triggered not once but many times (as long as you hold the key pressed). Be aware of that and handle them accordingly.

Updated Answer:
KeyDown
Fires multiple times when you hold keys down.
Fires meta key.
KeyPress
Fires multiple times when you hold keys down.
Does not fire meta keys.
KeyUp
Fires once at the end when you release key.
Fires meta key.
This is the behavior in both addEventListener and jQuery.
https://jsbin.com/vebaholamu/1/edit?js,console,output <-- try example
(answer has been edited with correct response, screenshot & example)

The onkeypress event works for all the keys except ALT, CTRL, SHIFT, ESC in all browsers where as onkeydown event works for all keys. Means onkeydown event captures all the keys.

Just wanted to share a curiosity:
when using the onkeydown event to activate a JS method, the charcode for that event is NOT the same as the one you get with onkeypress!
For instance the numpad keys will return the same charcodes as the number keys above the letter keys when using onkeypress, but NOT when using onkeydown !
Took me quite a few seconds to figure out why my script which checked for certain charcodes failed when using onkeydown!
Demo: https://www.w3schools.com/code/tryit.asp?filename=FMMBXKZLP1MK
and yes. I do know the definition of the methods are different.. but the thing that is very confusing is that in both methods the result of the event is retrieved using event.keyCode.. but they do not return the same value.. not a very declarative implementation.

Basically, these events act differently on different browser type and version, I created a little jsBin test and you can check the console for find out how these events behavior for your targeted environment, hope this help. http://jsbin.com/zipivadu/10/edit

The difference which I observed between keyup and keydown is
if we attach a eventhandler for keydown event and log the input box value i.e
(e.target.value) it returns whatever the value was before keydown event
But if we attach a eventhandler for keyup event and log the input box value
it returns the latest value including the key which was pressed
LETS UNDERSTAND WITH EXAMPLE
// the latest keypressed is not shown in e.target.value
// when keydown event handler is executed
// since until the keyup is not triggered
// the input box will not have that character in its value
const searchCitiesEleKeyDown = document.querySelector("#searchCities");
searchCitiesEleKeyDown.addEventListener("keydown", (e) => {
console.log(e.target.value);
});
// but in case of keyup event the e.target.value prints
// the text box content with the latest character pressed
// since as soon as the keyup event triggers
// the input box will have that character pressed in its value
const searchCitiesEleKeyUp = document.querySelector("#searchCities");
searchCitiesEleKeyUp.addEventListener("keyup", (e) => {
console.log(e.target.value);
});
<input type="text" id="searchCities" />
CodeSandbox Link
https://codesandbox.io/s/keydown-vs-keyup-wpj33m

A few practical facts that might be useful to decide which event to handle (run the script below and focus on the input box):
$('input').on('keyup keydown keypress',e=>console.log(e.type, e.keyCode, e.which, e.key))
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input/>
Pressing:
non inserting/typing keys (e.g. Shift, Ctrl) will not trigger a keypress. Press Ctrl and release it:
keydown 17 17 Control
keyup 17 17 Control
keys from keyboards that apply characters transformations to other characters may lead to Dead and duplicate "keys" (e.g. ~, ´) on keydown. Press ´ and release it in order to display a double ´´:
keydown 192 192 Dead
keydown 192 192 ´´
keypress 180 180 ´
keypress 180 180 ´
keyup 192 192 Dead
Additionally, non typing inputs (e.g. ranged <input type="range">) will still trigger all keyup, keydown and keypress events according to the pressed keys.

BLAZOR....
If you want to check which key is pressed use onkeypress OR onkeydown but if you want to get the text from the text field and then check the last key pressed for example you are scanning a barcode and you want to fire an even when the ENTER key is pressed (almost all barcode scanners send 13 "ENTER" in the last) then you should use onkeyup otherwise you will not get the text typed in the text field.
For example
<input type="text" class="form-control" #bind="#barcode" #onkeyup="BarCodeScan" placeholder="Scan" />
This will call the BarCodeScan function immediately after you will press enter by typing the code or if you scan it from scanner the BarCodeScan function will be called automatically. If you will use "onkeypress" or "onkeydown" here then the bind will not take place and you will not get the text from the text field.

Related

How can I tell that keydown will cause keypress event and in that case ignore it?

I'm not very satisfied with the key events in javascript. I need to capture both letters for writing (I'm writing text on <canvas>) and functional keys (escape) for other commands.
In Firefox it works, because Firefox fires keypress event for any key. It's very comfortable but specification directly permits it:
If supported by a user agent, this event MUST be dispatched when a key is pressed down, if and only if that key normally produces a character value.
I disagree with that specification as I see no reason for it. But as it is now, I can't do anything about it.
Problem is that Google Chrome follows that specification and doesn't fire keypress for functional keys. It does, however, notmally fire keydown for all keys.
My program has only one key event handler. It expects event containing keyCode (the ID of the physical key and optionally charCode, the equivalent character value (for keys where it makes sense).
keydown event does not contain any character values in neither browser! It only contains the keyCode. So if you define a Ctrl+Z combination and listen for keydown event, your program will be broken for users that have QWERTZ layout - because the physical location of the key (keyCode) is still the same.
If you listen for both keydown and keypress, character events will fire twice (beacuse character first fires keydown and then keypress with proper charCode property)
What I need?
Based on the above, I need to ignore keydown event for keys that will cause keypress. Doing so, I'll be able to capture Esc in keydown and characters in keypress.
How could I possibly do it?
Relevant code:
//Keypress for character codes
div.addEventListener("keypress", function(event) {
console.log(event);
if(_this.editor.event(event)) {
console.log("Event canceled.");
event.preventDefault();
event.cancelBubble = true;
return false;
}
return true;
});
//Keydown for Esc and the likes
div.addEventListener("keydown", function(event) {
//Character events are handled by keypress
if(event.charCode!=0) //Does NOT work - in keydown, charCode is ALLWAYS 0
return true;
console.log(event);
if(_this.editor.event(event)) {
console.log("Event canceled.");
event.preventDefault();
event.cancelBubble = true;
return false;
}
return true;
});
Interactive example
I figured I spend a lot of time making JSFiddles and it doesn't really increase the odds of getting an answer, so I instead uploaded the actual project.
Click into the white square in Firefox, press T, type text, press Esc, press Esc. After seconds Esc, cursor should get back to normal. Try to draw and press Ctrl+Z.
Repeat the process in Google Chrome. The Escape will not work because it doesn't fire keypress. For some reason, the Ctrl+Z fires event with keyCode 26.
From chat and comments:
#someDoge has created a fiddle which I have expanded and which now nicely shows the situation. As you can see, you can know that a key isn't character and ignore it in keypress. But you can't know that tab isn't character and cancel it in keydown (unless you have fixed array of keycode values as #someDoge sugests in comments).
You need to listen for keyup events instead of keydown, this way you won't get two separate events generated.
Then you can handle the 2 event types with the same handler function which will either get a charCode or not, depending on if the particular key generated a 'keypress' event. As long as you prevent bubbling your handler will only be called once.
Regarding the Chrome CTRL+Z problem: I don't see how you can get a charCode if the control key is being pressed, since it seems only to generate a keyup event.

Why can I preventDefault event on keydown but not on keyup with Javascript?

When using .keydown I can capture keydown event, then check and prevent default action (display the character).
When using .keyup I cannot?
I know the event is being captured as alert() fires when the code is inside the condition yet the preventDefault() doesn't prevent the action.
Here is a full DEMO
In keyup event the character has been typed and can't be undone but in keydown nothing has been typed and the browser has intent to type the character, so you can cancel the browser intent.
Whenever you type a character the following events occur:
keydown --> keypress repeatedly until the key is released --> keyup
keydown -> can be prevented -> fired when press a key
keypress -> can be prevented -> fired when hold a key
keyup -> cannot be prevented -> fired when release a key
the keydown() event is fired when the key is hit, meaning that code can be executed before the key is released.
When the key is pressed code can prevent an action, because it simply hasn't happened yet, whereas on the keyup() event, it already has.
e.g. a character has already been inserted into an input field when triggering keyup()
in general, keydown and keyup produce the same keycodes (when used with a given event)
however keypress gives you the physical key pressed (ASCII code returned rather than keyCode)

Handle a keyboard that produces only keypress instead of keydown/keyup events

I have a weird situation where a specialty PC keyboard produces strange codes in JavaScript when pressing the number keys.
Using this site (http://unixpapa.com/js/testkey.html), I found that the keyboard produces this when pressing the number 4:
keydown keyCode=18 which=18 charCode=0
keydown keyCode=101 (e) which=101 (e) charCode=0
keyup keyCode=101 (e) which=101 (e) charCode=0
keydown keyCode=98 (b) which=98 (b) charCode=0
keyup keyCode=98 (b) which=98 (b) charCode=0
keyup keyCode=18 which=18 charCode=0
keypress keyCode=52 (4) which=52 (4) charCode=52 (4)
A regular keyboard produces this:
keydown keyCode=52 (4) which=52 (4) charCode=0
keypress keyCode=52 (4) which=52 (4) charCode=52 (4)
keyup keyCode=52 (4) which=52 (4) charCode=0
So basically, this strange device holds the ALT key, adds two other characters, lets go of the ALT key, and THEN fires ONLY the keypress event for the actual key while ignoring keydown and keyup completely.
I can filter out the first part with event.altKey no problem, but it's the rest that is causing issues.
The problem is that my code was written to do one thing on keydown and another on keyup, and adding keypress only for this one keyboard is messing up everything...
I doubt there's a solution for this, and we probably just won't support this ... weird piece of hardware, but just in case:
Any ideas on how to detect if a keyboard creates only keypress (after filtering out the other event.altKey events before that)?
I tried having a global variable that contains the current event code and that is reset both on keypress and keyup and otherwise receives the current keycode, but I just can't get this to work...
Here's my code:
<input type="text" name="entry" id="entry" onkeyup="Entry('up', this, event);" onkeydown="Entry('down', this, event);" />
Yes, all keyboard events are supposed to be passed through into the text field, so no return needed here.
And the JavaScript:
function Entry(dir, field, evt)
{
// filter out Num Lock, Alt and Alt Pressed
if (evt.keyCode == 144 || evt.keyCode == 18 || evt.altKey)
return false;
if (dir == 'up') // keyup
{
if (field.value.length > 0)
{
if (evt.keyCode == 13) // Enter pressed
{
EnterUser(); // if more entries are found with FindUser(), select the first one, otherwise empty the screen
}
else
{
FindUser(); // start ajax that checks field content vs database
}
}
}
else // keydown
{
if (!field.disabled)
{
EmptyScreen(); // if the text field is disabled because a dialog box is in front, empty the screen.
}
}
}
The trick, of course, is to support this weird keyboard while not breaking stuff for other keyboards and barcode scanners that are currently working.
Chance are that we'll have to tell the customer "Sorry, get yourself a proper keyboard" or something, but it's bugging me :-)
Any thoughts on this?
Thanks!
PS: I have jQuery on that site, so if there's any good ideas that use that, I'd be game, too.
I have stumbled on this problem as well. A barcode scanner configured to send text in alt codes does this too.
There is an easy solution at least for Chrome (I haven't checked firefox), but both IE, and Edge requires a different approach, because those browsers fail to raise KeyUp event for the Alt key, which is an essential part to the solution.
Google chrome registers the Alt keyUp event, and event translates the "alt-code". All you need to do is to skip keys while the Alt key is being held and check the key property when on the Alt KeyUp event:
For IE and Edge browsers, you need to save characters while the alt key is held, convert them to a number and use String.fromCharCode(057) to get "9", the problem is it is hard to detect when to convert, because there are no KeyUp event for Alt button after "alt-code".
The solution I chose and that works with every browser (I think), was to focus a hidden input field on KeyDownevent for Alt key, and read its contents after they change, because inputs correctly handle the "Alt codes"
This might be late answer but may be of some use to other people.

Key event doesnt trigger in Firefox on Android when word suggestion is on

I have a search field that triggers an autocomplete search while typing. I have it trigger on keyup. This works perfectly in most browsers, but in Firefox on Android, this does not work. It seems like the keyup event is not triggered while typing. This only happens if word suggestions is turned on in the Android keyboard settings.
I see on Google search that the autocomplete search works there for the same setup, so it is obviously possible to do. I wonder how? Is it a special event I need to listen to for this to work?
Additionally I have tried to listen to the events change, keydown and keypress, but none is triggered.
HTML:
<input type="text" id="searchField"
autocomplete="off" spellcheck="false" autocorrect="off" />
jQuery event binding:
$('#searchField').keyup(function (e) {
var searchValue = $(this).val();
searchApi._executeAutocomplete(searchValue);
});
Note:
Sometimes, the key event is triggered, which is typically hitting a key that is not resulting in the process of forming a word. The most obvious here is Enter, which always triggers. Another is Space, which triggers because no word contain a space since space is the definition of a word completed. Backspace triggers if the the last character deleted was not within a word. This means it triggers if you just deleted the last remaining letter of a word (so it is the start of the field, or cursor following a space), but not if you deleted some characters at the end of a word where the cursor is still immediately following a letter. Basically, the key event is not triggered if the key press results in some kind of word suggestion from the keyboard app.
As a side note, I can say that everything works fine in Chrome on the same device.
You can use the input event instead, that worked for me in Firefox on Android.
You could bind event handlers to both input and keyup events for backwards compatibility, but in most modern browsers this will fire both:
$('#searchField').bind('input keyup', function(e){
var searchValue = $(this).val();
searchApi._executeAutocomplete(searchValue);
});
Example here:
http://jsfiddle.net/JQ928/3/
I found a solution in this answer to another question. The question was a basically "duplicate the text I write dynamically into another part of the page". The answer was including support for catching changes by non-keyboard actions, like pasting text using mouse. It was solved by starting a sniffer on focus in the text field that checks if the value has changed using setInterval(...). It clears the timer on blur.
This solved my problem which was basically that the key events didn't trigger, as well as the "paste by mouse" issue that I didn't realize was a problem until I found this answer...!
This works, but I'm not sure I am totally happy with this solution, because it uses a sniffer. I would be more happy with using some sort of event that is triggered on value change no matter what the cause of the change is. Using the change event would not work, as that is not triggered until focus leaves the field.
Trough the fact that Firefox on Android doesn't trigger key-events, but also triggers the input-event some kind of weird, (like if you press one key two events get triggerd, and it also triggers the input-event if you leave the input) I had to write my own event:
(function($){
var $event = $.event,
$special = $event.special.fennecInput = {
setup: function(){
$(this).on('input',$special.handler);
},
teardown: function(){
$(this).off('input',$spceial.handler);
},
handler: function(event) {
var context = this,
args = arguments,
dispatch = function() {
event.type='fennecInput';
$event.dispatch.apply(context,args);
};
if($(context).val() != $(context).attr('data-fennecInput-oldval')){
dispatch();
$(context).attr('data-fennecInput-oldval',$(context).val());
}
}
};
})(jQuery);
this event gets only triggered if an input-event happens that changes the value, so it doesn't execute events unnecessary.

Javascript, key press value is always one character behind the latest?

If I type 'St', by the time I press the t, if I output the input of textfield.value in the onkeypress/onkeydown functions, I only get 'S'.
Why is this? How do I get rid of this lag?
use the keyup event instead of keypress. keydown will show the before-keystroke value, as will keypress (apparently).
Within the keypress event, it's still possible to prevent the typed character from registering, so the input's value canot be updated until after the keypress event. You can use the keyup event instead, or use window.setTimeout() to set up a delay.
Because the keystroke is not registered until keyup event occurs. So you should detect onkeyup event instead of onkeypress.

Categories

Resources