如何修改RxJS快捷键事件以监听持续按住的按键?
实现RxJS持续按住快捷键触发的方案
方案1:按固定间隔持续触发
适合需要稳定频率执行操作的场景(比如每隔N毫秒触发一次),代码如下:
import { fromEvent, merge, map, scan, filter, distinctUntilChanged, switchMap, interval } from 'rxjs'; enum KeyCode { ShiftLeft = 'ShiftLeft', KeyM = 'KeyM' } function shortcutContinuous(keys: KeyCode[], intervalMs: number = 100) { // 监听按键按下/松开事件,映射为状态更新 const keyDown$ = fromEvent<KeyboardEvent>(document, 'keydown').pipe( map(event => ({ key: event.code, pressed: true })) ); const keyUp$ = fromEvent<KeyboardEvent>(document, 'keyup').pipe( map(event => ({ key: event.code, pressed: false })) ); // 维护当前所有按键的按下状态 const keyStates$ = merge(keyDown$, keyUp$).pipe( scan((state, { key, pressed }) => ({ ...state, [key]: pressed }), {} as Record<string, boolean>), // 仅当组合键的状态变化时才更新 distinctUntilChanged((prev, curr) => keys.every(key => prev[key] === curr[key]) ) ); // 组合键激活时按间隔持续发出事件,否则停止 return keyStates$.pipe( switchMap(state => { const isCombinationActive = keys.every(key => state[key]); return isCombinationActive ? interval(intervalMs).pipe(map(() => state)) : []; }) ); } // 使用示例:每100毫秒触发一次 const toggle$ = shortcutContinuous([KeyCode.ShiftLeft, KeyCode.KeyM], 100); toggle$.subscribe(() => { console.log("Shift+M 持续按住中..."); });
方案2:跟随浏览器默认按键重复频率触发
适合需要和原生按键重复行为一致的场景,代码如下:
import { fromEvent, merge, scan, withLatestFrom, filter, distinctUntilChanged } from 'rxjs'; enum KeyCode { ShiftLeft = 'ShiftLeft', KeyM = 'KeyM' } function shortcutContinuous(keys: KeyCode[]) { // 监听按键按下/松开事件,提取按键码 const keyDown$ = fromEvent<KeyboardEvent>(document, 'keydown').pipe( map(event => event.code) ); const keyUp$ = fromEvent<KeyboardEvent>(document, 'keyup').pipe( map(event => event.code) ); // 维护当前处于按下状态的按键集合 const activeKeys$ = merge(keyDown$, keyUp$).pipe( scan((activeKeys, key) => { if (activeKeys.includes(key)) { // 按键松开,从集合中移除 return activeKeys.filter(k => k !== key); } else { // 按键按下,添加到集合中 return [...activeKeys, key]; } }, [] as string[]), distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)) ); // 每次按键按下时,检查组合键是否全部处于激活状态 return keyDown$.pipe( withLatestFrom(activeKeys$), filter(([_, activeKeys]) => keys.every(key => activeKeys.includes(key))), // 可选:如果需要避免连续重复触发,可取消下方注释 // distinctUntilChanged() ); } // 使用示例 const toggle$ = shortcutContinuous([KeyCode.ShiftLeft, KeyCode.KeyM]); toggle$.subscribe(() => { console.log("Shift+M 持续按住中..."); });
核心修改思路
原方案仅在**按键松开(keyup)**时触发,要支持持续按住,需要:
- 实时跟踪所有按键的按下状态,维护一个活跃按键集合/状态对象
- 在**按键按下(keydown)**阶段持续检查组合键是否激活
- 根据需求选择固定间隔触发,或跟随浏览器原生重复频率触发
内容的提问来源于stack exchange,提问作者Temir
相关产品推荐
相关产品推荐

