ตรวจสอบว่าคีย์ไม่ทำงานหรือไม่?


94

มีวิธีตรวจสอบว่าคีย์ลงใน JavaScript หรือไม่?

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

ป.ล. ปัญหาที่ใหญ่ที่สุดดูเหมือนว่าหลังจากผ่านไประยะหนึ่งคีย์จะเริ่มทำงานซ้ำทำให้เกิดเหตุการณ์คีย์ดาวน์และคีย์อัพเหมือนปีศาจ หวังว่าจะมีฟังก์ชั่น isKeyDown (คีย์) ง่ายๆ แต่ถ้าไม่เช่นนั้นปัญหานี้จะต้องได้รับการแก้ไข / แก้ไข


6
ปัญหาที่พบบ่อยเกี่ยวกับคำตอบที่ฉันเห็นคือถ้าคุณกดปุ่มค้างไว้จากนั้นเปลี่ยนแท็บหรือเปลี่ยนโฟกัสปล่อยให้คีย์ขึ้นแล้วสลับกลับรหัสจะเชื่อว่าคีย์จะลงจนกว่าคุณจะกดอีกครั้งหรือย้าย วางเมาส์เหนือหน้า :-(
Eric Mickelsen

คำตอบ:


74

มีวิธีตรวจสอบว่าคีย์ลงใน JavaScript หรือไม่?

ไม่ ความเป็นไปได้เพียงอย่างเดียวคือการตรวจสอบแต่ละkeyupและkeydownและการจดจำ

หลังจากผ่านไประยะหนึ่งคีย์จะเริ่มทำซ้ำโดยจะเริ่มการทำงานของคีย์ดาวน์และคีย์อัพเหมือนปีศาจ

มันไม่ควร คุณจะต้องkeypressทำซ้ำอย่างแน่นอนและในหลาย ๆ เบราว์เซอร์คุณจะได้รับการทำซ้ำkeydownแต่ถ้าkeyupทำซ้ำจะเป็นข้อบกพร่อง

น่าเสียดายที่มันไม่ใช่ข้อผิดพลาดที่ไม่เคยมีมาก่อน: บน Linux, Chromium และ Firefox (เมื่อทำงานภายใต้ GTK + ซึ่งอยู่ใน distros ยอดนิยมเช่น Ubuntu) ทั้งคู่สร้างลำดับการกดคีย์อัพ - การกด - คีย์ดาวน์ซ้ำสำหรับคีย์ที่เก็บไว้ ซึ่งเป็นไปไม่ได้ที่จะแยกความแตกต่างจากคนที่ตอกกุญแจเร็วมาก


14
คุณชายเป็นสุภาพบุรุษและเป็นนักวิชาการ Chromium และ Firefox บน Ubuntu เป็นสภาพแวดล้อมการพัฒนาหลักของฉันดังนั้นจึงอธิบายปัญหาที่ฉันพบได้อย่างถูกต้อง หวังว่ามันจะดีขึ้นมิฉะนั้นโซลูชันแฮ็คตัวจับเวลาอาจเป็นวิธีแก้ปัญหาเพียงอย่างเดียว
Daniel X Moore

3
ใช่มันน่าผิดหวังที่ไม่มีความคืบหน้าในเรื่องนี้ ดูbugs.launchpad.net/ubuntu/+bug/369880 ฉันกำลังเขียนเกมบนเบราว์เซอร์และวิธีแก้ปัญหาของฉันในขณะนี้คือการยึดติดกับปุ่มตัวปรับแต่ง (shift, ctrl ฯลฯ ) ซึ่งจะไม่ทำซ้ำเลย
Bobince

2
ไม่เป็นไปได้ที่จะแยกความแตกต่างจากการกดแป้นซ้ำของแท้โดยขาดkeyupเหตุการณ์ที่สอดคล้องกัน
mako

4
ยังคงเป็นเช่นนี้อีก 8 ปีต่อมา? คำตอบนี้อาจต้องได้รับการอัปเดต
Marco Lavagnino

3
ความช่วยเหลือในการแยกวิเคราะห์: (Linux && (Chromium || (Firefox && GTK +)))
bobince

134

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

window.onmousemove = function (e) {
  if (!e) e = window.event;
  if (e.shiftKey) {/*shift is down*/}
  if (e.altKey) {/*alt is down*/}
  if (e.ctrlKey) {/*ctrl is down*/}
  if (e.metaKey) {/*cmd is down*/}
}

นี้มีอยู่ในทุกเบราว์เซอร์ที่สร้างวัตถุเหตุการณ์เช่นจากkeydown, keyupและkeypressดังนั้นคุณจึงไม่จำเป็นต้องใช้ mousemove

ฉันพยายามสร้างวัตถุเหตุการณ์ของตัวเองกับdocument.createEvent('KeyboardEvent')และdocument.createEvent('KeyboardEvent')และกำลังมองหาe.shiftKeyและเช่น แต่ฉันไม่มีโชค

ฉันใช้ Chrome 17 บน Mac


ฉันใช้สิ่งนี้ทั้งในเบราว์เซอร์ใหม่และเก่าแม้แต่ HTA's
Jakob Sternberg

1
มีวิธีนำคำตอบนี้ไปใช้เมื่อมีจำนวนไม่เพียงพอหรือไม่ ฉันได้ลองใช้ if (e.keyCode == 49) {console.log ("1 is down");} แต่ไม่ได้ผล :(
Roberto Sepúlveda Bravo

ดูเหมือนจะตอบคำถามคุณในคำตอบถัดไป ;)
Mark Odey

จริงๆแล้วคุณไม่ควรมองหา e.shiftKey ในการกดปุ่มหากคุณหมายถึง Shift ใช้ e.shiftKey บนเช่น onclick แทน
maciek

46

วิธีแก้ปัญหาของฉัน:

var pressedKeys = {};
window.onkeyup = function(e) { pressedKeys[e.keyCode] = false; }
window.onkeydown = function(e) { pressedKeys[e.keyCode] = true; }

ตอนนี้ฉันสามารถตรวจสอบว่ามีการกดปุ่มใดที่อื่นในสคริปต์หรือไม่โดยการตรวจสอบ

pressedKeys["code of the key"]

ถ้าเป็นจริงให้กดปุ่ม


2
เนื่องจากคีย์เป็นฟังก์ชันอยู่แล้วชื่อตัวแปรอื่นอาจดีกว่า
Raven

1
วิธีนี้จะใช้ไม่ได้ในการตรวจจับว่าปุ่ม Alt ไม่ทำงานหรือไม่ในทุกกรณี
Michael

1
เหมาะอย่างยิ่งสำหรับการตรวจจับขึ้น / ลง / ซ้าย / ขวา
Jonathan Spiller

11

ฉันไม่เชื่อว่าจะมีฟังก์ชัน isKeyDown แต่คุณสามารถเขียนของคุณเองได้

โดยทั่วไปให้สร้างอาร์เรย์ที่มีความยาวเท่ากับจำนวนคีย์ที่คุณต้องการมอนิเตอร์ จากนั้นใช้เอกสาร / หน้า / ควบคุม keyUp และเหตุการณ์ keyDown อัปเดตอาร์เรย์ด้วยสถานะของคีย์นั้น

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

var keyEnum = { W_Key:0, A_Key:1, S_Key:2, D_Key:3 };
var keyArray = new Array(4);

function onKeyDown()
{
    // Detect which key was pressed
    if( key == 'w' )
        keyArray[keyEnum.W_Key] = true;
    // Repeat for each key you care about...
}

function onKeyUp()
{
    // Detect which key was released
    if( key == 'w' )
        keyArray[keyEnum.W_Key] = false;
    // Repeat for each key you care about...
}

function isKeyDown(key)
{
    return keyArray[key];
}

นั่นควรจะบรรลุสิ่งที่คุณต้องการ


1
นี่เป็นสิ่งที่ดีและเป็นส่วนหนึ่งของการแก้ปัญหา แต่ก็ไม่ได้แก้ไขข้อผิดพลาดที่เกิดซ้ำของคีย์อัพที่ฉันพบ ดูคำตอบของ Bobince
Daniel X Moore

5
นี่ไม่ใช่วิธีแก้ปัญหาที่ดีเพราะคุณจะต้องเขียน ifs มากขึ้นเรื่อย ๆ "keyList = {};" การเป็นวัตถุยอมรับ "keyList [key] = true;" โดยไม่ต้องใช้ enum หรือ จำกัด เนื่องจากใช้ดัชนีสตริง / คุณสมบัติและใช้ได้กับทุกคีย์
SparK

วิธีนี้ใช้งานได้ แต่ใช้งานมาก
เกินไป

6

ลงเอยที่นี่เพื่อตรวจสอบว่ามีบางอย่างในเบราว์เซอร์อยู่แล้วหรือไม่ แต่ดูเหมือนว่าไม่มี นี่คือวิธีแก้ปัญหาของฉัน (คล้ายกับคำตอบของโรเบิร์ตมาก):

"use strict";

const is_key_down = (() => {
    const state = {};

    window.addEventListener('keyup', (e) => state[e.key] = false);
    window.addEventListener('keydown', (e) => state[e.key] = true);

    return (key) => state.hasOwnProperty(key) && state[key] || false;
})();

จากนั้นคุณสามารถตรวจสอบว่ามีการกดปุ่มด้วยis_key_down('ArrowLeft')หรือไม่


1

คนอื่นเคยถามคำถามประเภทนี้มาก่อน (แม้ว่าตอนนี้ฉันจะไม่เห็นสิ่งที่ผิดปกติใด ๆ ที่ชัดเจน)

ฉันคิดว่าคำตอบคือkeydownเหตุการณ์ (และคู่แฝดkeyup) เป็นข้อมูลทั้งหมดที่คุณได้รับ การทำซ้ำมีการต่อสายเข้ากับระบบปฏิบัติการอย่างแน่นหนาและโปรแกรมแอปพลิเคชันไม่ได้รับโอกาสมากนักในการสืบค้น BIOS สำหรับสถานะที่แท้จริงของคีย์

สิ่งที่คุณทำได้และอาจต้องทำหากต้องการให้มันทำงานได้คือการยกเลิกการตีกลับคีย์โดยทางโปรแกรม โดยพื้นฐานแล้วคุณสามารถประเมินkeydownและkeyupตัวเองได้ แต่เพิกเฉยต่อkeyupเหตุการณ์หากเกิดขึ้นเร็วเกินไปหลังจากช่วงสุดท้ายkeydown... หรือโดยพื้นฐานแล้วคุณควรชะลอการตอบสนองให้keyupนานพอที่จะแน่ใจว่าไม่มีkeydownเหตุการณ์อื่นตามมาด้วยเช่น 0.25 วินาทีของkeyup.

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


2
ฉันกังวลว่ามันอาจจะมาถึงนี้
Daniel X Moore

1
/*
Tracks what keys are currently down on the keyboard
*/

function keyboard_module(onUpdate){
    var kb = {};
    var unicode_mapping = {};
    document.onkeydown = function(e){
        var unicode=e.charCode? e.charCode : e.keyCode
        var key = getKey(unicode);
        kb[key] = true;
        if(onUpdate){
            onUpdate(kb);
        }
    }

    document.onkeyup = function(e){
        var unicode=e.charCode? e.charCode : e.keyCode
        var key = getKey(unicode);
        delete kb[key];
        if(onUpdate){
            onUpdate(kb);
        }
    }

    function getKey(unicode){
        if(unicode_mapping[unicode]){
            var key = unicode_mapping[unicode];
        }else{
            var key= unicode_mapping[unicode] = String.fromCharCode(unicode);
        }
        return key;
    }
    return kb;
}

function testing(kb){
    console.log('These are the down keys', kb);
}


var keyboard = keyboard_module(testing);

....
//somewhere else in the code
if(keyboard['K']){/*do something special */}

ไม่แน่ใจว่า String.fromCharCode (unicode); เป็นการค้นหาที่รวดเร็วหรือไม่นั่นคือเหตุผลที่ฉันมีวัตถุ unicode_mapping นี่อาจเป็นสิ่งที่ต้องดึงออกมาเพื่อตัดทอนโค้ดนี้ลงเล็กน้อยหากเร็วมาก เนื่องจากสิ่งนี้จะถูกเรียกซ้ำ ๆ สำหรับการดาวน์คีย์ความเร็วจึงมีความสำคัญดังนั้นทำไมฉันจึงเพิ่มการแมปในแง่ร้าย
RobKohr

1

รหัสต่อไปนี้คือสิ่งที่ฉันใช้:

var altKeyDownCount = 0;
window.onkeydown = function (e) {
    if (!e) e = window.event;
    if (e.altKey) {
        altKeyDownCount++;
        if (30 < altKeyDownCount) {
            $('.key').removeClass('hidden');
            altKeyDownCount = 0;
        }
        return false;
    }
}

window.onkeyup = function (e) {
    if (!e) e = window.event;
    altKeyDownCount = 0;
    $('.key').addClass('hidden');
}

เมื่อผู้ใช้กดปุ่ม Alt ค้างไว้สักพัก (ประมาณ 2 วินาที) กลุ่มของป้ายกำกับ (class = 'key hidden') จะปรากฏขึ้น เมื่อปล่อยปุ่ม Alt ป้ายกำกับจะหายไป ใช้ jQuery และ Bootstrap


และจะเกิดอะไรขึ้นหากกด "Tab" ในขณะที่ Alt ไม่ทำงาน
Michael

1

ฉันรู้ว่านี่เป็นคำถามที่เก่ามาก แต่มีไลบรารี JavaScript (~ .5Kb) ที่มีน้ำหนักเบามากซึ่ง "แก้ไข" อย่างมีประสิทธิภาพในการทำงานของตัวจัดการเหตุการณ์แป้นพิมพ์ที่ไม่สอดคล้องกันเมื่อใช้ DOM API

ห้องสมุดเป็นKeydrown

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

kd.P.down(function () {
  console.log('The "P" key is being held down!');
});

kd.P.up(function () {
  console.clear();
});

// This update loop is the heartbeat of Keydrown
kd.run(function () {
  kd.tick();
});

ฉันได้รวม Keydrown ไว้ใน JavaScript ฝั่งไคลเอ็นต์ของฉันเพื่อหยุดภาพเคลื่อนไหวที่เหมาะสมในเกม Red Light Green Light ที่ฉันกำลังเขียน คุณสามารถดูเกมทั้งหมดที่นี่ (หมายเหตุ: หากคุณกำลังอ่านสิ่งนี้ในอนาคตเกมควรเป็นรหัสที่สมบูรณ์และเล่นได้ :-D!)

ฉันหวังว่านี่จะช่วยได้.


1

ฉันได้สแกนคำตอบข้างต้นแล้วข้อเสนอkeydown/ keyupแนวทางใช้ได้เฉพาะในสถานการณ์พิเศษเท่านั้น หากผู้ใช้อยู่ห่างจากแท็บหรือใช้ท่าทางสัมผัสเพื่อเปิดหน้าต่างเบราว์เซอร์หรือแท็บใหม่keydownจะมีการลงทะเบียนซึ่งเป็นเรื่องปกติเพราะ ณ จุดนั้นมันเป็นไปไม่ได้ที่จะบอกว่าคีย์เป็นสิ่งที่เว็บแอปกำลังตรวจสอบอยู่หรือไม่ หรือเป็นเบราว์เซอร์มาตรฐานหรือทางลัดของระบบปฏิบัติการ กลับมาที่หน้าเบราว์เซอร์ก็จะยังคงคิดว่าคีย์นั้นค้างอยู่แม้ว่าจะเปิดตัวในระหว่างนี้ หรือคีย์บางปุ่มจะถูกเก็บไว้ในขณะที่ผู้ใช้เปลี่ยนไปใช้แท็บหรือแอปพลิเคชันอื่นด้วยเมาส์จากนั้นจึงปล่อยออกนอกหน้าของเรา

ปุ่มตัวปรับแต่ง ( Shiftฯลฯ ) สามารถตรวจสอบได้ผ่านทางmousemoveฯลฯ โดยสมมติว่าคาดว่าจะมีการโต้ตอบของเมาส์อย่างน้อยหนึ่งครั้งเมื่อแท็บย้อนกลับซึ่งมักจะเป็นเช่นนั้น

สำหรับส่วนปุ่มอื่น ๆ (ยกเว้นการปรับเปลี่ยน, Tab, Deleteแต่รวมSpace, Enter), การตรวจสอบkeypressจะทำงานสำหรับการใช้งานมากที่สุด - ปุ่มขึ้นลงจะยังคงเกิดไฟไหม้ แม้ว่าจะมีความล่าช้าในการรีเซ็ตคีย์เนื่องจากระยะเวลาในkeypressการเริ่มทำงาน โดยทั่วไปหากkeypressไม่ทำการยิงต่อไปก็เป็นไปได้ที่จะแยกแยะคีย์ส่วนใหญ่ นี้รวมกับการปรับเปลี่ยนเป็นสุญญากาศสวย แต่ฉันยังไม่ได้สำรวจสิ่งที่จะทำอย่างไรกับและTabBackspace

ฉันแน่ใจว่ามีห้องสมุดอยู่ที่นั่นซึ่งเป็นนามธรรมเกี่ยวกับจุดอ่อนของ DOM นี้หรืออาจมีการเปลี่ยนแปลงมาตรฐาน DOM บางอย่างที่ดูแลมันเนื่องจากเป็นคำถามที่ค่อนข้างเก่า


ขณะนี้เลิกใช้งานการกดแป้นพิมพ์แล้ว ดูเหมือนว่าจะไม่ทำงานเลยบน Chrome
eadsjr

0

ดูที่นี้คำตอบและการใช้งานและonkeyup นี่คือข้อมูลเฉพาะเพิ่มเติมเกี่ยวกับเหตุการณ์เหล่านั้นonkeydown


1
ลิงก์ที่คุณอ้างถึงมีไว้สำหรับเหตุการณ์ของเมาส์โดยที่การทำซ้ำอัตโนมัติไม่ใช่ปัญหา
Carl Smotricz

คีย์ขึ้นและคีย์ลงจะไม่ทำซ้ำ อาจกดแป้น
Claudiu

แม้ว่าพวกเขาจะเป็นเช่นนั้นฉันก็จินตนาการถึงบางอย่างเช่นโซลูชันของ TJMonk15 เพียงแค่ไม่ต้องการเขียนมัน
Claudiu

1
ข้อความในสองคำถามนั้นเหมือนกันทุกประการ เรื่องบังเอิญแปลก ๆ หรืออะไรมากกว่านั้น?
Mitch Lindgren

2
@ มิทช์: ว้าว ... เหลือเชื่อมาก ฉันไม่รู้ว่าทำไมใครบางคนถึงสร้างสองบัญชีเพื่อถามคำถามเดียวกัน หรือมีแนวโน้มว่าบุคคลนี้จะคัดลอกคำถามอื่นและดัดแปลงเป็นคีย์
Claudiu

0

ใช้งานได้ใน Firefox และ Chrome

ฉันจำเป็นต้องเปิดไฟล์ html พิเศษในเครื่อง (โดยการกดEnterเมื่อไฟล์ถูกเลือกใน file explorer ใน Windows) ไม่ว่าจะเพื่อดูไฟล์หรือแก้ไขในโปรแกรมแก้ไขออนไลน์พิเศษ

ดังนั้นผมจึงอยากจะเห็นความแตกต่างระหว่างทั้งสองตัวเลือกโดยถือลงCtrl-key Enterหรือไม่ในขณะที่กด

อย่างที่คุณเข้าใจจากคำตอบทั้งหมดที่นี่ดูเหมือนว่าจะไม่สามารถทำได้จริง ๆ แต่นี่เป็นวิธีที่เลียนแบบพฤติกรรมนี้ในแบบที่ฉันยอมรับได้

วิธีการทำงานเป็นดังนี้:

หากคุณกดปุ่มCtrl-key ค้างไว้เมื่อเปิดไฟล์เหตุการณ์คีย์ดาวน์จะไม่เริ่มทำงานในโค้ดจาวาสคริปต์ แต่เหตุการณ์Ctrlคีย์อัพจะเริ่มทำงาน (เมื่อคุณปล่อยคีย์ในที่สุด) รหัสจับสิ่งนั้น

นอกจากนี้โค้ดยังปิดการทำงานของคีย์ (ทั้งคีย์อัพและคีย์ดาวน์) ทันทีที่เกิดขึ้น ดังนั้นหากคุณกดCtrl-key หลังจากเปิดไฟล์แล้วจะไม่มีอะไรเกิดขึ้น

window.onkeyup = up;
window.onkeydown = down;
function up(e) {
  if (e.key === 'F5') return; // if you want this to work also on reload with F5.

  window.onkeyup = null;
  window.onkeyup = null;
  if (e.key === 'Control') {
    alert('Control key was released. You must have held it down while opening the file, so we will now load the file into the editor.');
  }         
}
function down() {
  window.onkeyup = null;
  window.onkeyup = null;
}

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