为什么 "ShiftLeft" 在 "ShiftRight" 被按住时不触发 keyUp 事件,反之亦然?

Why does "ShiftLeft" not trigger a keyUp-event while "ShiftRight" is held and vice versa?

考虑以下最小设置:

    function keyDown(event, element) {
        console.log("Down: " + event.code);
    }
    function keyUp(event, element) {
        console.log("Up: " + event.code);
    }
    <input
        type="text"
        onkeyup="keyUp(event, this)"
        onkeydown="keyDown(event, this)"
    />

现在,当输入字段处于活动状态时,每次按下和释放键时,控制台都会显示一条消息,以及相关键的键码。

按下并释放一个键将产生两条消息:

Down: KeyA Up: KeyA

按住一个键,然后按住另一个键,然后松开第一个键,然后松开第二个键将产生 4 条消息:

Down: KeyA Down: KeyB Up: KeyA Up: KeyB

这符合预期。 现在,对于上下文,“Shift”键实际上有两个键码,ShiftRightShiftLeft 分别用于区分大多数键盘上的左移键和右移键。现在是有趣的部分:

重复与之前相同的双键模式,这次只使用两个 Shift 键,结果如下:

Down: ShiftRight Down: ShiftLeft Up: ShiftLeft

即使我在松开左 shift 键之前松开右 shift 键,也从来没有为它触发 keyUp 事件。同样显示如果我以相反的方式进行,从 ShiftLeft:

开始

Down: ShiftLeft Down: ShiftRight Up: ShiftRight

起初我以为这可能只是键盘上那些有多个版本的特殊按钮的处理方式,但似乎并没有那么简单。例如,ControlLeftControlRight 的行为方式与任何其他按钮相同。另一方面,EnterNumpadEnter 的行为与两个班次的行为相同,每次都遗漏一个 keyUp 事件。

这种行为的原因是什么?有没有办法关闭它?

看来这是浏览器违背您意愿的情况。当我自己 运行 对此进行一些调查后,我注意到 event.repeat 标志以一种相当奇怪的方式设置。

从我的实验来看,浏览器似乎将两个 shift 键合并在一起,但仅限于 keyup 事件。按下第一个键将发出一个带有适当代码和 event.repeat: falsekeydown 事件。按下另一个键会发出带有自己代码的 keydown 事件,但是 event.repeat: true... 即使它是不同的键。此时,浏览器完全忘记了它们是单独的键。

一旦你松开一个键...没有任何反应。浏览器仍然认为 'shift' 被持有,所以它完全吞下了这个事件。事实上,您可以多次按下并释放它,但只会获得 keydown 个事件。只有当您松开第二个 Shift 键后,您才会获得一个 keyup 事件及其各自的代码。

我不确定有什么方法可以阻止这种行为。事件根本就没有产生,甚至cancelling/preventDefaulting原来的shift press也不影响

这会阻止您将两个 shift 键的顺序正确识别为一个键,但您仍然可以依靠 keyup 来识别 both 个 shift 键有被释放,因为这似乎是它开火的条件。如果您正在跟踪单个按键,则可以同时注册 ShiftLeft 的释放和 ShiftRight 的释放,反之亦然。