You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改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)**时触发,要支持持续按住,需要:

  1. 实时跟踪所有按键的按下状态,维护一个活跃按键集合/状态对象
  2. 在**按键按下(keydown)**阶段持续检查组合键是否激活
  3. 根据需求选择固定间隔触发,或跟随浏览器原生重复频率触发

内容的提问来源于stack exchange,提问作者Temir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 08:52:38