Làm cách nào để phát hiện nếu nhiều phím được nhấn cùng một lúc bằng JavaScript?


173

Tôi đang cố gắng phát triển một công cụ trò chơi JavaScript và tôi đã gặp phải vấn đề này:

  • Khi tôi nhấn SPACE nhân vật nhảy.
  • Khi tôi nhấn nhân vật di chuyển sang phải.

Vấn đề là khi tôi nhấn phải và sau đó nhấn phím cách, nhân vật sẽ nhảy và sau đó dừng di chuyển.

Tôi sử dụng keydownchức năng để lấy phím bấm. Làm cách nào để kiểm tra xem có nhiều phím được nhấn cùng lúc không?


3
Đây là bản demo của một trang web tự động in danh sách tất cả các phím được nhấn: stackoverflow.com/a/13651016/975097
Anderson Green

Câu trả lời:


327

Lưu ý: keyCode hiện không được dùng nữa.

Phát hiện nhiều tổ hợp phím là dễ dàng nếu bạn hiểu khái niệm

Cách tôi làm là như thế này:

var map = {}; // You could also use an array
onkeydown = onkeyup = function(e){
    e = e || event; // to deal with IE
    map[e.keyCode] = e.type == 'keydown';
    /* insert conditional here */
}

Mã này rất đơn giản: Vì máy tính chỉ truyền một lần nhấn phím cùng một lúc, một mảng được tạo để theo dõi nhiều phím. Mảng sau đó có thể được sử dụng để kiểm tra một hoặc nhiều khóa cùng một lúc.

Để giải thích, giả sử bạn nhấn AB, mỗi lần kích hoạt một keydownsự kiện đặt map[e.keyCode]giá trị của e.type == keydown, đánh giá là đúng hoặc sai . Bây giờ cả hai map[65]map[66]được thiết lập để true. Khi bạn buông tay A, keyupsự kiện sẽ kích hoạt, khiến logic tương tự xác định kết quả ngược lại cho map[65](A), hiện là sai , nhưng vì map[66](B) vẫn "xuống" (nó không kích hoạt sự kiện keyup), nó vẫn đúng .

Các mapmảng, thông qua cả hai sự kiện, trông như thế này:

// keydown A 
// keydown B
[
    65:true,
    66:true
]
// keyup A
// keydown B
[
    65:false,
    66:true
]

Có hai điều bạn có thể làm bây giờ:

A) Trình ghi nhật ký khóa ( ví dụ ) có thể được tạo làm tài liệu tham khảo cho lần sau khi bạn muốn nhanh chóng tìm ra một hoặc nhiều mã khóa. Giả sử bạn đã xác định một phần tử html và chỉ nó với biến element.

element.innerHTML = '';
var i, l = map.length;
for(i = 0; i < l; i ++){
    if(map[i]){
        element.innerHTML += '<hr>' + i;
    }
}

Lưu ý: Bạn có thể dễ dàng lấy một phần tử theo idthuộc tính của nó .

<div id="element"></div>

Điều này tạo ra một yếu tố html có thể dễ dàng được tham chiếu trong javascript với element

alert(element); // [Object HTMLDivElement]

Bạn thậm chí không phải sử dụng document.getElementById()hoặc $()để lấy nó. Nhưng vì mục đích tương thích, hãy sử dụng jQuery$() được sử dụng rộng rãi hơn.

Chỉ cần đảm bảo thẻ script xuất hiện sau phần thân của HTML. Mẹo tối ưu hóa : Hầu hết các trang web tên tuổi đặt thẻ script sau thẻ body để tối ưu hóa. Điều này là do thẻ script chặn các phần tử tiếp theo tải cho đến khi tập lệnh của nó được tải xuống xong. Đặt nó trước nội dung cho phép nội dung tải trước.

B (đó là nơi bạn quan tâm) Bạn có thể kiểm tra một hoặc nhiều khóa tại thời điểm đó /*insert conditional here*/, lấy ví dụ này:

