68

How to know if .keyup() is a character key (jQuery)

$("input").keyup(function() {

if (key is a character) { //such as a b A b c 5 3 2 $ # ^ ! ^ * # ...etc not enter key or shift or Esc or space ...etc
/* Do stuff */
}

});
faressoft
  • 19,053
  • 44
  • 104
  • 146

7 Answers7

103

You can't do this reliably with the keyup event. If you want to know something about the character that was typed, you have to use the keypress event instead.

The following example will work all the time in most browsers but there are some edge cases that you should be aware of. For what is in my view the definitive guide on this, see http://unixpapa.com/js/key.html.

$("input").keypress(function(e) {
    if (e.which !== 0) {
        alert("Charcter was typed. It was: " + String.fromCharCode(e.which));
    }
});

keyup and keydown give you information about the physical key that was pressed. On standard US/UK keyboards in their standard layouts, it looks like there is a correlation between the keyCode property of these events and the character they represent. However, this is not reliable: different keyboard layouts will have different mappings.

Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • I just encountered a similar problem, where I was *not* able to detect and disable the ENTER key with `keyup`, but I *was* able to do this with `keypress`. – Ian Campbell Jan 10 '14 at 06:00
  • 1
    @IanCampbell ```keydown``` would have worked too. It's because with ```keyup``` the enter button has already been pressed and received before the key was lifted up. – Ryan Taylor Sep 23 '14 at 17:33
  • The keypress event isn't fully reliable. In chrome, If you highlight a character and type a new character over it no keypress event is triggered. – danielson317 Apr 13 '16 at 21:18
  • 1
    @TimDown Looks like you are right. I had a conflicting event that would cancel the keypress by accident. thanks for setting me straight. – danielson317 Apr 14 '16 at 14:24
  • keypress doesnt work on android.... so keypress is not even an option in the first place – Toskan Mar 08 '20 at 04:11
  • WARNING: While keypress may still be the "better" answer here, the value is not rendered when the keypress triggers the way it is for keyup. Fiddle: https://jsfiddle.net/myingling/57ht0ys8/1/ – Bing May 06 '20 at 04:23
  • @Bing: True but not really relevant to this question. Makes sense when you consider that when the `keypress` event is raised, the typing effect can still be prevented by calling `preventDefault()` on the event. If you want an event fired after the character has been inserted, you may want `input` event, although this is fired for any input, not just via keystrokes. – Tim Down May 06 '20 at 08:20
  • @TimDown Given that the question specifically asked about the `keyup` function this seemed a very important distinction. Especially for those not familiar with the jQuery event orders (for example someone who go here by searching Google specifically for `keyup`). Understand and agreed there are ways to work around it, but the order of execution differing can certainly complicate those work-arounds. – Bing May 06 '20 at 21:40
46

Note: In hindsight this was a quick and dirty answer, and may not work in all situations. To have a reliable solution, see Tim Down's answer (copy pasting that here as this answer is still getting views and upvotes):

You can't do this reliably with the keyup event. If you want to know something about the character that was typed, you have to use the keypress event instead.

The following example will work all the time in most browsers but there are some edge cases that you should be aware of. For what is in my view the definitive guide on this, see http://unixpapa.com/js/key.html.

$("input").keypress(function(e) {
    if (e.which !== 0) {
        alert("Character was typed. It was: " + String.fromCharCode(e.which));
    }
});

keyup and keydown give you information about the physical key that was pressed. On standard US/UK keyboards in their standard layouts, it looks like there is a correlation between the keyCode property of these events and the character they represent. However, this is not reliable: different keyboard layouts will have different mappings.


The following was the original answer, but is not correct and may not work reliably in all situations.

To match the keycode with a word character (eg., a would match. space would not)

$("input").keyup(function(event)
{ 
    var c= String.fromCharCode(event.keyCode);
    var isWordcharacter = c.match(/\w/);
}); 

Ok, that was a quick answer. The approach is the same, but beware of keycode issues, see this article in quirksmode.

HankScorpio
  • 3,612
  • 15
  • 27
Nivas
  • 18,126
  • 4
  • 62
  • 76
  • 1
    On Firefox keyCode for F1 key and P keys is the same (also F2 is 'q', F3 is 'r' etc.). On Chromium (Webkit browser) F1 is 'P', F2 is 'Q' etc. – hluk Oct 20 '10 at 12:47
  • 5
    You can't get the character typed reliably from the `keyup` event. This may work on your keyboard but for different keyboard types and different cultures there are no guarantees at all. – Tim Down Oct 20 '10 at 13:13
  • 3
    If @TimDown's point wasn't clear enough, here's another one: **this is basically the wrong answer**. – Christian Jun 21 '12 at 13:10
  • @Christian agreed. I had answered this almost 2 years ago. Now when I look at it I know this is wrong. I don't even remember what I was thinking when I wrote this. I am unable to delete this as this is the accepted answer (but would be glad to if a Mod can help) – Nivas Jun 22 '12 at 15:40
  • I wouldn't delete it, it's still an *answer*. But sadly it seems mods aren't much proactive about the issue. – Christian Jun 22 '12 at 18:44
  • IMO mods should focus on getting this sort of answers fixed and put in right place rather than policing around and marking questions "unconstructive". I've seen many "unconstructive" questions voted up hundreds times which obviously means people find these helpful. BTW I appreciate the time you put in answering – spirytus Apr 10 '15 at 04:44
  • FYI e.which is deprecated https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/which – Jonathan Andersson Mar 03 '17 at 10:05
  • keypress doesnt work on android.... so keypress is not even an option in the first place – Toskan Mar 08 '20 at 04:11
16

I'm not totally satisfied with the other answers given. They've all got some kind of flaw to them.

