0

I am using WordPress jQuery to build some shortcuts for my site.

It works as intended, however it doesn't stop when other keys are pressed.

For example, if I press, f it performs the necessary task. But if I press CTRL + f then also it does the task.

Infact, I tried, other keys like f and p and that too worked.

I want it to only work on the specific key. Incase of any other key press, it should not run. It should run on clicking f, but NOT run on CTRL + f.

I tested this on Chrome 92.0.4515.159 and Chrome Beta Version 94.0.4606.31 on Windows 7 and 8.

    jQuery(window).keydown(function(e) {
        if( e.which === 27){
            jQuery('.SearchCreationsClose').click();
        }
        if(e.key == "f"){
            e.preventDefault();
            jQuery('.SearchCreationsIcon').click();
        }
    });
Aditya Agarwal
  • 52
  • 1
  • 14

3 Answers3

1

I think the best solution would be to merge this: Can jQuery .keypress() detect more than one key at the same time? with some sort of timeout like this:

var keys = {};
var eventTimeout;

$(document).keydown(function (e) {
  // Reset timeout
  if (eventTimeout) {
    clearTimeout(eventTimeout);
  }
  keys[e.which] = true;
  eventTimeout  = setTimeout(function () {
    if (typeof keys[70] !== "undefined"  && Object.keys(keys).length === 1) { // 70 is the "f" key and it is the only pressed key
      e.preventDefault();
      $('.SearchCreationsIcon').click();
    }
  }, 200); // Takes 200ms of time before going on
});

$(document).keyup(function (e) {
setTimeout(function(){
  delete keys[e.which];
},210);
});

The idea is that when you detect keydown you wait a little bit to see if there are others key pressed or just the "f" key. The keyup clears the buffer to ensure there are no leftovers

Edit for combo: This would be the solution to catch CTRL + SHIFT + S, see updated code. I just moved out code from if and nested into separated function. You could easily abstract the function to accept an arbitrary number of keys simultaneously pressed together with which keys should be pressed and create a single function. You got the idea

var keys = {};
var eventTimeout;

$(document).keydown(function (e) {
    // Reset timeout
    if (eventTimeout) {
        clearTimeout(eventTimeout);
    }
    keys[e.which] = true;
    eventTimeout  = setTimeout(function () {
        if (isFPressed() || isMyComboPressed()) { // 70 is the "f" key and it is the only pressed key
            e.preventDefault();
            $('.SearchCreationsIcon').click();
        }
    }, 200); // Takes 200ms of time before going on
});

function isFPressed() {
    return typeof keys[70] !== "undefined" && Object.keys(keys).length === 1;
}

/**
 * 16 - Key code of SHIFT
 * 17 - Key code of CTRL
 * 83 - Key code of "s"
 * @returns {boolean}
 */
function isMyComboPressed(){
    return typeof keys[16] !== "undefined" && keys[17] !== "undefined" && keys[83] !== "undefined" && Object.keys(keys).length === 3;
}

