KeyboardEvent和快捷键

背景

项目中需要对网页的 UI 操作设置快捷键,但是我们的开发机是 Mac,用户使用的是 Windows。所以开发起来遇到一些小小的坑。现在我们来梳理下这些知识点。

基础知识

网页上要设置快捷键最基础的做法一般是监听 keydown 事件,然后通过监听函数参数获取一些按键相关的属性来判断用户按了哪些按键:

  document.addEventListener( 'keydown', function( event ){
    let key = event.key;
    if ( key === 'Enter' ) {
      console.log( '你按下的是回车键~' );
    }
  } );

上面的代码只是做一个示例,按键相关的属性有很多个,这些属性定义在 KeyboardEvent 这个接口中。keydown 事件监听函数接受的第一个参数 event 就实现了这个接口(event不仅仅实现了 KeyboardEvent 还实现了其他接口噢)。KeyboardEvent 这个接口是在 W3C 的 DOM 规范里面定义的,现在最新发布的规范版本是 DOM4。不过呢,KeyboardEvent 在 DOM4 中并没有什么更新,文档直接把其定义指向了 DOM3 中的 KeyboardEvent 接口定义。所以接下来,让我们看下规范中是如何定义键盘事件的。

KeyboardEvent

先介绍下我们常用的一些属性(规范地址):

  • KeyboardEvent.key
  • KeyboardEvent.code
  • KeyboardEvent.ctrlKey
  • KeyboardEvent.shiftKey
  • KeyboardEvent.altKey
  • KeyboardEvent.metaKey

KeyboardEvent.ctrlKey | shiftKey | altKey | metaKey 比较简单,表示当你按下键盘的时候,Ctrl | Shift | Alt | meta 按键是否已经被按下。如果已经被按下这些值就是 true,通常我们要运用组合键的判断会用到(譬如:Alt + a)。大家看到 meta 会疑惑这个是哪个键?在 Mac 平台上指的是 command 键(),而在 Windows 平台指的是 windows 键()。但是不是所有 Windows 电脑键盘都有 这个键的。接下来我们介绍下最重要的两个属性 key 和 code。

KeyboardEvent.key

如果你按下的按钮所代表的是一个可打印的字符(printed representation),那么这个 key 的值就是这个字符(譬如:a、Enter、Shift、CapsLock、Backspace)。如果是一些特殊字符呢,这个值就可能是 Unidentified。你要问哪些键是特殊字符,这个。。。伦家标准里面说了应键盘而异。这里说的是单独按一个按键的场景,组合键又不同了,key 出什么值是有一套简单的算法的:

key holds the key value of the key pressed. If the value is has a printed representation, it MUST be a non-empty Unicode character string, conforming to the algorithm for determining the key value defined in this specification.

这里我只介绍最基本的用法,不详述算法。

KeyboardEvent.code

这个值比较诡异,它表示你按了键盘上的哪个按键。你按 a,code 的值是 KeyA,你按左边的 Shift,code 的值是 ShiftLeft。什么意思呢?就是他表示你按的按键在键盘的哪个位置。这里就有趣了,因为不同语言的键盘同一个键代表的字符可能不同,但是位置是相同的。打个比方:KeyQ 代表的是我们普通键盘q按键。但是呢 Dvorak 键盘q这个位置的按钮代表的不是 q,而是'。所以如果你按同一个按钮,key 的值可能不同,code 的值会相同。

有了上述的几个值一般的单个按键和组合键都能检测到了,不过按照 web 标准的尿性你可能会猜到,那兼容性问题呢?查下兼容表。。。key 和 code 兼容性堪忧啊,都是浏览器高级版本支持或者根本不支持。那么怎么办?

非标准属性

KeyboardEvent 接口标准经历了许多草稿版本,首先在 DOM2 下由于没有协商一致,它被丢弃; DOM3 重新加入。这导致了在早期的 DOM2 版本中非标准的实现。

  • KeyboardEvent.char:如果是 printed 的字符,则值是这个字符,如果是按键没有对应的 printed 字符,值为空。(如果该按键用作插入多个字符的宏, 则此属性的值是整个字符串, 而不仅仅是第一个字符。)
  • KeyboardEvent.charCode:是按键字符对应的 Unicode 编码的数字。(对于其 char 属性包含多个字符的按键是该属性中第一个字符的 Unicode 值。)
  • KeyboardEvent.keyCode:返回一个代表你所按按键的数字,这个数字是和系统实现相关。
  • KeyboardEvent.which:通常和 keyCode 是一致的。

DOM3 规范中说这些过期的属性会因平台,键盘语言,键盘布局等等众多因素而导致其取值不统一。

兼容性

如果你要在不同的浏览器甚至不同的平台使用一套快捷键,你尝试上述所有说到的属性,你会发现表现几乎都不一致。有的情况是相同按钮[组合]对应同一个属性取出的值不同。譬如 Alt + a,当你在 a 按下去的时候去获取 KeyboardEvent.key 的值,Windows 平台得到的是a,而 Mac 平台下得到的是å。有的情况是上述 KeyboardEvent 中很多属性都不支持,你连挑的机会都没有,譬如老版本的 IE 几乎只支持 KeyboardEvent.keyCode 这一个属性。

经过大量的测试,如果你需要一个大路化通用的解决方案,只能使用 KeyboardEvent.keyCode 来做统一的判断。当然如果这不能满足你的要求,那么你可以通过 userAgent 来判断不同平台,针对不同平台采取不同的快捷键策略。以上就是对这个知识点的简单梳理,如果想要更深入的如了解键盘事件的模型,请参考下方附上的规范。

参考资料

  1. KeyboardEvent from MDN: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.
  2. KeyboardEvent in DOM3 Events Specification: https://w3c.github.io/uievents/#interface-keyboardevent.
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,657评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,889评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,057评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,509评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,562评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,443评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,251评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,129评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,561评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,779评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,902评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,621评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,220评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,838评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,971评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,025评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,843评论 2 354

推荐阅读更多精彩内容

  • 例子: //这条命令相当于按了设备的Backkey键 adb shell input keyevent 4 //可...
    井望阅读 14,213评论 0 5
  • 手机端配置tcp方式连接 su setprop service.adb.tcp.port 5555 stop ad...
    yoyo鹿鸣阅读 5,662评论 0 4
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,656评论 18 139
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,409评论 0 17
  • error code(错误代码)=0是操作成功完成。error code(错误代码)=1是功能错误。error c...
    Heikki_阅读 3,381评论 1 9