不触发键盘或鼠标事件,检测已按下的修饰键。

14

当用户按下修饰键(Shift、Alt、Ctrl)时,我的应用程序会改变其状态。我使用keydown / keyup事件来跟踪修饰键:

var altPressed;
window.onkeydown = window.onkeyup = function(e) {
    altPressed = e.altKey;
}

键盘事件无法在浏览器标签之外触发。现在,想象以下情景:

  1. 按住 Shift 键
  2. 单击链接到我的应用程序,它将在一个新窗口中打开
  3. 释放 Shift 键

keyup 事件不会在我的页面失去焦点时触发,因此当我再次聚焦于我的应用程序标签时,它仍显示 Shift 键被按下的状态。

如果 页面可见性事件 具有修饰键属性,那就太好了。但是,它们没有这样的属性。

document.addEventListener('webkitvisibilitychange', function(e) {
    if (document.webkitHidden) return;

    e.altKey // undefined :(

}, false);

所以,您想知道在页面加载之前按下了哪些键吗?如果是这样,可能会是一条崎岖的道路... - rvighne
你能给一个理由为什么你想这样做吗?页面可以在后台加载,因此可能无法始终获取键事件。 - charlee
3
你实际上想要解决什么问题?目前看起来,你只是在描述你观察到的行为,我没有看到你需要帮助解决的特定问题描述。 - jfriend00
@jfriend00:请查看原始修订记录;由于某些原因,OP编辑了实际问题。 - rvighne
我认为关键是在返回应用程序后,alt/shift等键不应该仍然被按下,换句话说,在返回应用程序时检测它已经被释放。 - JDuarteDJ
2个回答

4
到目前为止,我想到的最好的是:
document.body.onkeydown = function(e) {
  if (e.which === 18) {
    alt_state.textContent = 'pressed';
  }
};

document.body.onkeyup = function(e) {
  if (e.which === 18) {
    alt_state.textContent = 'released';
  }
};

function detectAlt() {
  if (document.webkitHidden) return;
  window.addEventListener('mousemove', function onMove(e) {
    alt_state.textContent = e.altKey ? 'pressed' : 'released';
    window.removeEventListener('mousemove', onMove, false);
  }, false);
}

document.addEventListener('webkitvisibilitychange', detectAlt, false);
window.addEventListener('load', detectAlt, false);

按住 alt 键并单击链接:jsbin

它依赖于 mousemove 事件,与 loadvisibilitychange 事件不同,具有 altKey 属性。缺点是,直到用户移动鼠标才能检测到 altKey。


mousemove 一直在运行 detectAlt(),即使它只是一个 if() return;,它仍然一直在运行!(对此没有投反对票,因为它仍然是一个解决方案) - JDuarteDJ
1
@JDuarteDJ onMove 在每次鼠标移动时运行,但是如果你查看代码,在第一次运行后它就被移除了。detectAlt 在加载和 webkitvisibilitychange 事件触发时运行。 - Tibos
大部分时间它都是开启的。自从加载直到按下alt键,然后自从可见直到下一个alt键按下。基本上只要它不闲置! 我觉得你的回答很好。 - JDuarteDJ
我发现另一个问题:有时它无法检测到按下的alt键,很可能是因为它在mousemove触发器之间被按下了,或者其他什么原因... - JDuarteDJ
1
我尝试使用setTimeout和自定义事件分派来解决问题。不幸的是,我无法在不触发本机事件(keydown keypress keyup mouseenter mouseleave mousemove mouseout mouseover)的情况下获取shift / alt / ctrl键状态。而且我不能强制用户触发其中之一。你的解决方案到目前为止是最好的。你只能通过添加我提到的所有事件来扩展它,这样状态就会随着几乎任何用户交互而更新,而不仅仅是mousemove。祝你好运! - Entity Black
这里的技巧是将修改器状态保存到您自己的变量中。 - JDuarteDJ

1
我能想到两个选项:

  1. 使用定时的“alt状态”--> 2秒后宣布alt未按下。

    document.body.onkeydown = function(e) { if (e.which === 18) { alt_state.textContent = 'pressed'; setTimeout(function(){ alt_state.textContent= ""; },2000); } };

  2. 当可见性丢失时,只需重置所有alt标记。

    document.addEventListener('webkitvisibilitychange', function(e) {
        if (document.webkitHidden){
            altPressed = "";
            return;
        }
    }, false);
    

尝试这个:http://jsbin.com/jihuyibu/1/edit。这是我最好的猜测,即使如此也不能完美地实现。


重置...所有东西? - xyhhx
我看不到这个有效。另外,你正在链接到我的 jsbin。 - NVI
@Martin 是的,重置你所有的修改器标志。NVI 我在你的代码中做了一个小改变,使用了2。仔细看一下。 - JDuarteDJ
明天我会改进答案,但基本上唯一有问题的站点是在应用程序外按下修改器并检测其输入时。就那个部分而言,我会采用你的解决方案的一个版本:在可见性更改时添加一个mousemove监听器,然后在第一次触发时删除它,并记录修饰键状态。这也可以解决在应用程序外检测释放的相反情况。第二个选项仍然是使用假设:假设离开时释放键,假设进入时没有按键。这可能会使它更容易。 - JDuarteDJ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接