จะตรวจสอบได้อย่างไรว่ากดปุ่มหลายครั้งพร้อมกันโดยใช้ JavaScript?


173

ฉันพยายามที่จะพัฒนาเอ็นจิ้นเกม JavaScript และฉันเจอปัญหานี้แล้ว:

  • เมื่อฉันกดSPACEตัวละครกระโดด
  • เมื่อฉันกดตัวละครจะเลื่อนไปทางขวา

ปัญหาคือเมื่อฉันกดขวาแล้วกดเว้นวรรคตัวละครจะกระโดดแล้วหยุดเคลื่อนไหว

ฉันใช้keydownฟังก์ชั่นเพื่อกดปุ่ม ฉันจะตรวจสอบว่ามีการกดหลายปุ่มพร้อมกันได้อย่างไร


3
นี่คือตัวอย่างของหน้าเว็บที่พิมพ์รายการของปุ่มทั้งหมดที่กดไว้โดยอัตโนมัติ: stackoverflow.com/a/13651016/975097
Anderson Green

คำตอบ:


327

หมายเหตุ: ขณะนี้ keyCode เลิกใช้แล้ว

การตรวจจับการกดแป้นหลายครั้งเป็นเรื่องง่ายถ้าคุณเข้าใจแนวคิด

วิธีที่ฉันทำมันเป็นเช่นนี้:

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 */
}

รหัสนี้ง่ายมาก: เนื่องจากคอมพิวเตอร์ส่งผ่านการกดแป้นพิมพ์ครั้งละครั้งเท่านั้นอาร์เรย์จึงถูกสร้างขึ้นเพื่อติดตามปุ่มหลาย ๆ ปุ่ม อาเรย์นั้นสามารถใช้เพื่อตรวจสอบหนึ่งคีย์ขึ้นไปในครั้งเดียว

เพียงเพื่ออธิบายสมมติว่าคุณกดAและBแต่ละยิงkeydownเหตุการณ์ที่ชุดmap[e.keyCode]ค่าของe.type == keydownซึ่งประเมินทั้งจริงหรือเท็จ ตอนนี้ทั้งสองmap[65]และมีการกำหนดให้map[66] trueเมื่อคุณปล่อยให้ไปของAการkeyupเกิดเพลิงไหม้เหตุการณ์ที่ก่อให้เกิดตรรกะเดียวกันเพื่อตรวจสอบผลตรงข้ามสำหรับmap[65](A) ซึ่งขณะนี้เป็นเท็จแต่เนื่องจากmap[66](B) ยังคงเป็น "ลง" (มันยังไม่ได้เรียกเหตุการณ์ keyup ก) มันยังคงเป็นจริงเป็นความจริง

mapอาร์เรย์ผ่านเหตุการณ์ทั้งสองมีลักษณะเช่นนี้

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

มีสองสิ่งที่คุณสามารถทำได้ในตอนนี้:

A) Key logger ( ตัวอย่าง ) สามารถสร้างเป็นข้อมูลอ้างอิงได้ในภายหลังเมื่อคุณต้องการหารหัสคีย์อย่างน้อยหนึ่งรหัส สมมติว่าคุณได้กำหนดองค์ประกอบ HTML elementและชี้ไปที่มันมีตัวแปร

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

หมายเหตุ: คุณสามารถคว้าองค์ประกอบด้วยidแอตทริบิวต์ได้อย่างง่ายดาย

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

สิ่งนี้จะสร้างองค์ประกอบ html ที่สามารถอ้างอิงได้ง่ายใน javascript ด้วย element

alert(element); // [Object HTMLDivElement]

คุณไม่จำเป็นต้องใช้document.getElementById()หรือ$()คว้ามัน แต่เพื่อประโยชน์ในการใช้งานร่วมกันได้แนะนำให้ใช้ jQuery $()มากกว่า

