检查钥匙是否按下?


91

有没有一种方法可以检测JavaScript中当前是否存在某个键?

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

PS最大的问题似乎是在一段时间后,密钥开始重复,触发了诸如恶魔般的keydown和keyup事件。希望只有一个简单的isKeyDown(key)函数,但是如果没有,则需要解决/解决此问题。


6
我在这里看到的答案的一个常见问题是,如果您按住某个键,然后更改选项卡或更改焦点,先放开该键,然后再切换回去,则代码将认为该键已按下,直到您再次按下或移动将鼠标放在页面上。:-(
埃里克·米克尔森

Answers:


71

有没有一种方法可以检测JavaScript中当前是否存在某个键?

不。唯一的可能就是监控每个keyupkeydown和记忆。

一段时间后,按键开始重复,触发了按下按键和按下按键等恶性事件。

不应该这样 您肯定会keypress重复的,在许多浏览器中您也会重复的keydown,但是如果keyup重复,那是一个错误。

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


14
您先生是一位绅士和学者。Ubuntu上的Chromium和Firefox是我的主要开发环境,因此可以准确地解释我所遇到的问题。希望它会变得更好,否则计时器黑客解决方案可能是唯一的解决方法。
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

除了使用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,所以你不必使用鼠标移动。

我试着用document.createEvent('KeyboardEvent')document.createEvent('KeyboardEvent')寻找e.shiftKey这样的东西来生成自己的事件对象,但是我没有运气。

我在Mac上使用Chrome 17


在新旧浏览器中,甚至在HTA上,我都在使用它
Jakob Sternberg 2014年

1
当前某个数字下降时,是否有办法实现此答案?我tryed与IF(e.keyCode == 49){执行console.log( “1降”);},但不工作:(
罗伯托·塞普尔韦达·布拉沃

嘿@RobertoSepúlvedaBravoRobert似乎会在下一个答案上回答您的问题。;)
Mark Odey

实际上,如果您要按Shift键,则不应该在keyup上寻找e.shiftKey。在例如onclick上使用e.shiftKey代替。
maciek

45

我的解决方案:

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

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

pressedKeys["code of the key"]

如果为真,则按下该键。


2
由于键已经是一个函数,因此使用其他变量名称可能会更好。
乌鸦

1
这在所有情况下都无法检测出Alt键是否按下。
迈克尔(Michael)

1
这非常适合检测上/下/左/右
Jonathan Spiller

11

我不相信有什么像isKeyDown函数,但是您可以编写自己的函数。

基本上,创建一个数组,其长度是要监视的键数。然后使用document / pages / controls 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,

4
这不是一个好的解决方案,因为您将编写越来越多的ifs。一个“ keyList = {};” 作为对象接受“ keyList [key] = true;” 不需要枚举或限制,因为它使用字符串索引/属性并适用于所有键。
SparK 2012年

5

最终在这里检查浏览器是否已经内置了某些功能,但似乎没有。这是我的解决方案(非常类似于Robert的回答):

"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查询密钥的实际状态。

您可以做的,或者如果需要进行此工作,可能需要做的是,以编程方式将密钥反跳。本质上,您可以自己评估keydownkeyupkeyup如果事件在最后一次之后过快发生,则可以忽略该事件keydown;或者本质上,您应该将响应延迟keyup足够长的时间,以确保不会再出现keydown0.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 2014年

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 =“键隐藏”)。松开Alt键时,标签消失。jQuery和Bootstrap都被使用。


如果在按住Alt键的同时按下“ Tab”键会怎样?
迈克尔(Michael)

1

我知道这是一个非常老的问题,但是有一个非常轻便的(〜.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();
});

我已将Keydrown集成到我的客户端JavaScript中,以便在我正在编写的Red Light Green Light游戏中适当地暂停动画。您可以在此处查看整个游戏。(注意:如果您将来要阅读此书,则游戏应该是完整的代码,并且可以玩:-D!)

我希望这有帮助。


1

我扫描了以上答案,提出的keydown/ keyup方法仅在特殊情况下有效。如果用户alt跳开标签,或使用键盘手势打开新的浏览器窗口或标签,则将keydown注册a,这很好,因为此时无法确定该密钥是否是Web应用程序正在监视的东西,或者是标准的浏览器或操作系统快捷方式。回到浏览器页面,尽管它是同时释放的,但仍然会认为该键已被按住。或者在用户使用鼠标切换到另一个选项卡或应用程序时,只是简单地按住了一些键,然后将其释放到我们的页面之外。

Shift可以通过mousemove等方式监视修改键(等),假设在回跳时至少需要进行一次鼠标交互(通常是这种情况)。

对于大多数其他所有按键(除了改性剂,TabDelete,但包括SpaceEnter),监控keypress会为大多数应用-一键按住会继续火。但是由于keypress触发的周期性,重置密钥会有一些延迟。基本上,如果keypress不保持触发状态,则可以排除大多数键。与修饰符结合使用时,虽然我还没有探索过与Taband的关系,但是它与气密性相当Backspace

我敢肯定那里有一些库可以解决这个DOM弱点,或者也许是某些DOM标准更改可以解决这个问题,因为这是一个相当老的问题。


现在不推荐使用keypress。它似乎根本无法在Chrome上运行。
eadsjr

0

查看答案,然后使用onkeyuponkeydown是有关这些事件的更具体的信息。


1
您引用的链接是针对鼠标事件的,其中自动重复不是问题。
卡尔·斯莫特里兹

向上键和向下键将不再重复。按键可能。
克拉迪(Claudiu)

好吧,即使他们这样做了,我也在想像TJMonk15的解决方案,只是不想写下来
Claudiu

1
这两个问题的措词完全相同。奇怪的巧合,还是更多?
米奇·林格伦

2
@Mitch:哇……真不可思议。我不知道为什么有人会提出两个帐户来问同样的问题。或更可能是此人刚刚复制了另一个问题,并对其进行了修改以适应关键要求
Claudiu 2010年

0

这适用于Firefox和Chrome。

我需要在本地打开一个特殊的html文件(通过Enter在Windows的文件资源管理器中选择该文件时按),以查看文件或在特殊的在线编辑器中对其进行编辑。

因此,我想通过按住- Ctrl键或不按住-键来区分这两个选项Enter

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

运作方式如下:

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

一旦其中之一发生,该代码还将关闭键盘事件(键盘事件和键盘事件)。因此,如果Ctrl在打开文件后按- 键,则不会发生任何事情。

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

-3
$('#mytextbox').keydown(function (e) {
            if (e.keyCode == 13) {
                if (e.altKey) {
                    alert("alt is pressed");
                }
            }
 });

如果按Alt + Enter,您将看到警报。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.