if(map[17] && map[16] && map[65]){ // CTRL+SHIFT+A
    alert('Control Shift A');
}else if(map[17] && map[16] && map[66]){ // CTRL+SHIFT+B
    alert('Control Shift B');
}else if(map[17] && map[16] && map[67]){ // CTRL+SHIFT+C
    alert('Control Shift C');
}

Chỉnh sửa : Đó không phải là đoạn dễ đọc nhất. Khả năng đọc là quan trọng, vì vậy bạn có thể thử một cái gì đó như thế này để dễ nhìn hơn:

function test_key(selkey){
    var alias = {
        "ctrl":  17,
        "shift": 16,
        "A":     65,
        /* ... */
    };

    return key[selkey] || key[alias[selkey]];
}

function test_keys(){
    var keylist = arguments;

    for(var i = 0; i < keylist.length; i++)
        if(!test_key(keylist[i]))
            return false;

    return true;
}

Sử dụng:

test_keys(13, 16, 65)
test_keys('ctrl', 'shift', 'A')
test_key(65)
test_key('A')

Tốt hơn chưa?

if(test_keys('ctrl', 'shift')){
    if(test_key('A')){
        alert('Control Shift A');
    } else if(test_key('B')){
        alert('Control Shift B');
    } else if(test_key('C')){
        alert('Control Shift C');
    }
}

(kết thúc chỉnh sửa)


Ví dụ này kiểm tra cho CtrlShiftA, CtrlShiftBCtrlShiftC

Nó chỉ đơn giản như vậy :)

Ghi chú

Theo dõi mã khóa