เพียงตรวจสอบให้แน่ใจว่าแท็กสคริปต์มาตามเนื้อความของ HTML เคล็ดลับการเพิ่มประสิทธิภาพ : ส่วนใหญ่เว็บไซต์ขนาดใหญ่ชื่อใส่แท็กสคริปต์ที่หลังแท็ก body เพื่อเพิ่มประสิทธิภาพ นี่เป็นเพราะแท็กสคริปต์บล็อกองค์ประกอบเพิ่มเติมจากการโหลดจนกว่าสคริปต์จะเสร็จสิ้นการดาวน์โหลด การวางไว้ข้างหน้าของเนื้อหาทำให้สามารถโหลดเนื้อหาได้ล่วงหน้า

B (ซึ่งเป็นที่ที่คุณสนใจ)คุณสามารถตรวจสอบหนึ่งหรือมากกว่าหนึ่งคีย์ในเวลาที่/*insert conditional here*/เป็นตัวอย่าง:

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');
}

แก้ไข : นั่นไม่ใช่ตัวอย่างที่อ่านได้มากที่สุด การอ่านเป็นสิ่งสำคัญดังนั้นคุณสามารถลองทำสิ่งนี้เพื่อทำให้ง่ายต่อสายตา:

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;
}

การใช้งาน:

test_keys(13, 16, 65)
test_keys('ctrl', 'shift', 'A')
test_key(65)
test_key('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');
    }
}

(สิ้นสุดการแก้ไข)


นี้การตรวจสอบตัวอย่างสำหรับCtrlShiftA, CtrlShiftBและCtrlShiftC

มันง่ายเหมือนที่ :)

หมายเหตุ

การติดตาม KeyCodes

โดยทั่วไปแล้วเป็นวิธีปฏิบัติที่ดีในการจัดทำรหัสเอกสารโดยเฉพาะสิ่งต่าง ๆ เช่นรหัสคีย์ (เช่น // CTRL+ENTER) เพื่อให้คุณสามารถจดจำสิ่งที่พวกเขาเป็น

คุณควรใส่รหัสที่สำคัญในลำดับเดียวกันกับเอกสาร ( CTRL+ENTER => map[17] && map[13]ไม่ใช่map[13] && map[17]) วิธีนี้คุณจะไม่สับสนเมื่อคุณต้องการย้อนกลับและแก้ไขรหัส

gotcha พร้อมโซ่ if-else

หากตรวจสอบคอมโบที่มีจำนวนแตกต่างกัน (เช่นCtrlShiftAltEnterและCtrlEnter) ให้วางคอมโบที่เล็กกว่าหลังคอมโบที่ใหญ่กว่ามิฉะนั้นคอมโบที่เล็กกว่าจะเข้ามาแทนที่คอมโบที่ใหญ่กว่าถ้ามันมีคอมโบเหมือนกัน ตัวอย่าง:

// 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: "คำสั่งผสมคีย์นี้ยังคงเปิดใช้งานแม้ว่าฉันจะไม่ได้กดปุ่ม"

เมื่อจัดการกับการแจ้งเตือนหรือสิ่งใดก็ตามที่โฟกัสจากหน้าต่างหลักคุณอาจต้องการรวมmap = []การรีเซ็ตอาร์เรย์หลังจากทำตามเงื่อนไข นี่เป็นเพราะบางสิ่งเช่นalert()ดึงโฟกัสออกไปจากหน้าต่างหลักและทำให้เหตุการณ์ 'การกดปุ่ม' ไม่ทำงาน ตัวอย่างเช่น:

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: ค่าเริ่มต้นของเบราว์เซอร์

นี่คือสิ่งที่น่ารำคาญที่ฉันพบโดยมีวิธีแก้ปัญหารวมอยู่:

ปัญหา: เนื่องจากเบราว์เซอร์มักจะมีการกระทำเริ่มต้นในคีย์คอมโบ (เช่นCtrlDเปิดใช้งานหน้าต่างบุ๊กมาร์กหรือCtrlShiftCเปิดใช้งาน skynote เมื่อ maxthon) คุณอาจต้องการเพิ่มreturn falseหลังจากmap = []ดังนั้นผู้ใช้เว็บไซต์ของคุณจะไม่ผิดหวังเมื่อ "ซ้ำไฟล์" ฟังก์ชั่นที่ถูกใส่CtrlDบุ๊คมาร์คหน้าแทน

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

หากไม่มีreturn falseหน้าต่างบุ๊กมาร์กจะปรากฏขึ้นเพื่อทำให้ผู้ใช้ผิดหวัง

คำสั่งการส่งคืน (ใหม่)

ตกลงดังนั้นคุณไม่ต้องการออกจากฟังก์ชั่น ณ เวลานั้นเสมอไป นั่นเป็นเหตุผลที่event.preventDefault()ฟังก์ชั่นอยู่ที่นั่น สิ่งที่ตั้งค่าการตั้งค่าสถานะภายในที่บอกให้ล่ามไม่อนุญาตให้เบราว์เซอร์เรียกใช้การกระทำเริ่มต้น หลังจากนั้นการทำงานของฟังก์ชันจะดำเนินต่อไป (ในขณะที่returnจะออกจากฟังก์ชันทันที)

ทำความเข้าใจความแตกต่างนี้ก่อนตัดสินใจใช้return falseหรือe.preventDefault()

event.keyCode เลิกใช้แล้ว

ผู้ใช้SeanVieiraชี้ให้เห็นในความคิดเห็นที่event.keyCodeเลิกใช้แล้ว

ที่นั่นเขาได้ให้ทางเลือกที่ดี: event.keyซึ่งผลตอบแทนเป็นตัวแทนสตริงของคีย์ถูกกดเช่น"a"สำหรับAหรือสำหรับ"Shift"Shift

ฉันไปข้างหน้าและทำเครื่องมือสำหรับการตรวจสอบสตริงดังกล่าว

element.onevent VS element.addEventListener

ตัวจัดการที่ลงทะเบียนด้วยaddEventListenerสามารถซ้อนกันและถูกเรียกตามลำดับการลงทะเบียนในขณะที่การตั้งค่า.oneventโดยตรงค่อนข้างก้าวร้าวและแทนที่สิ่งที่คุณเคยมี

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
});

