【问题标题】:Check if a key is down?检查一个键是否已关闭?
【发布时间】:2010-12-22 03:58:54
【问题描述】:

有没有办法检测一个键当前是否在 JavaScript 中被关闭?

我知道“keydown”事件,但这不是我需要的。按键被按下后的一段时间,我希望能够检测它是否仍然被按下。

P。 S. 最大的问题似乎是在一段时间后键开始重复,像恶魔一样触发 keydown 和 keyup 事件。希望只有一个简单的 isKeyDown(key) 函数,但如果没有,则需要克服/解决这个问题。

【问题讨论】:

  • 我在这里看到的答案的一个常见问题是,如果你按住一个键,然后更改选项卡或更改焦点,让键向上,然后再切换回来,代码会认为键是直到您再次按下它或将鼠标移到页面上。 :-(
  • 这能回答你的问题吗? JavaScript: Check if mouse button down?

标签: javascript input keyboard


【解决方案1】:

其他人以前也问过这种问题(尽管我现在没有看到任何明显的骗局)。

我认为答案是keydown 事件(以及它的孪生keyup)是您获得的所有信息。重复与操作系统紧密相连,应用程序没有太多机会向 BIOS 查询密钥的实际状态。

你可以做的,如果你需要让它工作,也许必须做的是,以编程方式去弹键。本质上,您可以自己评估keydownkeyup,但如果keyupevent 在最后一个keydown 之后发生得太快,则忽略它...或者本质上,您应该延迟对keyup 的响应足够长确保在 keyup 的 0.25 秒之后没有另一个 keydown 事件。

这将涉及使用计时器活动,并记录以前事件的毫秒时间。我不能说这是一个非常吸引人的解决方案,但是......

【讨论】:

  • 我担心会变成这样。
【解决方案2】:

我不相信有类似 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];
}

这应该可以完成你想要的。

【讨论】:

  • 这很好,确实是解决方案的一部分,但它没有解决我遇到的 keyup 重复错误。请参阅 bobince 的回答。
  • 这不是一个好的解决方案,因为您会编写越来越多的 if。一个“keyList = {};”作为一个对象接受“keyList[key] = true;”不需要枚举或限制,因为它使用字符串索引/属性并适用于所有键。
【解决方案3】:

有没有办法检测一个键当前是否在 JavaScript 中被关闭?

不。唯一的可能是监控每个keyupkeydown 并记住。

一段时间后,按键开始重复,像恶魔一样触发 keydown 和 keyup 事件。

不应该。你肯定会得到重复的keypress,并且在许多浏览器中你也会得到重复的keydown,但如果重复keyup,这是一个错误。

不幸的是,这并不是一个完全闻所未闻的错误:在 Linux、Chromium 和 Firefox 上(当它在 GTK+ 下运行时,它在流行的发行版中,如 Ubuntu)都生成重复的 keyup-keypress-keydown 序列握着钥匙,这与快速敲击钥匙的人无法区分。

【讨论】:

  • 您先生是一位绅士和一位学者。 Ubuntu 上的 Chromium 和 Firefox 是我的主要开发环境,因此准确地解释了我所看到的问题。希望它会变得更好,否则计时器黑客解决方案可能是唯一的解决方法。
  • 是的,令人沮丧的是,这方面没有进展。见bugs.launchpad.net/ubuntu/+bug/369880。我正在编写一个浏览器游戏,我目前的解决方法是坚持使用完全不重复的修饰键(shift、ctrl 等)。
  • 不,可以通过缺少相应的keyup 事件将它们与真正的重复按键区分开来。
  • 8年后还是这样吗?此答案可能需要更新。
  • 解析帮助:(Linux && (Chromium || (Firefox && GTK+)))
【解决方案4】:

除了使用 keyupkeydown 侦听器来跟踪键何时按下和备份之外, 实际上还有一些属性可以告诉您某些键是否按下。

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

这适用于所有浏览器生成的事件对象,例如来自 keydownkeyupkeypress 的事件对象,因此您不必使用 mousemove。

我尝试使用document.createEvent('KeyboardEvent')document.createEvent('KeyboardEvent') 生成我自己的事件对象并寻找e.shiftKey 等,但我没有运气。

我在 Mac 上使用 Chrome 17

【讨论】:

  • 我在新旧浏览器中都使用这个,甚至在 HTA 中
  • 当某个数字当前下降时,有没有办法实现这个答案?我试过 if (e.keyCode==49) {console.log("1 is down");} 但不起作用:(
  • 嘿@RobertoSepúlvedaBravo Robert 似乎在下一个答案中回答了你的问题。 ;)
  • 实际上,如果您的意思是 Shift,您不应该在 keyup 上寻找 e.shiftKey。使用 e.shiftKey 例如而是点击。
  • Dope 答案,正是我来这里寻找的。谢谢!