Theo nguyên tắc chung, nên sử dụng mã tài liệu, đặc biệt là những thứ như Mã khóa (như // CTRL+ENTER) để bạn có thể nhớ chúng là gì.

Bạn cũng nên đặt các mã khóa theo thứ tự giống như tài liệu ( CTRL+ENTER => map[17] && map[13], KHÔNG map[13] && map[17]). Bằng cách này, bạn sẽ không bao giờ bị nhầm lẫn khi bạn cần quay lại và chỉnh sửa mã.

Một gotcha với chuỗi if-other

Nếu kiểm tra các combo có số lượng khác nhau (như CtrlShiftAltEnterCtrlEnter), hãy đặt các combo nhỏ hơn sau các combo lớn hơn, nếu không, các combo nhỏ hơn sẽ ghi đè lên các combo lớn hơn nếu chúng đủ tương tự. Thí dụ:

// Correct:
if(map[17] && map[16] && map[13]){ // CTRL+SHIFT+ENTER
    alert('Whoa, mr. power user');
}else if(map[17] && map[13]){ // CTRL+ENTER
    alert('You found me');
}else if(map[13]){ // ENTER
    alert('You pressed Enter. You win the prize!')
}

// Incorrect:
if(map[17] && map[13]){ // CTRL+ENTER
    alert('You found me');
}else if(map[17] && map[16] && map[13]){ // CTRL+SHIFT+ENTER
    alert('Whoa, mr. power user');
}else if(map[13]){ // ENTER
    alert('You pressed Enter. You win the prize!');
}
// What will go wrong: When trying to do CTRL+SHIFT+ENTER, it will
// detect CTRL+ENTER first, and override CTRL+SHIFT+ENTER.
// Removing the else's is not a proper solution, either
// as it will cause it to alert BOTH "Mr. Power user" AND "You Found Me"

Gotcha: "Combo phím này tiếp tục kích hoạt mặc dù tôi không nhấn phím"

Khi xử lý các cảnh báo hoặc bất cứ điều gì lấy nét từ cửa sổ chính, bạn có thể muốn đưa map = []vào để đặt lại mảng sau khi điều kiện được thực hiện. Điều này là do một số thứ, như alert(), lấy tiêu điểm ra khỏi cửa sổ chính và khiến sự kiện 'keyup' không kích hoạt. Ví dụ:

if(map[17] && map[13]){ // CTRL+ENTER
    alert('Oh noes, a bug!');
}
// When you Press any key after executing this, it will alert again, even though you 
// are clearly NOT pressing CTRL+ENTER
// The fix would look like this:

if(map[17] && map[13]){ // CTRL+ENTER
    alert('Take that, bug!');
    map = {};
}
// The bug no longer happens since the array is cleared

Gotcha: Mặc định của trình duyệt

Đây là một điều khó chịu tôi tìm thấy, với giải pháp bao gồm:

Sự cố: Vì trình duyệt thường có các hành động mặc định trên các tổ hợp phím (như CtrlDkích hoạt cửa sổ dấu trang hoặc CtrlShiftCkích hoạt skynote trên maxthon), nên bạn cũng có thể muốn thêm return falsesau map = [], vì vậy người dùng trang web của bạn sẽ không cảm thấy thất vọng khi "Tệp trùng lặp" chức năng, được đưa vào CtrlD, đánh dấu trang thay thế.

if(map[17] && map[68]){ // CTRL+D
    alert('The bookmark window didn\'t pop up!');
    map = {};
    return false;
}

Nếu không return false, cửa sổ Bookmark sẽ bật lên, làm mất tinh thần của người dùng.

Tuyên bố trả lại (mới)

Được rồi, vì vậy bạn không luôn muốn thoát khỏi chức năng tại thời điểm đó. Đó là lý do tại sao event.preventDefault()chức năng là ở đó. Những gì nó làm là đặt một cờ nội bộ thông báo cho trình thông dịch không cho phép trình duyệt chạy hành động mặc định của nó. Sau đó, việc thực thi chức năng tiếp tục (trong khi đó returnsẽ ngay lập tức thoát khỏi chức năng).

Hiểu sự khác biệt này trước khi bạn quyết định sử dụng return falsehaye.preventDefault()

event.keyCode không được chấp nhận

Người dùng SeanVieira đã chỉ ra trong các ý kiến ​​không event.keyCodeđược tán thành.

Ở đó, ông đã đưa ra một giải pháp thay thế tuyệt vời : event.key, trả về một chuỗi đại diện của phím được nhấn, như "a"cho Ahoặc "Shift"choShift .

Tôi đã đi trước và nấu một công cụ để kiểm tra các chuỗi nói.

element.onevent đấu với element.addEventListener

Trình xử lý đã đăng ký có addEventListenerthể được xếp chồng lên nhau và được gọi theo thứ tự đăng ký, trong khi cài đặt .oneventtrực tiếp khá tích cực và ghi đè bất cứ thứ gì bạn có trước đây.

document.body.onkeydown = function(ev){
    // do some stuff
    ev.preventDefault(); // cancels default actions
    return false; // cancels this function as well as default actions
}

document.body.addEventListener("keydown", function(ev){
    // do some stuff
    ev.preventDefault() // cancels default actions
    return false; // cancels this function only
});

Tài .oneventsản dường như ghi đè lên tất cả mọi thứ và hành vi của ev.preventDefault()return false;có thể khá khó đoán.

Trong cả hai trường hợp, trình xử lý được đăng ký thông qua addEventlistenerdường như dễ viết hơn và lý do về.

Ngoài ra còn có attachEvent("onevent", callback)từ triển khai phi tiêu chuẩn của Internet Explorer, nhưng điều này vượt quá sự phản đối và thậm chí không liên quan đến JavaScript (nó liên quan đến một ngôn ngữ bí truyền gọi là JScript ). Bạn nên tránh mã polyglot càng nhiều càng tốt.

Một lớp người trợ giúp

Để giải quyết sự nhầm lẫn / khiếu nại, tôi đã viết một "lớp" thực hiện việc trừu tượng hóa này ( liên kết pastebin ):

function Input(el){
    var parent = el,
        map = {},
        intervals = {};
    
    function ev_kdown(ev)
    {
        map[ev.key] = true;
        ev.preventDefault();
        return;
    }
    
    function ev_kup(ev)
    {
        map[ev.key] = false;
        ev.preventDefault();
        return;
    }
    
    function key_down(key)
    {
        return map[key];
    }

    function keys_down_array(array)
    {
        for(var i = 0; i < array.length; i++)
            if(!key_down(array[i]))
                return false;

        return true;
    }
    
    function keys_down_arguments()
    {
        return keys_down_array(Array.from(arguments));
    }
    
    function clear()
    {
        map = {};
    }
    
    function watch_loop(keylist, callback)
    {
        return function(){
            if(keys_down_array(keylist))
                callback();
        }
    }

    function watch(name, callback)
    {
        var keylist = Array.from(arguments).splice(2);

        intervals[name] = setInterval(watch_loop(keylist, callback), 1000/24);
    }

    function unwatch(name)
    {
        clearInterval(intervals[name]);
        delete intervals[name];
    }

    function detach()
    {
        parent.removeEventListener("keydown", ev_kdown);
        parent.removeEventListener("keyup", ev_kup);
    }
    
    function attach()
    {
        parent.addEventListener("keydown", ev_kdown);
        parent.addEventListener("keyup", ev_kup);
    }
    
    function Input()
    {
        attach();

        return {
            key_down: key_down,
            keys_down: keys_down_arguments,
            watch: watch,
            unwatch: unwatch,
            clear: clear,
            detach: detach
        };
    }
    
    return Input();
}

Lớp này không làm mọi thứ và nó sẽ không xử lý mọi trường hợp sử dụng có thể hiểu được. Tôi không phải là một người thư viện. Nhưng để sử dụng tương tác chung thì nó sẽ ổn.

Để sử dụng lớp này, hãy tạo một thể hiện và trỏ nó đến thành phần bạn muốn liên kết đầu vào bàn phím với:

var input_txt = Input(document.getElementById("txt"));

input_txt.watch("print_5", function(){
    txt.value += "FIVE ";
}, "Control", "5");

Những gì điều này sẽ làm là gắn một trình nghe đầu vào mới vào phần tử với #txt(giả sử đó là một vùng văn bản) và đặt một điểm theo dõi cho tổ hợp phím Ctrl+5. Khi cả hai Ctrl5không hoạt động, chức năng gọi lại mà bạn đã truyền vào (trong trường hợp này, một chức năng thêm "FIVE "vào vùng văn bản) sẽ được gọi. Cuộc gọi lại được liên kết với tên print_5, vì vậy để loại bỏ nó, bạn chỉ cần sử dụng:

input_txt.unwatch("print_5");

Để tách input_txtkhỏi txtphần tử:

input_txt.detach();

Bằng cách này, bộ sưu tập rác có thể nhặt đối tượng ( input_txt), nếu nó bị vứt đi và bạn sẽ không còn người nghe sự kiện zombie cũ.

Để tìm hiểu kỹ, đây là một tài liệu tham khảo nhanh về API của lớp, được trình bày theo kiểu C / Java để bạn biết họ trả về cái gì và những đối số họ mong đợi.

Boolean  key_down (String key);

Trả về truenếu keylà xuống, sai khác.

Boolean  keys_down (String key1, String key2, ...);

Trả về truenếu tất cả các phím key1 .. keyNbị hỏng, sai khác.

void     watch (String name, Function callback, String key1, String key2, ...);

Tạo một "điểm quan sát" sao cho nhấn tất cả keyNsẽ kích hoạt cuộc gọi lại

void     unwatch (String name);

Loại bỏ quan điểm cho biết thông qua tên của nó

void     clear (void);

Xóa bộ nhớ cache "phím xuống". Tương đương như map = {}trên

void     detach (void);

Tách người nghe ev_kdownev_kupngười nghe khỏi phần tử cha, giúp có thể thoát khỏi trường hợp một cách an toàn

Cập nhật 2017-12-02 Đáp lại yêu cầu xuất bản này lên github, tôi đã tạo ra một ý chính .

Cập nhật 2018-07-21 Tôi đã chơi với lập trình kiểu khai báo một thời gian và cách này hiện là sở thích cá nhân của tôi: fiddle , pastebin

Nói chung, nó sẽ hoạt động với các trường hợp bạn thực sự muốn (ctrl, alt, shift), nhưng nếu bạn cần nhấn, a+wđồng thời, sẽ không quá khó để "kết hợp" các cách tiếp cận vào một tra cứu đa khóa.


Tôi hy vọng câu trả lời này được giải thích cặn kẽ mini-blog là hữu ích :)