.oneventคุณสมบัติดูเหมือนว่าจะแทนที่ทุกอย่างและลักษณะการทำงานของev.preventDefault()และreturn false;สามารถค่อนข้างคาดเดาไม่ได้

ในกรณีใดก็ตามตัวจัดการที่ลงทะเบียนผ่านaddEventlistenerดูเหมือนจะง่ายต่อการเขียนและเหตุผลเกี่ยวกับ

นอกจากนี้ยังมีattachEvent("onevent", callback)จากการใช้งานที่ไม่ได้มาตรฐานของ Internet Explorer แต่สิ่งนี้เกินกว่าที่จะปฏิเสธและไม่เกี่ยวข้องกับ JavaScript (เกี่ยวข้องกับภาษาลึกลับที่เรียกว่าJScript ) มันจะเป็นประโยชน์สูงสุดของคุณเพื่อหลีกเลี่ยงรหัส polyglot ให้มากที่สุด

ชั้นผู้ช่วย

เพื่อจัดการกับความสับสน / ข้อร้องเรียนฉันได้เขียน "คลาส" ที่ทำสิ่งนี้เป็นนามธรรม ( ลิงก์ 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();
}

คลาสนี้ไม่ได้ทำทุกอย่างและมันจะไม่จัดการกับทุกกรณีที่นึกออก ฉันไม่ใช่คนห้องสมุด แต่สำหรับการใช้งานแบบอินเตอร์แอคทีฟทั่วไปควรจะใช้ได้

หากต้องการใช้คลาสนี้ให้สร้างอินสแตนซ์และชี้ไปที่องค์ประกอบที่คุณต้องการเชื่อมโยงคีย์บอร์ดเข้าด้วย:

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

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

