Web 键盘输入法应用开发指南 (1) —— 基本概念
介绍
在 Web 应用中,用户交互是十分基本和重要的功能,而来自用户的输入又离不开键盘。现代 Web 浏览器已经在底层对键盘做了相对较好的支持(逐渐就能看出为什么是“相对”),并通过 API 的方式暴露给开发者。这包括针对按键的事件捕获,不同语言键盘布局(Keyboard Layout)的支持,对输入法的支持(涉及中、日、韩等东亚语言),以及对不同平台(Windows、Mac、iOS 等)上组合键的支持,等等。在这个系列的开头,我们来过一遍浏览器提供的这些与键盘输入相关的基本技术特性,先有一个基本印象,后续再逐渐展开。
按键事件
对于按键事件(Keyboard Event)[1]大家应该都不陌生,在开发 Web 应用时或多或少应该接触过。一般来说,这类事件是你在键盘上按下某个键时最先触发的事件。“最先”的意思是还有后续的事件类型产生(比如input
事件等),用于进一步的输入逻辑处理。而到这一步,你(或者说 Web 应用)能知道的是,浏览器从操作系统那里得到的按键信息。至于说这个按键会得到怎样的输入和文本,那就是后续事件的事情了。我前面还加上了“一般来说type
属性来区分。前两类的含义可以从字面理解,而 keypress 类型一般是针对产生具体字符的按键(比如单按一个 Ctrl 键就不会产生字符),但已不推荐使用了[2]。有了这些类型,就可以在应用中对用户的键盘输入做比较精细的处理。一个简单的例子是,我要知道用户按住了某个特定的键,持续一段时间,以执行某个业务逻辑,并在释放按键时终止逻辑。
按键事件对象里还有一些常用的属性,比如code
属性告诉你哪个键被按了,location
属性告诉你这个键在键盘的哪个区域(是左 Alt 还是右 Alt),isCompsing
属性告诉你这个键是不是在使用输入法期间按下的,等等。当然,这些属性很多都有兼容性问题,我会在后面细说。
键盘布局
简单来说,键盘布局[3](Keyboard Layout)规定了你的键盘上某个位置的键将会产生怎样的输出,这是一个映射关系。比如在 Windows 系统上,我们输入中文和英文,其实都在使用英文键盘布局,而输入日文和德文就需要相应的日文和德文键盘布局了。在英文布局上,你按下“y”这个键,结果就输出“y”这个字符,而在德文布局下,同样的键会产生“z”字符。键盘布局在你切换输入语言或者输入法时会进行相应变换,这些由系统完成。
在一些系统上有Scan Code
的概念,一个键的 scan code 标识了这个键在当前所使用键盘上的物理位置。比如在常用的英文键盘上,左边 shift 键旁边的位置就是字母“z“,那么它的 scan code 就标识了这个键的位置在左 shift 的右边,仅此而已。至于按下键后会输出什么字符,这就需要键盘布局的信息了。系统会根据当前的键盘布局,将来自物理键盘的 scan code 信息“翻译”成应该输出的字符。
现代浏览器的实现中没有直接拿到 scan code,但通过键盘事件中的code
属性[4],可以访问到类似的位置信息。例如按下字母“Q”键产生的 keydown 事件中code
属性的值为KeyQ
,它的含义是英文键盘上对应 Q 的位置的键被按下了。注意 IE 浏览器不支持 code 属性,在开发时要考虑用户的场景。在这里[4]可以找到更详细的针对不通过键盘类型的 code 定义。
那么浏览器中的应用能知道用户当前的系统键盘布局吗?答案是:目前还不能。因为这需要浏览器通过系统 API 得到需要的信息,而浏览器还没有提供 JavaScript 接口。目前只有个getLayoutMap
接口[5],且还没有被所有主流浏览器支持。它返回一个 promise,并在 promise 被 resolve 时拿到一个从按键信息到字符信息的 map。这样只要通过事件对象拿到按键信息(比如code
属性),就可以得到它在当前系统键盘布局下的输出字符,从而可以反推目前系统的键盘布局信息。当然,如此获得键盘布局信息还是略显笨拙且容易出错,还是期待未来标准中对键盘信息有更为完善的支持。
输入法事件
对于中、日、韩等东亚语言来说,输入法(Input Method Editor)是必不可少的输入工具。浏览器对输入法需要特别支持,原因在于使用输入法时有一个组字(Composition)的过程。这一点我们很熟悉了,比如用中文输入法打出“你好”两个字,你需要先输入“nihao”的拼音,然后从候选框中选择你要输入的字或者词。对于浏览器来说,最终填入输入框的是“你好”两个字,但是前面输入拼音的过程也需要精确地监控,以满足可能的业务需求。
浏览器中与输入法相关的常用事件[6]有,compositionstart
(开始组字),compositionupdate
(更新组字),compositionend
(结束组字)等。有了这些事件,应用程序可以知道用户是否在使用输入法输入,目前到了组字的哪个阶段,以及是否提交了组字结果。对于日文输入法来说,还有分段组字的支持,可以对不同词语调出候选框进行选择。此外,input
事件有时也很有用,可以根据 input 事件的不同类型[7],来获取当前的输入内容或者进行其他操作。
需要注意的是,不同浏览器对各类输入法事件的支持并不一致,W3C 组织制定的相应标准也有多个版本(Level1,Level2...),而不同浏览器厂商对标准的实现有出入,涉及触发事件的类型、事件的时序以及兼容性等。这就需要开发者了解多种浏览器的实现,避免出现与输入相关的 bug。
组合键
浏览器对组合键也需要特别的支持,否则用户的输入将无法正确实现。组合键可以大致分为两类,一类是功能性的,比如Ctrl+Shift+字母键
,在某个应用中完成特定的功能;另一类是辅助输入的,比如在西班牙语等欧洲语言中,要想打出特定的字符,需要先按某个功能键,再按一个字母键,才能得出正确结果,比如字符á
,它需要先按英语键盘上的[
键,再按字母a
键。浏览器需要一些特殊的按键事件属性对这些输入提供支持。
对于第一类组合键,应用程序需要知道当某个键被按下时,是否还有某个功能键(如 Alt,Ctrl,或者 Shift 等)也被按下了,这时可以通过 keydown 事件的*Key
属性来判断。比如,如果是Alt+F
组合键,那么在F
的 keydown 事件中,altKey
属性值为true
;如果是Ctrl+Shift+K
,那么在K
的 keydown 事件中,ctrlKey
和shiftKey
属性都为true
。
对于第二类组合键,比如字符西语字符á
,先按的[
键被称为Dead Key
[8],此时浏览器产生了 keydown 事件,但没有产生任何输出,事件的key
属性值为Dead
。当字母键被按下时,产生正确的输出,同时key
属性的值被设置为最终的字符á
。
组合键的问题有时候会很复杂,因为一些组合键可能先被系统的输入法或者其他进程捕获,而没有发送到应用程序。还有些时候,为了防止组合键的副作用,需要显式地阻断一些组合键的效果,这都需要对按键事件进行特殊处理,同时有不能影响正常的用户输入。
总结
本文梳理了 Web 浏览器中键盘和输入法功能的要点,可以让你对基本的概念有一些感性的印象,从下篇文章开始,我们开始逐一探讨具体的开发技术。欢迎关注和讨论。
参考阅读
[1] Keyboard Event
[2] Keypress Event
[3] Keyboard Layout
[4] Code property
[7] Input Type
[8] Dead Key
版权声明: 本文为 InfoQ 作者【天择】的原创文章。
原文链接:【http://xie.infoq.cn/article/a96cc023fa03ffb847c85a858】。文章转载请联系作者。
评论 (2 条评论)