【解决方案5】:
/*
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 对象的原因。如果它是超快的,这可能是为了减少这段代码。由于这将被重复调用以进行按键操作,因此速度很重要,因此我悲观地添加了映射。
【解决方案6】:

以下代码是我正在使用的:

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都用到了。

【讨论】:

  • 如果在 Alt 按下时按下“Tab”会发生什么?
【解决方案7】:

我的解决方案:

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

我现在可以通过检查来检查是否在脚本中的其他任何地方按下了任何键

pressedKeys["code of the key"]

如果为真,则按键被按下。

【讨论】:

  • 由于键已经是一个函数,不同的变量名可能会更好。
  • 这不适用于检测 Alt 键是否在所有情况下都按下。
  • 这非常适合检测上/下/左/右
  • 小心使用 mac 上的“cmd-tab”或 windows 上的“ctrl-tab”。它会触发按键,然后切换窗口,当它们返回时,它永远不会触发按键(因为浏览器没有专注于接收该按键事件)
【解决方案8】:

我知道这是一个非常古老的问题,但是有一个非常轻量级 (~.5Kb) 的 JavaScript 库可以有效地“修补”在使用 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();
});

我已将 Keydrow 合并到我的客户端 JavaScript 中,以便在我正在编写的红灯绿灯游戏中获得适当的暂停动画。您可以查看整个游戏here。 (注意:如果您将来阅读此内容,游戏应该是代码完整且可玩的:-D!)

我希望这会有所帮助。

【讨论】:

    【解决方案9】:

    到这里检查浏览器是否已经内置了一些东西,但似乎没有。这是我的解决方案(与罗伯特的回答非常相似):

    "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') 检查是否按下了某个键。

    【讨论】:

      【解决方案10】:

      我浏览了上述答案,建议的keydown/keyup 方法仅在特殊情况下有效。如果用户 alt-tabs 离开,或者使用按键手势打开新的浏览器窗口或选项卡,则将注册 keydown,这很好,因为此时无法判断按键是否是网络应用程序正在监控,或者是标准浏览器或操作系统快捷方式。回到浏览器页面,它仍然会认为密钥是被持有的,尽管它同时被释放了。或者,当用户用鼠标切换到另一个选项卡或应用程序时,某个键被简单地按住,然后在我们的页面之外释放。

      修改键(Shift 等)可以通过mousemove 等进行监控。假设在回退时预期至少有一次鼠标交互,这种情况经常发生。

      对于大多数其他键(除了修饰符,TabDelete,但包括SpaceEnter),监视keypress 将适用于大多数应用程序 - 按住键将继续触发。但是,由于keypress 触发的周期性,重置密钥存在一些延迟。基本上,如果keypress 没有继续触发,则可以排除大部分键。这与修饰符结合起来非常密封,尽管我还没有探索过如何处理 TabBackspace

      我确信那里有一些库可以抽象出这个 DOM 弱点,或者可能是一些 DOM 标准更改解决了它,因为这是一个相当古老的问题。

      【讨论】:

      • keypress 现已弃用。它似乎根本无法在 Chrome 上运行。
      【解决方案11】:

      这适用于 Firefox 和 Chrome。

      我需要在本地打开一个特殊的 html 文件(在 Windows 的文件资源管理器中选择该文件时按 Enter),或者只是为了查看文件或在特殊的在线编辑器中编辑它。

      所以我想通过在按下Enter的同时按住Ctrl键来区分这两个选项。

      正如你们都从这里的所有答案中理解的那样,这似乎不太可能,但这是一种以我可以接受的方式模仿这种行为的方法。

      它的工作方式是这样的:

      如果您在打开文件时按住Ctrl-key,则不会在 javascript 代码中触发 keydown 事件。但是会触发 keyup 事件(当您最终释放 Ctrl-key 时)。代码捕捉到了这一点。

      代码还会在其中一个事件发生时立即关闭键事件(keyup 和 keydown)。所以如果你在文件打开后按下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;
      }
      

      【讨论】:

        【解决方案12】:

        我知道为时已晚,但我有一个轻量级(398 字节)脚本,如果按下某个键,它会返回:https://github.com/brunoinds/isKeyPressed

        if (KeyPressing.isKeyPressed(13)){ //Pass the keyCode integer as parameter
             console.log('The Enter key is being pressed!')
          }else{
             console.log('The Enter key is NOT being pressed!')
          }
        

        你甚至可以设置一个时间间隔来检查按键是否被按下:

        setInterval(() => {
            if (KeyPressing.isKeyPressed(13)){
                console.log('The Enter key is being pressed!')
            }else{
                console.log('The Enter key is NOT being pressed!')
            }
          }, 1000) //Update data every 1000ms (1 second)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-04-19
          • 2011-03-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-01-29
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多