สิ่งนี้จะทำคือการแนบฟังป้อนข้อมูลใหม่ให้กับองค์ประกอบที่มี#txt(สมมติว่ามันเป็น textarea) และตั้ง watchpoint Ctrl+5สำหรับคำสั่งผสมที่สำคัญ เมื่อทั้งคู่Ctrlและ5ลงฟังก์ชันการโทรกลับที่คุณส่งผ่าน (ในกรณีนี้"FIVE "จะมีการเรียกฟังก์ชันที่เพิ่มเข้าไปใน textarea) การโทรกลับเชื่อมโยงกับชื่อprint_5ดังนั้นในการลบคุณเพียงใช้:

input_txt.unwatch("print_5");

ในการแยกออกinput_txtจากtxtองค์ประกอบ:

input_txt.detach();

ด้วยวิธีนี้การรวบรวมขยะสามารถเลือกวัตถุ ( input_txt) ควรโยนทิ้งไปและคุณจะไม่มีผู้ฟังเหตุการณ์ซอมบี้ตัวเก่าเหลืออยู่

เพื่อความทั่วถึงนี่คือการอ้างอิงอย่างรวดเร็วเกี่ยวกับ API ของคลาสที่นำเสนอในสไตล์ C / Java เพื่อให้คุณรู้ว่าพวกเขากลับมาและสิ่งที่พวกเขาคาดหวัง

Boolean  key_down (String key);

ผลตอบแทนtrueถ้าkeyมันเป็นเท็จเป็นอย่างอื่น

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

ส่งคืนtrueถ้าคีย์ทั้งหมดไม่key1 .. keyNถูกต้องเป็นเท็จมิฉะนั้น

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

สร้าง "watchpoint" ซึ่งการกดทั้งหมดkeyNจะทำให้เกิดการติดต่อกลับ

void     unwatch (String name);

นำ watchpoint ออกจากชื่อของมัน

void     clear (void);

เช็ดแคช "keys down" เทียบเท่ากับmap = {}ข้างบน

void     detach (void);

แยกส่วนev_kdownและev_kupผู้ฟังจากองค์ประกอบหลักทำให้สามารถกำจัดอินสแตนซ์ได้อย่างปลอดภัย

ปรับปรุง 2017/12/02ในการตอบสนองต่อการร้องขอในการเผยแพร่นี้เพื่อ GitHub ผมได้สร้างส่วนสำคัญ

อัปเดต 2018-07-21ฉันเคยเล่นกับการเขียนโปรแกรมสไตล์ที่เปิดเผยมาระยะหนึ่งแล้วและตอนนี้วิธีนี้กลายเป็นรายการโปรดส่วนตัวของฉัน: fiddle , pastebin

โดยทั่วไปแล้วมันจะทำงานกับกรณีที่คุณต้องการแนบเนียน (ctrl, alt, shift) แต่ถ้าคุณต้องการตีพูดa+wในเวลาเดียวกันมันจะไม่ยากเกินไปที่จะ "รวม" แนวทางเข้าสู่ หลายคีย์ค้นหา


ฉันหวังว่านี้คำตอบที่อธิบายอย่างละเอียดมินิบล็อกมีประโยชน์ :)


ฉันเพิ่งปรับปรุงคำตอบนี้ให้ใหญ่! ตัวอย่าง keylogger มีความเชื่อมโยงกันมากขึ้นฉันอัปเดตการจัดรูปแบบเพื่อให้ส่วน "บันทึกย่อ" อ่านง่ายขึ้นและฉันได้เพิ่มบันทึกย่อใหม่เกี่ยวกับreturn falsevspreventDefault()
Braden Best

สิ่งที่เกี่ยวกับเมื่อคุณกดปุ่มที่มีเอกสารอยู่ในโฟกัสแล้วคุณคลิกที่กล่อง URL จากนั้นคุณปล่อยกุญแจ การกดคีย์ไม่เคยถูกไล่ออก แต่คีย์นั้นทำงานอยู่ทำให้รายการไม่ถูกต้อง นอกจากนี้ในทางกลับกัน: การกดปุ่ม / กดค้างไว้ในกล่อง URL การกดคีย์ไม่เคยถูกไล่ออกจากนั้นวางโฟกัสบนเอกสารและสถานะการเลื่อนลงไม่ได้อยู่ในรายการ โดยทั่วไปเมื่อใดก็ตามที่เอกสารกลับมาโฟกัสคุณจะไม่สามารถมั่นใจได้ว่าสถานะสำคัญ
user3015682