Using keyPress with event.which is unreliable because you can't catch a backspace or a delete (as mentioned by Tarl). Using keyDown (as in Niva's and Tarl's answers) is a bit better, but the solution is flawed because it attempts to use event.keyCode with String.fromCharCode() (keyCode and charCode are not the same!).

However, what we DO have with the keydown or keyup event is the actual key that was pressed (event.key). As far as I can tell, any key with a length of 1 is a character (number or letter) regardless of which language keyboard you're using. Please correct me if that's not true!

Then there's that very long answer from asdf. That might work perfectly, but it seems like overkill.


So here's a simple solution that will catch all characters, backspace, and delete. (Note: either keyup or keydown will work here, but keypress will not)

$("input").keydown(function(event) {

    var isWordCharacter = event.key.length === 1;
    var isBackspaceOrDelete = event.keyCode === 8 || event.keyCode === 46;

    if (isWordCharacter || isBackspaceOrDelete) {
        // do something
    }
});
Mike Doe
  • 16,349
  • 11
  • 65
  • 88
HankScorpio
  • 3,612
  • 15
  • 27
11

This helped for me:

$("#input").keyup(function(event) {
        //use keyup instead keypress because:
        //- keypress will not work on backspace and delete
        //- keypress is called before the character is added to the textfield (at least in google chrome) 
        var searchText = $.trim($("#input").val());

        var c= String.fromCharCode(event.keyCode);
        var isWordCharacter = c.match(/\w/);
        var isBackspaceOrDelete = (event.keyCode == 8 || event.keyCode == 46);

        // trigger only on word characters, backspace or delete and an entry size of at least 3 characters
        if((isWordCharacter || isBackspaceOrDelete) && searchText.length > 2)
        { ...
HankScorpio
  • 3,612
  • 15
  • 27
TARL
  • 129
  • 2
  • 5
  • Also works with copy/paste CTRL+C/CTRL+V. Much simple condition : `String.fromCharCode(e.keyCode).match(/\w/) || e.keyCode === 8 || e.keyCode === 46` – fdaugan Oct 06 '16 at 14:46
  • Small bug here. You're using `String.fromCharCode`, but inputting `event.keyCode`. Should be `event.charCode`. However, `event.charCode` is always 0 for the keyUp event (in Chrome, at least). This answer is flawed. If you inspect the variable `c` you'll see that it doesn't equate to the key that was pressed. – HankScorpio Oct 20 '16 at 18:54
4

I wanted to do exactly this, and I thought of a solution involving both the keyup and the keypress events.

(I haven't tested it in all browsers, but I used the information compiled at http://unixpapa.com/js/key.html)

Edit: rewrote it as a jQuery plugin.

(function($) {
    $.fn.normalkeypress = function(onNormal, onSpecial) {
        this.bind('keydown keypress keyup', (function() {
            var keyDown = {}, // keep track of which buttons have been pressed
                lastKeyDown;
            return function(event) {
                if (event.type == 'keydown') {
                    keyDown[lastKeyDown = event.keyCode] = false;
                    return;
                }
                if (event.type == 'keypress') {
                    keyDown[lastKeyDown] = event; // this keydown also triggered a keypress
                    return;
                }

                // 'keyup' event
                var keyPress = keyDown[event.keyCode];
                if ( keyPress &&
                     ( ( ( keyPress.which >= 32 // not a control character
                           //|| keyPress.which == 8  || // \b
                           //|| keyPress.which == 9  || // \t
                           //|| keyPress.which == 10 || // \n
                           //|| keyPress.which == 13    // \r
                           ) &&
                         !( keyPress.which >= 63232 && keyPress.which <= 63247 ) && // not special character in WebKit < 525
                         !( keyPress.which == 63273 )                            && //
                         !( keyPress.which >= 63275 && keyPress.which <= 63277 ) && //
                         !( keyPress.which === event.keyCode && // not End / Home / Insert / Delete (i.e. in Opera < 10.50)
                            ( keyPress.which == 35  || // End
                              keyPress.which == 36  || // Home
                              keyPress.which == 45  || // Insert
                              keyPress.which == 46  || // Delete
                              keyPress.which == 144    // Num Lock
                              )
                            )
                         ) ||
                       keyPress.which === undefined // normal character in IE < 9.0
                       ) &&
                     keyPress.charCode !== 0 // not special character in Konqueror 4.3
                     ) {

                    // Normal character
                    if (onNormal) onNormal.call(this, keyPress, event);
                } else {
                    // Special character
                    if (onSpecial) onSpecial.call(this, event);
                }
                delete keyDown[event.keyCode];
            };
        })());
    };
})(jQuery);
asdf
  • 41
  • 2
4

If you only need to exclude out enter, escape and spacebar keys, you can do the following:

$("#text1").keyup(function(event) {
if (event.keyCode != '13' && event.keyCode != '27' && event.keyCode != '32') {
     alert('test');
   }
});

See it actions here.

You can refer to the complete list of keycode here for your further modification.

bla
  • 5,350
  • 3
  • 25
  • 26
0

I never liked the key code validation. My approach was to see if the input have text (any character), confirming that the user is entering text and no other characters

$('#input').on('keyup', function() {
    var words = $(this).val();
    // if input is empty, remove the word count data and return
    if(!words.length) {
        $(this).removeData('wcount');
        return true;
    }
    // if word count data equals the count of the input, return
    if(typeof $(this).data('wcount') !== "undefined" && ($(this).data('wcount') == words.length)){
        return true;
    }
    // update or initialize the word count data
    $(this).data('wcount', words.length);
    console.log('user tiped ' + words);
    // do you stuff...
});
<html lang="en">
  <head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  </head>
  <body>
  <input type="text" name="input" id="input">
  </body>
</html>
lordlouis
  • 11
  • 2