$(document).keyup(function (e) {
    setTimeout(function () {
        delete keys[e.which];
    }, 210);
});
Diego
  • 1,610
  • 1
  • 14
  • 26
  • Had read somewhere that it's better to use keydown instead of keypress... so tried with keydown... Anyways allow me an hour, as I am not at office. Thanks for help tho. – Aditya Agarwal Sep 08 '21 at 07:58
  • Hey thanks for helping... Most of it works... Actually the code in question was one of the several shortcut keys on my site... I was building another shortcut involving CTRL and SHIFT and S key... this is the code that I was using `if((e.ctrlKey || e.metaKey) && e.shiftKey && e.which == 83){` how to check for the other the other 2 keys using your code? I tried typeof keys[CTRL] that didnt work – Aditya Agarwal Sep 08 '21 at 10:04
  • Thanks, But I already know the keycodes of CTRL and SHIFT.. Problem is someone told me that this works only with Windows, for it to work on macOS, I need to use the e.metaKey, so how to do that... (You can look at my previous comment, how I coded to have either ctrlKey or metaKey) – Aditya Agarwal Sep 08 '21 at 13:36
  • Hey, I am using these shortcuts on a page with long textarea where people often type 1000+ words... So would timeout be troubling with ux, as I believe timeouts are much more resource intensive as far as I know? If yes, then could their be a better approach – Aditya Agarwal Sep 08 '21 at 17:15
  • I've actually wrote the code using macOS, so the keys must be correct by that mean. About the performance issue i don't really know, you should test it out with intensive writing and see if it blows up. In the while i'll try to think if there's a better solution to this problem – Diego Sep 09 '21 at 08:36
  • Great. I implemented it and works flawlessly on windows, happy to hear that it works on macOS too... BTW the concern for performance came because of this. https://stackoverflow.com/questions/69112118/can-settimeout-on-keydown-affect-performance Somehow, when I change windows by using Alt+Tab and come back to it after 5-10 seconds... the shortcuts stop working... This is tested on 2 windows machines with 5-6 year old specs... So I thought it was performane thing... :-p – Aditya Agarwal Sep 09 '21 at 09:18
  • Hey, I think I misunderstood the issue. The issue is far bigger. If we go away from the url with key pressed the shortcuts stop working until reload. I am sharing a screen recording. In it I use On-Screen keyboard just to show you what I am doing, but in the issue is same with real keyboard. I load url and use shortcuts, it work perfectly. Then I go to another tab by mouse click & return to the url via mousclick it works. BUT then I use CTRL+2 to change tabs & CTRL+1 to return & then shortcuts stop working https://drive.google.com/file/d/14FOakHpekhN2eGxq9e6snYr4i7a5wtpV/view?usp=sharing – Aditya Agarwal Sep 09 '21 at 12:33
  • This is true with any action that involves going out of page with key pressed, Alt+Tab, Ctrl+ 0-9 in chrome, Windows + 0-9 or anything. While a key is pressed if the page gets out of view shortcuts stop. Please help – Aditya Agarwal Sep 09 '21 at 12:35
  • Can confirm e.preventDefault isnt running properly either, because preventDefault is inside Timeout – Aditya Agarwal Sep 10 '21 at 06:17
1

I saw the answer from @diego and understand that you want to implement shortcuts such that they are limited to a specific key combination, extra keypress will stop the function.

The solution was really good, but reading comments there are 2 main problems, 1.) It stops when the window goes out of focus, and 2.) event.preventDefault doesn't not work

I have a solution, that works without the timeout function, making it solve the e.preventDefault problem. And I use a different approach to make it happen.

    var MyKeys= 0;

    jQuery(window).focus(function(){
        MyKeys = 0;
    });

    jQuery(window).keyup(function(e){
        if(MyKeys > 0){
            MyKeys--
        }
        else {
            MyKeys = 0;
        }
    });

    jQuery(window).keydown(function(e){
        if (!e.repeat) {
            MyKeys++
        }
        if(e.which == 70 && MyKeys === 1){
            e.preventDefault();
            console.log('f is pressed')
        }
        if(e.which == 70 && (e.ctrlKey || e.metaKey) && MyKeys === 2){
            e.preventDefault();
            console.log('ctrl+f is pressed')
        }
    });

Pretty sure that it solves the prevent default problem..

And I think it will solve the Alt + Tab problem too... (Haven't tested but am confident)

It isn't perfect. There is only a small limitation, if a user comes focuses into your Windows with a key already pressed, he would have to lift the key before being able to use the shortcut. He cants just focus in with CTRL pressed and then press f.

Amit Bajar
  • 98
  • 7
0

Use e.ctrlKey which is true if ctrl key was pressed:

 jQuery(window).keydown(function(e) {
  if(e.key=='f' && e.ctrlKey){ 
    console.log('ctrl+f');} 
  else if (e.key=='f'){ 
     console.log('"JUST" f key');
  }
 });

If you want to catch only f keydown but not ctrl+f:

 jQuery(window).keydown(function(e) {
   if(e.key=='f' && !e.ctrlKey){ 
     console.log('"JUST" f key');
   }
 });
koalaok
  • 5,075
  • 11
  • 47
  • 91
  • Well, as I said the keydown works for every key, like if I press `f` and `p` then also it does the same task. I want it to work only with f. Your code prevents ctrl+f but it doesnt stop other key combinations – Aditya Agarwal Sep 06 '21 at 03:11
  • My code above logs only if you press key "f" or combination of ctrl+f, other key or combination won't be logged. Isn't it what you want to catch? – koalaok Sep 06 '21 at 06:37
  • Nope. See my code `if(e.key == "f"){jQuery('.SearchCreationsIcon').click();` This is more or less same as yours. It works when i press F, but it ALSO works when i press x + f or y + f or shift + f. I want it to work only when I press F and NO other KEY is pressed – Aditya Agarwal Sep 06 '21 at 09:46
  • The keyboard handler can only trigger on individual keys or on a combination with ctrl, opt, shift.... you should implement yourself how to catch other combinations using timeouts... – koalaok Sep 06 '21 at 10:38