Tôi vừa thực hiện một bản cập nhật lớn cho câu trả lời này! Ví dụ về keylogger mạch lạc hơn, tôi đã cập nhật định dạng để phần "ghi chú" sẽ dễ đọc hơn và tôi đã thêm một ghi chú mới về return falsevspreventDefault()
Braden Best

Thế còn khi bạn nhấn / giữ một phím với tài liệu được lấy nét, sau đó bạn nhấp vào hộp URL, sau đó bạn buông phím. keyup không bao giờ được kích hoạt, nhưng khóa vẫn hoạt động, khiến danh sách không chính xác. Ngoài ra, ngược lại: nhấn / giữ phím trong hộp URL, phím tắt không bao giờ được kích hoạt, sau đó tập trung vào tài liệu và trạng thái phím tắt không có trong danh sách. Về cơ bản bất cứ khi nào tài liệu lấy lại trọng tâm, bạn không bao giờ có thể chắc chắn về trạng thái khóa.
user3015682

3
NB: keyCodekhông được dùng nữa - nếu bạn chuyển sang keythì bạn sẽ có được biểu diễn ký tự thực tế của khóa có thể tốt.
Sean Vieira

1
@SeanVieira Sau đó, một lần nữa, bạn cũng có thể làm một số thứ lạ trong C. Ví dụ, bạn có biết điều đó myString[5]giống như 5[myString]và thậm chí nó sẽ không đưa ra cảnh báo biên dịch (ngay cả với -Wall -pedantic) không? Đó là bởi vì pointer[offset]ký hiệu lấy con trỏ, thêm phần bù và sau đó hủy kết quả, làm cho myString[5]giống như *(myString + 5).
Braden hay nhất vào

