43

Is it at all possible to combine a mixture of keypress' to fire a single event?

$(document).keyup(function(e){
    if (e.keyCode == 68 && e.keyCode == 69 && e.keyCode == 86) {
        alert('oh hai');
    }
});

I've tried it in Chrome but the event doesn't fire.

Call me crazy but I am writing a Chrome extension and want to push D+E+V keys together to force it into a hidden developer mode.

gplumb
  • 712
  • 6
  • 29
remarsh
  • 658
  • 2
  • 10
  • 17
  • The keyCode can represent only one key. Try to use a combination of keydown + keyup + flags to detect this. – yent May 18 '12 at 15:14
  • possible duplicate of [Can jQuery .keypress() detect more than one key at the same time?](http://stackoverflow.com/questions/4954403/can-jquery-keypress-detect-more-than-one-key-at-the-same-time) – Diodeus - James MacFarlane May 18 '12 at 15:14
  • Consider changing the accepted answer to [this](http://stackoverflow.com/a/35249618/3853934). It presents more modern and general approach. – Michał Perłakowski Feb 26 '16 at 18:07

12 Answers12

77

If you want to detect that the d, e, and v keys were all down at the same time, you have to watch both keydown and keyup and keep a map of the ones that are down. When they're all down, fire your event.

For example: Live copy | source

var map = {68: false, 69: false, 86: false};
$(document).keydown(function(e) {
    if (e.keyCode in map) {
        map[e.keyCode] = true;
        if (map[68] && map[69] && map[86]) {
            // FIRE EVENT
        }
    }
}).keyup(function(e) {
    if (e.keyCode in map) {
        map[e.keyCode] = false;
    }
});

I assume you don't care what order they're pressed down in (as that would be a pain to reliably press) as long as they're all down at the same time at some point.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
21

Similar to Vega's...but simpler

var down = {};
$(document).keydown(function(e) {
    down[e.keyCode] = true;
}).keyup(function(e) {
    if (down[68] && down[69] && down[86]) {
        alert('oh hai');
    }
    down[e.keyCode] = false;
});​
Parth Thakkar
  • 5,427
  • 3
  • 25
  • 34
  • 5
    This is really good and will work well. If you need to match a sequence of the keys, then you may check the order by pushing to an array: Instead of `down[e.keyCode]=true`, say `down.push(e.keyCode)` and validate instead of this: `if(down[68]&&down[69]&&down[86])`, as this: `if(down[0]===68&&down[1]===69&&down[2]===86)`. – lu1s May 18 '12 at 15:38
  • 2
    I created a [fiddle](http://jsfiddle.net/bplumb/B2efC/1/) to complement lu1s comment. – Blake Plumb Feb 08 '13 at 17:36
  • Working like a charm, also thank you @lu1s for the keys order ! :) – Sebastian Manuelli Jul 21 '21 at 18:18
9

Perhaps a simpler key combination would be easier?

How about something like Shift + Alt + D? (You probably shouldn't use the Control key because most browsers already interpret Ctrl+D in one way or another)

The code for this would be something like this:

if(e.shiftKey && e.altKey && e.keyCode == 68)
{
  alert('l33t!');
}
gplumb
  • 712
  • 6
  • 29
  • 1
    that isn't the answer to the question, is it? – Parth Thakkar May 18 '12 at 15:31
  • @ParthThakkar - From the question, you can derive the requirement: "to force it into a hidden developer mode". Being pragmatic, I suggested a simple alternative to acheive the same end result – gplumb May 18 '12 at 15:46
  • all right...that may be the way to go...i just thought that wasn't the answer to the required question, so i just asked that...no offence!) – Parth Thakkar May 18 '12 at 15:48
  • Based on this discussion in Comments @GPlumb, it would probably be a good idea for you to include the remarks about this being an althernative to the considered approach and why... – Cindy Meister Feb 07 '16 at 09:15
6

I have answer from T.J. Crowder in plain javascript for someone who would want to avoid Jquery.

//A W S D simultaneously
var map = {65: false, 87: false, 83: false, 68: false};
document.body.addEventListener('keydown', function (e) {
    var e = e || event; //to deal with old IE
    if (e.keyCode in map) {
        map[e.keyCode] = true;
        if (map[65] && map[87]) {
            console.log('up left');
        }else if (map[83] && map[68]) {
            console.log('down right');
        }else if (map[87] && map[68]) {
            console.log('up right');
        }else if (map[83] && map[65]) {
            console.log('down left');
        }
    }
});
document.body.addEventListener('keyup', function (e) {
    if (e.keyCode in map) {
        map[e.keyCode] = false;
    }
});
Smelino
  • 266
  • 3
  • 4
1

You would need to capture the three key events separately and fire your action only after the third one.

var keys = {
        d: { code: 100, pressed: false, next: 'e' },
        e: { code: 101, pressed: false, next: 'v' },
        v: { code: 118, pressed: false, next: 'd' }
    },
    nextKey = 'd';

$(document).keypress(function(e) {
    if (e.keyCode === keys[nextKey].code) {
        keys[nextKey].pressed = true;
        nextKey = keys[nextKey].next;
    } else {
        keys.d.pressed = false;
        keys.e.pressed = false;
        keys.v.pressed = false;
        nextKey = 'd';
    }

    if (keys.d.pressed && keys.e.pressed && keys.v.pressed) {
        alert('Entering dev mode...');
    }
});​

There's a number of ways to do this of course. This example doesn't require you to hold the keys down simultaneously, just that you type them in order: d e v.

If you used this, you might want to augment it to clear the pressed flags after some time interval.

Here's a working example.


Disclaimer: I realize the original question said that the keys should be "pressed together". This is just an alternative as other answerers have already provided sufficient solutions for the keys being pressed together.

FishBasketGordo
  • 22,904
  • 4
  • 58
  • 91
  • I tested this in Chrome, and it wasn't working with the original key codes. I've ran across this before, but I forget why they're different. – FishBasketGordo May 18 '12 at 15:49
1

I tried the three top answers (as of this post), and none of them worked for me. They didn't reset the keys.

If it took 3 keys fire the script, after firing it once - pressing any one of the 3 keys would fire it again.

I just wrote this script and it's working very well. It uses Shift+S to fire, but you can easily change that. It resets after pressing the combination.

var saveArray = new Array();
saveArray[0] = false;
saveArray[1] = false;

$(document).ready(function(){

    $(document).keydown(function (f){
        if (f.keyCode == 16) {
            saveArray[0] = true;
        }
    });

    $(document).keyup(function (g){
        if(g.which == 16){
            saveArray[0] = false;
        }
    });

    $(document).keydown(function (h){
        if (h.keyCode == 83) {
            saveArray[1] = true;
            if(saveArray[0] == true && saveArray[1] == true){
                saveArray[0] = false;
                saveArray[1] = false;
                keypressSaveFunction();
            }
        }
    });

    $(document).keyup(function (i){
        if (i.which == 83) {
            saveArray[1] = false;
        }
    });
});

    function keypressSaveFunction(){
        alert("You pressed Shift+S");
    }

Fiddle: http://jsfiddle.net/9m8yswwo/13/

Nemo-Omen
  • 117
  • 9
  • This won't work if the user continues to hold the Shift key down and presses S a second time. Forcing `saveArray[0] = false` in the S's keydown event (which makes an assumption that the Shift key was released) is a pretty horrible hack. On the other hand, it may just be the reason this worked for you. – poshest Jan 05 '16 at 12:02
  • Please *don't* use `new Array()`. – Michał Perłakowski Feb 07 '16 at 04:19
1

A bit more modern solution, takes advantage of arrow functions and rest parameters:

const multipleKeypress = (function($document) {
  // Map of keys which are currently down.
  const keymap = {}
  // Update keymap on keydown and keyup events.
  $document.on(
    "keydown keyup"
    // If the key is down, assign true to the corresponding
    // propery of keymap, otherwise assign false.
   ,event => keymap[event.keyCode] = event.type === "keydown"
  )
  // The actual function.
  // Takes listener as the first argument,
  // rest of the arguments are key codes.
  return (listener, ...keys) =>
    $document.keydown(() => {
      // Check if every of the specified keys is down.
      if (keys.every(key => keymap[key]))
        listener(event)
    })
// Pass a jQuery document object to cache it.
}($(document)))

// Example usage:
multipleKeypress(() => console.log("pressed"), 68, 69, 86)

// Automatically focus the snippet result
window.focus()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Try pressing <kbd>d</kbd>, <kbd>e</kbd> and <kbd>v</kbd> at once.</p>
Michał Perłakowski
  • 88,409
  • 26
  • 156
  • 177
0

if I well understood : example fiddle, http://jsfiddle.net/gAtTk/ (look at your js console)

this code will let you enter the word "dev" (and in this example, at the end the event keyup is removed)

(function(seq) {
    var tmp = seq.slice();
    $(document).on("keyup.entersequence", function(e){
        if (!(e.keyCode === tmp.pop())) {
           tmp = seq.slice();
        }
        else {
           console.log(e.keyCode);  
            if (!tmp.length) {
               console.log('end');
               $(document).off("keyup.entersequence");
            }
        }
    });
}([68,69,86].reverse()));
Fabrizio Calderan
  • 120,726
  • 26
  • 164
  • 177
0

You should use the keydown and keyup events, to handle more then one key "at the same time".

input.on("keydown", function (e) {
                        if (e.which == 17) {
                            isCtrl = true; // Ctrl
                            return;
                        }

                        /* Ctrl and "c" */
                        if (isCtrl && e.which == 67) {
                            //some code 
                        }
                    }).keyup(function (e) {
                        if (e.which == 17) {
                            isCtrl = false; // no Ctrl
                        }
                    });
kapsiR
  • 2,720
  • 28
  • 36
0

Use this code to have an event triggered by multiple key presses + Timeout after 100ms to prevent mistypes. In this example : if A,Z,E are pressed within a time period of 100ms, the event will be triggered.

var map = {65:false,90:false,69:false}; //Modify keyCodes here
$(document).keydown(function(e){
    console.log(e.keyCode);
    map[e.keyCode] = e.keyCode in map ? true : map[e.keyCode] || false;
    var result = Object.keys(map).filter(function(key){
        return map[key];
    }).length === Object.keys(map).length ? true : false;
    if(result){
        //Your event here
        Object.keys(map).forEach(function(key){
            map[key] = false;
        });
    }
    setTimeout(function(){
        map[e.keyCode] = false;
    },100);
});
-1

If you care about the order and also need to hold a key and tap another (ex: Shift + DEL, DEL, DEL...), without having to lift up on the first key to get the event to fire again... I've modified @BlakePlumm's [fiddle] comment which extended @lu1s' comment on @ParthThakkar's answer.

Also, using jQuery's .on() allows you to listen for the key sequence only on certain elements. Change 'body' to 'input.selector' or whatever else.

var map = [];
var down = [];
$(document).on('keydown','body', function(e) {
    if(!map[e.which]){
        down.push(e.which);
        if(down[0] === 68 && down[1] === 69 && down[2] === 86) {
            console.log('D + E + V');
        } else if(down[0] === 16 && down[1] === 46) {
            console.log('SHIFT + DEL');
        }
        /* more conditions here */
    }
    map[e.which] = true;
}).keyup(function(e) {
    map[e.which] = false;

    /* important for detecting repeat presses of
       last key while holding first key(s)
       (can be shortened. see fiddle) */
    var len = down.length;
    while (len--) {
        if(down[len] === e.which) down.splice(len,1); //removes only the keyup'd key
    }        
    $('.alert').html('');
});

Additional thoughts: If you only kinda care about the order - that is, the first keys just need to be down, as long as your main event-firing key is pressed last (stuff like CTRL+SHIFT+TAB, TAB, TAB), add this condition:

else if(down.length>2) {
    if($.inArray(68,down)!=-1 && $.inArray(69,down)!=-1 && down[2] === 86) {
        $('.alert').html('A hacky D+E+V was pressed');
    }
}

fiddle with more glorious options and live demo: - http://jsfiddle.net/kstarr/4ftL1p3k/

-1

https://github.com/JesseBuesking/jquery.hotkeys.extended

Check this out. You might be looking for this.

We can trigger a function on multiple key press. eg: p+t+k

 $(document).hotkeys('p', 't', 'k', function (){
        //show blurbox
        $('#popup').blurbox({
            blur: 10, animateBlur: true, bgColor: 'rgba(255,255,0,0.2)'
        })bb.show();
    });

maybe your looking for this.

pTK
  • 659
  • 6
  • 19