微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

监听 JS

如何解决监听 JS

在 JavaScript 中,我知道我可以侦听特定的键代码,但是如何侦听特定的击键“模式”,然后在键入这些模式时触发不同的事件?

这方面的一个例子可能是一个游戏,其中玩家按下秘密 Konami 代码的键(上、上、下、下、左、右、左、右、B、A、开始)。我如何在 JavaScript 中跟踪该模式或其他类似模式?

我是否会通过某种等待/异步过程来捕获每个键并等待下一个键来完成此操作?有没有更简单的方法解决这个问题,而不会耗尽最终用户的系统?

我想做这样的伪代码

on('keydown',() => {
    if (lastKeyspressed === "QWERTY") doSomething();
});

我目前尝试的是将输入的每个键记录到一个字符串中,然后读取 keyCode 序列以查看它是否像这样匹配:

let typedString = "";
const secret = "This is a secret";
document.addEventListener('keydown',e => {
    typedString += e.key;
    if (typedString.slice(-secret.length) === secret) alert('Secret typed!');
});

这是迄今为止我得到的最接近的一个字符串,到目前为止它对我有用,但是我很难让它为多个字符串工作,并且当中间有大写字母时字符串,因为 keydown 事件也捕获“Shift”键并将 Shift 附加到我的 typedString

解决方法

就个人而言,我会通过将每个击键的 keyCode 存储到一个数组中,然后检查该键盘记录器数组中的 最后 X 个项目并将其与您的模式进行匹配来解决此问题想听。

为了保持该数组的轻量级,我会将每次击键时的数组长度修剪为最长模式的数组长度,这将是跟踪所有模式所需的最大击键次数。

在比较最近键入的键时,我取消移动新键代码以将它们添加到 keylog 数组的开头,然后将其与每个模式的反转状态进行比较以从右到左检查。这很重要,因为我们不断地从数组中删除最后一个字符,即最旧的字符。最近的字符将始终首先出现在 keylog 数组中。为了对模式进行浅反向,以免改变原始模式的顺序,我使用 .slice().reverse()

最后,为了获得小写和大写字母的准确键码,如果事件的 e.key.charCodeAt() 属性正好是一个字符,我会取 key。否则,所有字母都将呈现为大写,并且某些字符(例如“斜杠”)将具有错误的 charCode。

在这里试试:

patterns = {
    "konami code": [38,38,40,37,39,98,97,13],"happy birthday": "happy birthday".split("").map(e => e.charCodeAt()),"sticky keys": [16,16,16],"hello world": "hello world".split("").map(e => e.charCodeAt()),"todays date": `${((new Date()).getMonth() + 1).toString()}/${(new Date()).getDate().toString()}/${(new Date()).getFullYear().toString()}`.split("").map(e => e.charCodeAt())
};

const maxLength = Math.max(...Object.values(patterns).map(e => e.length));
const keylog = [];
const testArraysEqual = (arr1,arr2) => arr1.length === arr2.length && arr1.every((e,i) => e === arr2[i]);

document.addEventListener('keydown',e => {
    keylog.unshift(e.key.length === 1 ? e.key.charCodeAt() : e.keyCode);
    if (keylog.length > maxLength) keylog.length = maxLength;
    for ([patternName,pattern] of Object.entries(patterns)) {
        if (pattern.length <= keylog.length && testArraysEqual(pattern.slice().reverse(),keylog.slice(0,pattern.length))) {
            console.log(`${patternName} pattern fired`);
        }
    }
});
Try clicking anywhere in this result window and typing any of the following patterns:
<ul>
    <li>↑ ↑ ↓ ↓ ← → ← → b a "enter"</li>
    <li>happy birthday</li>
    <li>"shift" "shift" "shift" "shift" "shift"</li>
    <li>hello world</li>
    <li>today's date in M/D/YYYY format (e.g. `2/22/2021`)</li>
</ul>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。