When CMD key is kept pressed, keyup is not triggered for any other key
Asked Answered
A

3

30

I am developing an application where I need to do some post-processing when the user presses CMD+LEFT on a particular text-box. I need to do this after the browser's default functionality (i.e. after it takes the caret to first position in current physical line).

The problem is keyup is not being triggered for the LEFT key (or any key for that matter) as long as the CMD key is down.

I tried this with CTRL and SHIFT keys and found that keyup gets triggered as expected for the secondary key. So if you do CTRL+LEFT and then release LEFT and then release CTRL, you get four events in total, 2 keydowns and 2 keyups. For the CMD key however, we get 2 keydowns, but only one keyup event (the one for CMD key itself when we release it in the end).

I tried this with SHIFT key and found that keyup gets triggered as expected for the secondary key. So if you do SHIFT+LEFT and then release LEFT and then release SHIFT, you get 4 events in total, 2 keydowns and 2 keyups. For the CMD key however, we get 2 keydowns, but only one keyup event (the one for CMD key itself when we release it in the end).

What could it be? Is there any way I can get keyup triggered for the LEFT key (or any key) when CMD is down?

I'm trying this with the latest Google Chrome on OSX 10.9.5. The behaviour is exactly the same on Firefox too. So this isn't a Chrome issue.

Demo: http://jsfiddle.net/techfoobar/xu0o11nh/4/

Essentially:

$('#mytextbox')

    // this gets correctly triggered for the meta key as well as the secondary key
    // when you press CMD and LEFT in sequence, you get two lines in the console one for 
    // the CMD key and one for the LEFT key
    .keydown(function(_e) {
        console.log('Keydown: ' + _e.keyCode);
    })

    // however, if I release the LEFT key (while keeping the CMD key down)
    // this does NOT get triggered for the LEFT key
    .keyup(function(_e) {
        console.log('Keyup: ' + _e.keyCode);
    });
Argufy answered 9/12, 2014 at 13:25 Comment(4)
In chrome I get all events. jQuery send a key in the event which is called ctrlKey where you can check if ctrl is pressed... i dodnt check which is cmd but you can easily find it out by console complete eventDeracinate
@Mephiztopheles - The problem is only with the CMD key (event.metaKey courtesy jQuery).Argufy
Either I didn't understand your problem or I couldn't simulate it. Here is my console: 70(index):34 Keydown: 17 (index):34 Keydown: 37 (index):37 Keyup: 37 (index):37 Keyup: 17Salep
if you check my console, you'll see that I held CTRL and it triggered Keydown for 70 times, then I triggered down LEFT KEY, then I triggered up LEFT KEY, then I triggered up CTRL. puu.sh/dxnVq/8a9a74a2f8.pngSalep
P
7

This is known behavior with the meta key, and there is unfortunately no known workaround.

For your case, you may consider implementing the default browser behavior yourself (how to do that), then implement the custom behavior you need, and finish it off with _e.preventDefault();

Parathion answered 16/12, 2014 at 19:34 Comment(2)
Thank you. So thats that. Known issue. No easy workaround as well. Custom implementing CMD+LEFT (taking caret to first position in physical line of text considering wrapping, etc.) is too complicated for my simple purpose.Argufy
Your first link is broken. Here's a working link using the wayback machine. web.archive.org/web/20160304022453/http://bitspushedaround.com/…Uitlander
H
2

This is almost certainly to do with system set 'hot keys'.Apparently according to the docs this missing keyup event is expected behaviour too.

When i do cmdspace i dont even get a keydown event for the space as the spotlight window appears.

On your mention of the ctrl key: because i have 'spaces' set up when i ctrlleft or ctrlright i get no left or right keydown events fired, however ctrlup or ctrldown at least fire their keydown events.

I think it would be difficult to assume the use of a system that does not have the "default" hot keys setup.

Hardhack answered 12/12, 2014 at 2:30 Comment(5)
Hi, Thank you very much for the answer. But on a Mac, CMD+Left/Right does not have any system action, only a component (textbox) action - i.e. taking the caret to the first position in the current horizontal line of text. This is comparable to Shift+LEFT, which extends selection to the left by one position - but with Shift, we get 4 key events as outlined in the question, i.e. I can do post processing after Shift+Left is done extending the selection. The case with CMD+Space is understandable because it has a system action - Spotlight, same with Ctrl+Left/Right (mission control).Argufy
Also, the behaviour is exactly the same in Firefox, so this isn't a Chrome issue.Argufy
Agreed, I would totally not expect this to be Chrome specific behaviour. Perhaps a solution might lie in detecting the change in caret position: https://mcmap.net/q/501036/-detect-when-quot-cursor-position-inside-input-change-quot-in-jquery . However, this still is bound to the keydown event so not sure if it's what you're looking forHardhack
The only (ugly) solution I can think of as of now is capturing the last keydown and doing the post processing inside a setTimeout set for after a few milliseconds. Since the browser keeps firing keydowns for the secondary key as long as it is kept pressed, this should be possible. But imo not a very clean way to do it!Argufy
I suppose you can assume that given the cmd+left functionality happens immediately, any hold of the left key doesnt act to serve any better purpose (eg. unlike shift+left would)Hardhack
A
1

don't think you'll need a settimeout.

i've changed the code to detect 2 keydowns. this can be refactored further to a cleaner code.

http://jsfiddle.net/7nd7hf16/1/

var cmdDown = false;
$('#foo')
.keydown(function(_e) {
    if(_e.keyCode == 91)
        cmdDown = true;

    if(cmdDown && _e.keyCode == 37)
        console.log('cmd + left'); 

    console.log('Keydown: ' + _e.keyCode);
})
.keyup(function(_e) {
    if(_e.keyCode == 91)
        cmdDown = false;

    console.log('Keyup: ' + _e.keyCode);
})
.focus();
Agley answered 15/12, 2014 at 23:28 Comment(3)
Hi, Thank You for the your answer. The problem is not in detecting the keyup for the cmd key (which your answer addresses), but the keyup for the secondary key as long as the cmd key is kept pressed. Also, note that jQuery gives us _e.metaKey for detecting whether the cmd is pressed (i.e. we do not need to detect it ourselves as in your answer).Argufy
if(cmdDown && _e.keyCode == 37) console.log('cmd + left'); i think you've skipped the above code.. so, on cmd keydown using keycode or metakey you set a cmdDown to true and on key up you change it back to false.. since you know the cmd key state you can now check for the second key pressed..Agley
Thats right. I can get the keydown event correctly for CMD+<secondary key> like you've shown - The only problem is in getting the keyup event for the second key (LEFT in our case) as long as CMD is kept pressed down.Argufy

© 2022 - 2024 — McMap. All rights reserved.