1
@inorganik bạn đang đề cập đến lớp người trợ giúp? Gist có thể được sử dụng như repos? Sẽ thật tẻ nhạt khi tạo ra một repo toàn bộ cho một đoạn mã nhỏ. Chắc chắn, tôi sẽ làm một ý chính. Tôi sẽ quay cho tối nay. Núi nửa đêm Time -ish
Braden hay nhất

30

Bạn nên sử dụng KeyDown sự kiện để theo dõi các phím bấm, bạn nên sử dụng KeyUp sự kiện để theo dõi khi các phím được phát hành.

Xem ví dụ này: http://jsfiddle.net/vor0nwe/mkHsU/

(Cập nhật: Tôi đang sao chép mã ở đây, trong trường hợp jsfiddle.net bảo lãnh :) HTML:

<ul id="log">
    <li>List of keys:</li>
</ul>

... và Javascript (sử dụng jQuery):

var log = $('#log')[0],
    pressedKeys = [];

$(document.body).keydown(function (evt) {
    var li = pressedKeys[evt.keyCode];
    if (!li) {
        li = log.appendChild(document.createElement('li'));
        pressedKeys[evt.keyCode] = li;
    }
    $(li).text('Down: ' + evt.keyCode);
    $(li).removeClass('key-up');
});

$(document.body).keyup(function (evt) {
    var li = pressedKeys[evt.keyCode];
    if (!li) {
       li = log.appendChild(document.createElement('li'));
    }
    $(li).text('Up: ' + evt.keyCode);
    $(li).addClass('key-up');
});

Trong ví dụ đó, tôi đang sử dụng một mảng để theo dõi những phím nào đang được nhấn. Trong một ứng dụng thực tế, bạn có thể muốndelete từng phần tử một khi khóa liên kết của chúng được phát hành.

Lưu ý rằng mặc dù tôi đã sử dụng jQuery để làm cho mọi thứ trở nên dễ dàng với bản thân mình trong ví dụ này, khái niệm này cũng hoạt động tốt khi làm việc trong Javascript 'thô'.


Nhưng như tôi đã nghĩ có một lỗi. Nếu bạn tiếp tục nhấn một nút, sau đó chuyển sang một tab khác (hoặc lấy nét lỏng) trong khi vẫn giữ nút khi bạn tập trung vào scrit, nó sẽ cho thấy nút đó được nhấn ngay cả khi không. : D
XCS

