为什么当按住两个键并释放第一个键时会触发额外事件?

问题描述 投票:0回答:1

这个问题困扰我有一段时间了。我正在 Javascript 中使用 WebAudioAPI 来制作合成器。我有一个播放声音的 keydown 事件和一个停止声音的 keyup 事件。但是,如果我按住两个键,首先是 q,然后是 w,如果我松开 q(按住 w),w 的事件会第二次触发,留下一个从未播放过的附加声音。即使在触发 keyup 事件后也会结束。

这是按键事件:

document.body.addEventListener('keydown', (e) => {
            if(e.repeat){
                return;
            }

            else if (this.heldKeys.length > 0){
                let keyIsHeld;
                for (let key of this.heldKeys){
                    if (key.code == e.code){
                        this.eventStop(key, true);
                        keyIsHeld = true;
                    }
                }
                if(keyIsHeld){
                    this.removeElementsFromArrayByProperty(this.heldKeys, e);
                }
            }

            this.eventStart(e, true);
            this.heldKeys.push(e);
        });

注意

if (e.repeat)
子句。这非常适合按住该键并且不会重复,但是一旦按下另一个键并且释放第一个键,天哪,我们就会触发另一个事件。

我尝试了几种方法来捕获这些重复的声音(就像上面看到的 else if 语句一样),但即使它有效(这里没有),事件仍然会触发,并且会出现中断声音。

我已经做了相当多的谷歌搜索,但我回来的只是添加

e.repeat
语句(或者与按下的键的 bool 非常相似的东西),但是这些都没有能力阻止晚宴上看不见的(但声音很大)的人,每次弹奏两个键并且放开第一个键时,他都会闯入。

我希望对此有一个非常明显的答案,比如也许使用 html 元素,但我无法理解是什么让两个事件以按下一个键的价格触发(在其前身的帮助下)。

顺便说一句,我已经用多个键盘尝试过这一点。结果相同。

这是 keydown 事件(如果有帮助的话):

document.body.addEventListener('keyup', (e) => {
            this.eventStop(e, true);
            this.removeElementsFromArrayByProperty(this.heldKeys, e);
        });

这是一个堆栈片段,您可以使用它来复制我收到的事件:

document.body.addEventListener('keydown', (e) => {
    if (!e.repeat) {
        console.log(e.type, e.key);
    }
});
document.body.addEventListener('keyup', (e) => {
    console.log(e.type, e.key);
});
To replicate:
<ol>
    <li>Click here to focus the document</li>
    <li>Press and hold <kbd>q</kbd></li>
    <li>Press and hold <kbd>w</kbd></li>
    <li>Let go of <kbd>q</kbd></li>
</ol>
After the <code>keyup</code> for <kbd>q</kbd>, there's a spurious non-repeat <code>keydown</code> for <kbd>w</kbd>.

javascript html web-audio-api
1个回答
0
投票

记住 @Kaddath 向我们展示的内容,当触发事件的键被按下时,事件的

repeat
属性被设置为
false
,同时另一个键也被按住并抬起以触发其
keyup 
事件;我编辑了
keyup
keydown
事件处理程序,以便在触发此附加事件时返回
keydown

document.body.addEventListener('keydown', (e) => {
            let isKeyAlreadyPressed;
            for (let key of this.heldKeys){
                if (key.code == e.code){
                    isKeyAlreadyPressed = true;
                }
            }
            if(e.repeat || isKeyAlreadyPressed){
                return;
            }
            else{
                this.eventStart(e, true);
                this.heldKeys.push(e);
            }
        });

        document.body.addEventListener('keyup', (e) => {
            this.eventStop(e, true);
            this.heldKeys = this.removeElementsFromArrayByProperty(this.heldKeys, "code", e.code);
        });

keydown
事件结束时,我们将该事件添加到名为
heldKeys
的数组中。

keyUp
中,
heldKeys
数组中与
code
具有相同
e
属性的每个元素都将从数组中删除,因此我们知道它不再被保留。

当下一次触发

keyDown
时,我们检查
heldKeys
中是否存在与
code
e
匹配的
code
事件。如果这是真的,那么已经有一个相同类型的键被按下,因此当这个附加事件触发时,可以防止它永无休止的多余声音破坏我们的耳朵。

这不是一个正确的解决方案,但我实际上还没有看到任何人发布解决方案,所以我想在这里发布此内容,以防有人想要快速解决类似问题。

这是项目顺便说一句(大部分已完成,目前正在针对 React 和 TypeScript 进行重组)。

© www.soinside.com 2019 - 2024. All rights reserved.