ktp-forked-repos / custom-keyboard

A JavaScript library for binding keyboard combination and sequence.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Keyboard Util


支持的功能

  • 任意数量键组合监听
  • 输入顺序检测,完全对应检测
  • n连击监听
  • 按下/放开响应
  • 上下文切换绑定监听
  • 全局响应/暂停监听
  • 绑定到'key' | 'keyCode' | 'code'三种不同类型的键盘事件
  • Typescript支持

引入

import Keyboard, { AvalidKeys } from 'keyboard.util';

Keyboard是个单例, AvalidKeys是keyboard.util定义的合法绑定键名的ts类型。


响应/暂停监听 mount / unmount

Keyboard.mount();
Keyboard.unmount();

Keyboard做了事件委托,只绑定一个监听事件到document。 首先在任意位置调用一次Keyboard.mount()使得Keyboard响应已绑的监听。 在需要暂停响应监听的时候调用Keyboard.unmount(),需要响应监听的时候再次调用Keyboard.mount();


bind(bindKeys | bindOption, pressDownExectuor, pressUpExectuor) 生成监听器

示例
Keyboard.bind('a', () => {
    console.log('pressDown a')
}, () => {
    console.log('pressUp a')
});
bind函数接受三个参数:
  • 1.bindKeys: 需要监听的键 (必须,键名必须为MapEventKeyCode.ts文件里定义的范畴) bindKeys可为三种格式:

    • string类型 (格式为:键名+键名+...,中间可有可无空格)
          Keyboard.bind('a + b');  // 监听a+b
          Keyboard.bind('a+b + c'); // 监听a+b+c
          Keyboard.bind('q + q + q'); // 监听q三连击
      
          Keyboard.bind('a + b | c + d'); // 同时监听a+b和c+d
    • Array/类型
          Keyboard.bind(['a', 'b']); // 监听a+b
          Keyboard.bind(['a', 'b', 'c']; // 监听a+b+c
          Keyboard.bind(['q', 'q', 'q'); // 监听q三连击
    • Array类型
          Keyboard.bind([['a', 'b'], ['c', 'd']]); // 同时监听a+b和c+d

    Array类型的优势在于,typescript下有类型提示和校验。但这也带来语义不足的问题:

    绑定['a', 'b', 'a'], 'a + a + b'这种带有重复键名的多键组合的,出于语义上的考量会把重复的键给去重,而不是表示为依次顺序按下。

    打个比方: string类型的输入可以多一种 'a > b > c'的写法表示顺序按下,但是Array貌似不能再多一种语义了。

    所以为了string和Array语义等价,也没有在string上额外加一种功能表示顺序按下。

    我觉得用纯重复键名组合表示连击这种方式都已经是一种很Hack的做法……但是为了Ts的支持,先就这样吧。

    Ts4.1出了个template string type,本质是转化到union type,键名数量级太大也不能用在这里,但是说不定以后进化了。

    bindKeys如不符合上述三种类型和或键名不合法,会导致bind函数失败返回false

  • 2.pressDownExectuor: 按下按键时的响应函数 (必须, Function或者显式的null)

  • 3.pressUpExectuor: 松开按键时的响应函数 (可选, Function)

    • bindKeys表示连击时绑pressUpExectuor会被忽视

bind成功会返回一个包含了所有生成的监听器对象的数组


bind函数 进阶选项 bindOptions

bind函数的第一个参数除了可以是上述bindKeys类型,还可以是符合如下规则的对象(此时对象的bindKeys键为必填属性): 使用bindKeys时生成的监听器拥有下述属性的默认值 等同 使用bindOption而不填属性值时的默认值

interface BindOption {
    bindKeys: BindKeys;
    type?: 'key' | 'keyCode' | 'code'; // default 'key'
    context?: string;
    preventRepeat?: boolean; // default true
    strictOrder?: boolean | 'equal'; // default true
    caseSensitive?: boolean; // default false
}

bindOption -- type

每个键盘事件KeyboardEvent中有三种类型 'key' | 'keyCode' | 'code' 标志按下的是哪个键。

事件对象的 key 属性允许获取字符,而事件对象的 code 属性则允许获取“物理按键代码”。

例如,同一个按键 Z,可以与或不与 Shift 一起按下。会得到两个不同的字符:小写的 z 和大写的 Z。

event.key 正是这个字符,并且它将是不同的。但是,event.code 是相同的:

如果用户使用不同的语言,那么切换到另一种语言将产生完全不同的字符,而不是 "Z"。它将成为 event.key 的值,而 event.code 则始终都是一样的:"KeyZ"。

因为特殊物理配列的键盘实在太多了(在我眼里),所以还是建议使用'key'。即使这样子会导致开着非英文输入法时候无效。

'code'是'keyCode'的新标准, 我还没写填上。


bindOption -- caseSensitive

只有当bindOption type 为'key'时才有意义,所以默认设为false。

比如当按下shitf + xx的组合键时,event.key是大小写敏感的,但是在我想当然的大部分场景下仅仅只是想把shift当组合键而不是触发大写语义。


bindOption -- preventRepeat

Keyboard.bind({
    bindKeys: ['v', 'b', 'n'],
    preventRepeat: false,
}, () => {
    console.log('repeat press v and b and n');
});

一直按着键盘不放会持续触发键盘事件,显式设置这个参数为false使监听器响应重复事件。


bindOption -- strictOrder

Keyboard.bind({
    bindKeys: ['j', 'k', 'l'],
    strictOrder: false,
}, () => {
    console.log('press j and k and l');
});

strictOrder默认为true,即只有按照key在数组中的顺序才会触发响应 如下必须依次jkl

strictOrder可以为'equal'进行更严格校验, 即 只 顺序按着key, 如果在之前还额外按着别的键如下h->j->k->l则不触发

显式设置strictOrder为false去掉顺序校验


bindOption -- context and Keyboard.setContext, getContext, getAllContext

Keyboard.getContext();
Keyboard.setContext('context');
Keyboard.getAllContext();
Keyboard.bind({
    bindKeys: ['a'],
    context: 'context2'
}, () => {
    console.log('press a in context2')
});

Keyboard有上下文的概念,可以在bindOption中设置context值显式为一个监听器指定生效的上下文。

默认为undefined即在任何上下文中都生效

  • 通过getContext获取Keyboard当前Context
  • 通过setContext设置Keyboard当前Context
  • 通过getAllContext获取Keyboard中所有有context的监听器的context集合

unbind

const listener1 = Keyboard.bind('t', () => {});
const listener2 = Keyboard.bind(['g', 'h'], () => {});
if (listener1 && listener2) {
    Keyboard.unbind(listener1[0]);
    Keyboard.unbind([...listener2, ...listener1]);
}

bind成功会返回包含生成的监听器对象的数组,可以拿这个对象数组去unbind

也可以拿单个监听器对象

有任一解绑成功则返回true, 否则返回false


getAllListener

console.log(Keyboard.getAllListener());

getAllListener可以拿到Keyboard中所有的bind生成的监听器对象


设置连击检测时间间距

通过setContinuousInterval设置连击检测的时间间隔,默认为 250。

代表两次相同按键超过250ms不算连击

Keyboard.setContinuousInterval(222);

reset

reset可以清空Keyboard中已经绑定的监听器和上下文

Keyboard.reset();

注意事项

MacOS下基于command的组合键有个系统层级的问题

当按住command时候再按其他任意键触发组合键,这时候接着按住command,松开其他键,松开的键的keyup事件不会被浏览器触发。

所以在command松开的时候全清_pressed里监测的已按下的按键防止bug,但是按住command再连续按其他键这种操作方式没有解决。

如果只是跟踪command + 任意一键,可以通过keyEvent里判定是否同时按下command解决,但是三键以上组合这个问题几乎无解。

About

A JavaScript library for binding keyboard combination and sequence.


Languages

Language:TypeScript 89.7%Language:SCSS 8.6%Language:HTML 1.3%Language:JavaScript 0.4%