3
@Cristy: sau đó bạn cũng có thể thêm một onblurtrình xử lý sự kiện, loại bỏ tất cả các phím được nhấn khỏi mảng. Khi bạn đã mất tiêu điểm, sẽ rất hợp lý khi phải nhấn lại tất cả các phím. Thật không may, không có JS tương đương GetKeyboardState.
Martijn

1
Gặp sự cố với Dán trên máy Mac (Chrome). Nó thành công nhận được keydown 91 (lệnh), keydown 86 (v), nhưng sau đó chỉ keyup 91, bỏ 86 xuống. Danh sách các khóa: Lên: 91, Xuống: 86. Điều này dường như chỉ xảy ra khi buông phím lệnh thứ hai - nếu tôi buông nó trước thì nó sẽ đăng ký chính xác khóa trên cả hai.
James Alday

2
Có vẻ như khi bạn nhấn ba hoặc nhiều phím cùng một lúc, nó sẽ ngừng phát hiện thêm bất kỳ phím nào cho đến khi bạn nhấc một phím. (Đã thử nghiệm với Firefox 22)
Qvcool

1
@JamesAlday Vấn đề tương tự. Nó dường như chỉ ảnh hưởng đến khóa Meta (OS) trên máy Mac. Xem vấn đề # 3 tại đây: bitspushedaround.com/ từ
Don McCurdy

20
document.onkeydown = keydown; 

function keydown (evt) { 

    if (!evt) evt = event; 

    if (evt.ctrlKey && evt.altKey && evt.keyCode === 115) {

        alert("CTRL+ALT+F4"); 

    } else if (evt.shiftKey && evt.keyCode === 9) { 

        alert("Shift+TAB");

    } 

}

1
Đây là tất cả những gì tôi muốn, câu trả lời hay nhất
Randall Coding

7

Tôi đã sử dụng cách này (phải kiểm tra bất cứ nơi nào nhấn Shift + Ctrl):

// create some object to save all pressed keys
var keys = {
    shift: false,
    ctrl: false
};

$(document.body).keydown(function(event) {
// save status of the button 'pressed' == 'true'
    if (event.keyCode == 16) {
        keys["shift"] = true;
    } else if (event.keyCode == 17) {
        keys["ctrl"] = true;
    }
    if (keys["shift"] && keys["ctrl"]) {
        $("#convert").trigger("click"); // or do anything else
    }
});

$(document.body).keyup(function(event) {
    // reset status of the button 'released' == 'false'
    if (event.keyCode == 16) {
        keys["shift"] = false;
    } else if (event.keyCode == 17) {
        keys["ctrl"] = false;
    }
});

5

cho những ai cần mã ví dụ đầy đủ. Phải + Thêm trái

var keyPressed = {};
document.addEventListener('keydown', function(e) {

   keyPressed[e.key + e.location] = true;

    if(keyPressed.Shift1 == true && keyPressed.Control1 == true){
        // Left shift+CONTROL pressed!
        keyPressed = {}; // reset key map
    }
    if(keyPressed.Shift2 == true && keyPressed.Control2 == true){
        // Right shift+CONTROL pressed!
        keyPressed = {};
    }

}, false);

document.addEventListener('keyup', function(e) {
   keyPressed[e.key + e.location] = false;

   keyPressed = {};
}, false);

3

Làm cho phím tắt thậm chí gọi nhiều chức năng, với mỗi chức năng kiểm tra một khóa cụ thể và trả lời thích hợp.

document.keydown = function (key) {

    checkKey("x");
    checkKey("y");
};

2

Tôi sẽ thử thêm một keypress Eventtrình xử lý keydown. Ví dụ:

window.onkeydown = function() {
    // evaluate key and call respective handler
    window.onkeypress = function() {
       // evaluate key and call respective handler
    }
}

window.onkeyup = function() {
    window.onkeypress = void(0) ;
}

Điều này chỉ có nghĩa là để minh họa một mô hình; Tôi sẽ không đi vào chi tiết ở đây (đặc biệt là không Eventđăng ký trình duyệt cấp 2 + cụ thể ).

Gửi lại xin vui lòng cho dù điều này giúp hay không.