3
หมายเหตุ: keyCodeเลิกใช้แล้ว - หากคุณเปลี่ยนไปใช้keyคุณจะได้รับการแสดงอักขระที่แท้จริงของคีย์ซึ่งอาจดี
Sean Vieira

1
@SeanVieira จากนั้นอีกครั้งคุณสามารถทำสิ่งที่แปลกประหลาดใน C เช่นกัน ตัวอย่างเช่นคุณก็รู้ว่าmyString[5]เป็นเช่นเดียวกับ5[myString]และมันจะไม่ได้ให้คุณคำเตือนรวบรวม (แม้จะมี-Wall -pedantic)? มันเป็นเพราะpointer[offset]สัญกรณ์ใช้เวลาตัวชี้เพิ่มชดเชยแล้ว dereferences ผลทำให้เป็นเช่นเดียวกับmyString[5] *(myString + 5)
Braden ที่ดีที่สุด

1
@inorganik คุณหมายถึงคลาสผู้ช่วยหรือไม่ ส่วนสำคัญสามารถใช้เป็น repos ได้หรือไม่? มันจะน่าเบื่อที่จะทำธุรกรรมซื้อคืนทั้งหมดสำหรับโค้ดขนาดเล็ก แน่นอนฉันจะทำส่วนสำคัญ ฉันจะยิงคืนนี้ เวลาเที่ยงคืนของภูเขา - ออก
Braden ดีที่สุดใน

30

คุณควรใช้เหตุการณ์keydownเพื่อติดตามการกดแป้นและคุณควรใช้เหตุการณ์keyupเพื่อติดตามเวลาที่ปล่อยปุ่ม

ดูตัวอย่างนี้: http://jsfiddle.net/vor0nwe/mkHsU/

(ปรับปรุง: ฉันทำซ้ำรหัสที่นี่ในกรณี jsfiddle.net bails :) HTML:

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

... และ Javascript (โดยใช้ 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');
});

ในตัวอย่างนั้นฉันกำลังใช้อาร์เรย์เพื่อติดตามการกดแป้นต่างๆ ในแอปพลิเคชันจริงคุณอาจต้องการให้deleteแต่ละองค์ประกอบเมื่อคีย์ที่เกี่ยวข้องของพวกเขาได้รับการเผยแพร่

โปรดทราบว่าในขณะที่ฉันใช้ jQuery เพื่อทำให้สิ่งต่าง ๆ เป็นเรื่องง่ายสำหรับฉันในตัวอย่างนี้แนวคิดทำงานได้ดีเช่นกันเมื่อทำงานใน 'ดิบ' Javascript


แต่อย่างที่ฉันคิดว่ามีข้อผิดพลาด หากคุณกดปุ่มเดียวค้างไว้ให้สลับไปยังแท็บอื่น (หรือโฟกัสที่หลวม) ในขณะที่ยังกดปุ่มค้างไว้เมื่อคุณปรับโฟกัสบนหน้าจอจะแสดงว่าปุ่มนั้นถูกกดแม้ว่าจะไม่ได้เป็นก็ตาม : D
XCS

3
@Cristy: จากนั้นคุณสามารถเพิ่มonblurตัวจัดการเหตุการณ์ซึ่งจะลบคีย์ที่กดทั้งหมดออกจากอาร์เรย์ เมื่อคุณสูญเสียโฟกัสไปแล้วคุณจะต้องกดปุ่มทั้งหมดอีกครั้ง แต่น่าเสียดายที่ไม่มีเทียบเท่า JS GetKeyboardStateไป
Martijn

1
มีปัญหากับการวางบน Mac (Chrome) มันได้รับ keydown 91 (คำสั่ง), keydown 86 (v), แต่จากนั้นเพียงกดคีย์ 91, ทิ้ง 86 ลง รายการของคีย์: ขึ้น: 91, ลง: 86 นี่ดูเหมือนจะเกิดขึ้นเมื่อปล่อยคีย์คำสั่งที่สอง - ถ้าฉันปล่อยมันไปก่อนมันจะลงทะเบียนคีย์อัพอย่างถูกต้องทั้งคู่
James Alday

