Files
kiss-translator/src/libs/shortcut.js

107 lines
2.9 KiB
JavaScript

import { isSameSet } from "./utils";
/**
* 键盘快捷键监听器
* @param {(pressedKeys: Set<string>, event: KeyboardEvent) => void} onKeyDown - Keydown 回调
* @param {(pressedKeys: Set<string>, event: KeyboardEvent) => void} onKeyUp - Keyup 回调
* @param {EventTarget} target - 监听的目标元素
* @returns {() => void} - 用于注销监听的函数
*/
export const shortcutListener = (
onKeyDown = () => {},
onKeyUp = () => {},
target = document
) => {
const pressedKeys = new Set();
const handleKeyDown = (e) => {
if (pressedKeys.has(e.code)) return;
pressedKeys.add(e.code);
onKeyDown(new Set(pressedKeys), e);
};
const handleKeyUp = (e) => {
// onKeyUp 应该在 key 从集合中移除前触发,以便判断组合键
onKeyUp(new Set(pressedKeys), e);
pressedKeys.delete(e.code);
};
target.addEventListener("keydown", handleKeyDown);
target.addEventListener("keyup", handleKeyUp);
return () => {
target.removeEventListener("keydown", handleKeyDown);
target.removeEventListener("keyup", handleKeyUp);
pressedKeys.clear();
};
};
/**
* 注册键盘快捷键
* @param {string[]} targetKeys - 目标快捷键数组
* @param {() => void} fn - 匹配成功后执行的回调
* @param {EventTarget} target - 监听目标
* @returns {() => void} - 注销函数
*/
export const shortcutRegister = (targetKeys = [], fn, target = document) => {
if (targetKeys.length === 0) return () => {};
const targetKeySet = new Set(targetKeys);
const onKeyDown = (pressedKeys, event) => {
if (targetKeySet.size > 0 && isSameSet(targetKeySet, pressedKeys)) {
event.preventDefault();
event.stopPropagation();
fn();
}
};
const onKeyUp = () => {};
return shortcutListener(onKeyDown, onKeyUp, target);
};
/**
* 高阶函数:为目标函数增加计次和超时重置功能
* @param {() => void} fn - 需要被包装的函数
* @param {number} step - 需要触发的次数
* @param {number} timeout - 超时毫秒数
* @returns {() => void} - 包装后的新函数
*/
const withStepCounter = (fn, step, timeout) => {
let count = 0;
let timer = null;
return () => {
timer && clearTimeout(timer);
timer = setTimeout(() => {
count = 0;
}, timeout);
count++;
if (count === step) {
count = 0;
clearTimeout(timer);
fn();
}
};
};
/**
* 注册连续快捷键
* @param {string[]} targetKeys - 目标快捷键数组
* @param {() => void} fn - 成功回调
* @param {number} step - 连续触发次数
* @param {number} timeout - 每次触发的间隔超时
* @param {EventTarget} target - 监听目标
* @returns {() => void} - 注销函数
*/
export const stepShortcutRegister = (
targetKeys = [],
fn,
step = 2,
timeout = 500,
target = document
) => {
const steppedFn = withStepCounter(fn, step, timeout);
return shortcutRegister(targetKeys, steppedFn, target);
};