1
Điều này sẽ không làm việc: bấm phím không kích hoạt trên rất nhiều phím mà KeyDown và KeyUp làm cò. Ngoài ra, không phải tất cả các trình duyệt liên tục kích hoạt các sự kiện keydown.
Martijn

Quirksmode nói sai của bạn: quirksmode.org/dom/events/keys.html . Nhưng tôi sẽ không tranh luận rằng vì tôi đã không kiểm tra đề xuất của mình.
FK82

Trích dẫn từ trang đó: "Khi người dùng nhấn các phím đặc biệt như phím mũi tên, trình duyệt KHÔNG được kích hoạt các sự kiện nhấn phím" . Về phần lặp lại, nó liệt kê Opera và Konqueror là không làm điều đó một cách chính xác.
Martijn

2

Nếu một trong các phím được nhấn là Alt / Crtl / Shift, bạn có thể sử dụng phương pháp này:

document.body.addEventListener('keydown', keysDown(actions) );

function actions() {
   // do stuff here
}

// simultaneous pressing Alt + R
function keysDown (cb) {
  return function (zEvent) {
    if (zEvent.altKey &&  zEvent.code === "KeyR" ) {
      return cb()
    }
  }
}

2
    $(document).ready(function () {
        // using ascii 17 for ctrl, 18 for alt and 83 for "S"
        // ctr+alt+S
        var map = { 17: false, 18: false, 83: false };
        $(document).keyup(function (e) {
            if (e.keyCode in map) {
                map[e.keyCode] = true;
                if (map[17] && map[18] && map[83]) {
                    // Write your own code here, what  you want to do
                    map[17] = false;
                    map[18] = false;
                    map[83] = false;
                }
            }
            else {
                // if u press any other key apart from that "map" will reset.
                map[17] = false;
                map[18] = false;
                map[83] = false;
            }
        });

    });

Cảm ơn sự đóng góp của bạn. xin vui lòng cố gắng không chỉ gửi mã, thêm một số giải thích.
Tim Rutter

2

Đây không phải là một phương pháp phổ quát, nhưng nó hữu ích trong một số trường hợp. Nó hữu ích cho các kết hợp như CTRL+ somethinghoặc Shift+ somethinghoặc CTRL+ Shift+ something, v.v.

Ví dụ: Khi bạn muốn in một trang bằng CTRL+ P, phím đầu tiên được nhấn luôn được CTRLtheo sau P. Tương tự với CTRL+ S, CTRL+ Uvà các kết hợp khác.

document.addEventListener('keydown',function(e){
      
    //SHIFT + something
    if(e.shiftKey){
        switch(e.code){

            case 'KeyS':
                console.log('Shift + S');
                break;

        }
    }

    //CTRL + SHIFT + something
    if(e.ctrlKey && e.shiftKey){
        switch(e.code){

            case 'KeyS':
                console.log('CTRL + Shift + S');
                break;

        }
    }

});


1
case 65: //A
jp = 1;
setTimeout("jp = 0;", 100);

if(pj > 0) {
ABFunction();
pj = 0;
}
break;

case 66: //B
pj = 1;
setTimeout("pj = 0;", 100);

if(jp > 0) {
ABFunction();
jp = 0;
}
break;

Không phải là cách tốt nhất, tôi biết.


-1
Easiest, and most Effective Method

//check key press
    function loop(){
        //>>key<< can be any string representing a letter eg: "a", "b", "ctrl",
        if(map[*key*]==true){
         //do something
        }
        //multiple keys
        if(map["x"]==true&&map["ctrl"]==true){
         console.log("x, and ctrl are being held down together")
        }
    }

//>>>variable which will hold all key information<<
    var map={}

//Key Event Listeners
    window.addEventListener("keydown", btnd, true);
    window.addEventListener("keyup", btnu, true);

    //Handle button down
      function btnd(e) {
      map[e.key] = true;
      }

    //Handle Button up
      function btnu(e) {
      map[e.key] = false;
      }

//>>>If you want to see the state of every Key on the Keybaord<<<
    setInterval(() => {
                for (var x in map) {
                    log += "|" + x + "=" + map[x];
                }
                console.log(log);
                log = "";
            }, 300);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.