2
ปรากฏว่าเมื่อคุณกดปุ่มสามปุ่มขึ้นไปในครั้งเดียวมันจะหยุดตรวจจับปุ่มใด ๆ เพิ่มเติมจนกว่าคุณจะยกขึ้นหนึ่งปุ่ม (ทดสอบกับ Firefox 22)
Qvcool

1
@JamesAlday ปัญหาเดียวกัน ดูเหมือนว่าจะมีผลกับคีย์ Meta (OS) บน Mac เท่านั้น ดูปัญหา # 3 ที่นี่: bitspushedaround.com/…
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
นี่คือทั้งหมดที่ฉันต้องการคำตอบที่ดีที่สุด
Randall Coding

7

ฉันใช้วิธีนี้ (ต้องตรวจสอบทุกที่กด 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

สำหรับผู้ที่ต้องการรหัสตัวอย่างที่สมบูรณ์ ขวา + ซ้ายเพิ่ม

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

ทำให้การเลื่อนลงแม้แต่การเรียกใช้หลาย ๆ ฟังก์ชั่นโดยที่แต่ละฟังก์ชั่นตรวจสอบหาคีย์เฉพาะและตอบสนองอย่างเหมาะสม

document.keydown = function (key) {

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

2

ฉันพยายามเพิ่มการจัดการเมื่อkeypress Event keydownเช่น:

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) ;
}

นี่มีไว้เพื่อแสดงรูปแบบเท่านั้น ฉันจะไม่เข้าไปดูรายละเอียดได้ที่นี่ (โดยเฉพาะอย่างยิ่งไม่ได้ลงในเบราว์เซอร์ที่เฉพาะเจาะจง level2 + Eventลงทะเบียน)

โพสต์กลับโปรดว่าสิ่งนี้ช่วยได้หรือไม่


1
สิ่งนี้จะไม่ทำงาน: การกดปุ่มไม่ทำงานกับปุ่มจำนวนมากที่การกดแป้นและการกดแป้นจะทริกเกอร์ นอกจากนี้เบราว์เซอร์บางตัวเท่านั้นที่ไม่สามารถเรียกใช้เหตุการณ์คีย์ดาวน์ได้
Martijn

quirksmode กล่าวผิดของคุณ: quirksmode.org/dom/events/keys.html แต่ฉันจะไม่เถียงว่าตั้งแต่ฉันไม่ได้ทดสอบข้อเสนอของฉัน
FK82

ที่ยกมาจากหน้าว่า"เมื่อผู้ใช้กดปุ่มพิเศษเช่นปุ่มลูกศร, เบราว์เซอร์ไม่ควรเหตุการณ์กดปุ่ม" สำหรับการทำซ้ำมันจะแสดงรายการ Opera และ Konqueror ว่าไม่ถูกต้อง
Martijn

2

หากกดปุ่มใดปุ่มหนึ่งเป็น Alt / Crtl / Shift คุณสามารถใช้วิธีนี้:

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;
            }
        });

    });

ขอบคุณสำหรับการสนับสนุนของคุณ โปรดอย่าเพิ่งโพสต์รหัสเพิ่มคำอธิบาย
ทิม Rutter

2

นี่ไม่ใช่วิธีสากล แต่ก็มีประโยชน์ในบางกรณี มันมีประโยชน์สำหรับชุดค่าผสมเช่นCTRL+ somethingหรือShift+ somethingหรือCTRL+ Shift+ somethingฯลฯ

ตัวอย่าง: เมื่อคุณต้องการพิมพ์หน้าโดยใช้CTRL+ Pปุ่มแรกจะถูกกดCTRLตามด้วยPเสมอ เหมือนกันกับCTRL+ S, CTRL+ Uและชุดค่าผสมอื่น ๆ

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;

ไม่ใช่วิธีที่ดีที่สุดที่ฉันรู้


-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);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.