按键字符映射文件

按键字符映射文件(.kcm 文件)负责将 Android 按键代码与辅助键的组合映射到 Unicode 字符。

对于具有按键的所有内部(内置)输入设备,即使只是为了告诉系统这些设备仅用于特殊用途(非全键盘),特定于设备的按键布局文件也必不可少。

对于外部键盘,特定于设备的按键布局文件为可选项,并且通常根本不需要。系统会提供适用于许多外部键盘的通用按键字符映射。

如果没有提供特定于设备的按键布局文件,系统将选择默认按键布局文件。

位置

系统会按 USB 供应商、产品(并可能按版本)ID 或输入设备名称来查找按键字符映射文件,

并会按顺序检测以下路径。

  • /odm/usr/keychars/Vendor_XXXX_Product_XXXX_Version_XXXX.kcm
  • /vendor/usr/keychars/Vendor_XXXX_Product_XXXX_Version_XXXX.kcm
  • /system/usr/keychars/Vendor_XXXX_Product_XXXX_Version_XXXX.kcm
  • /data/system/devices/keychars/Vendor_XXXX_Product_XXXX_Version_XXXX.kcm
  • /odm/usr/keychars/Vendor_XXXX_Product_XXXX.kcm
  • /vendor/usr/keychars/Vendor_XXXX_Product_XXXX.kcm
  • /system/usr/keychars/Vendor_XXXX_Product_XXXX.kcm
  • /data/system/devices/keychars/Vendor_XXXX_Product_XXXX.kcm
  • /odm/usr/keychars/DEVICE_NAME.kcm
  • /vendor/usr/keychars/DEVICE_NAME.kcm
  • /system/usr/keychars/DEVICE_NAME.kcm
  • /data/system/devices/keychars/DEVICE_NAME.kcm
  • /odm/usr/keychars/Generic.kcm
  • /vendor/usr/keychars/Generic.kcm
  • /system/usr/keychars/Generic.kcm
  • /data/system/devices/keychars/Generic.kcm
  • /odm/usr/keychars/Virtual.kcm
  • /vendor/usr/keychars/Virtual.kcm
  • /system/usr/keychars/Virtual.kcm
  • /data/system/devices/keychars/Virtual.kcm

当构建包含设备名称的文件路径时,设备名称中除“0-9”“a-z”“A-Z”“-”或“_”之外的所有字符都会被替换为“_”。

通用按键字符映射文件

系统提供了一个特殊的内置按键字符映射文件,名为 Generic.kcm。 此按键字符映射旨在支持各种标准外部键盘。

请勿修改通用按键字符映射!

虚拟按键字符映射文件

系统提供了一个特殊的内置按键字符映射文件,名为 Virtual.kcm,供虚拟键盘设备使用。

虚拟键盘设备属于合成输入设备,其 ID 为 -1(请参阅 KeyCharacterMap.VIRTUAL_KEYBOARD)。从 Android Honeycomb 3.0 开始,所有 Android 设备都配备了虚拟键盘设备。虚拟键盘设备的目的是提供一种已知的内置输入设备,它可用于通过 IME 或测试插桩将按键注入到应用中,即使设备没有内置键盘也是如此。

虚拟键盘在所有设备上都假定具有相同的完整 QWERTY 布局。这样一来,应用可以使用虚拟键盘设备注入按键,并始终得到相同的结果。

请勿修改虚拟按键字符映射!

语法

按键字符映射文件是由键盘类型声明和一组按键声明组成的纯文本文件。

键盘类型声明

键盘类型声明描述了键盘的整体行为。 字符映射文件必须包含键盘类型声明。为了清楚起见,声明通常放置在文件的顶部。

type FULL

系统可识别以下键盘类型:

  • NUMERIC:数字(12 键)键盘。

    数字键盘支持使用多次击键方式输入文本。 可能需要多次击键才能生成所需的字母或符号。

    这种类型的键盘通常设计为用拇指打字。

    对应于 KeyCharacterMap.NUMERIC

  • PREDICTIVE:一种具有所有字母的键盘,但每个键包含多个字母。

    这种类型的键盘通常设计为用拇指打字。

    对应于 KeyCharacterMap.PREDICTIVE

  • ALPHA:一种具有所有字母的键盘,并且还可能带有一些数字。

    字母键盘支持直接输入文本,但由于尺寸小,因此布局可能会很紧凑。与 FULL 键盘相比,一些符号只能使用特殊的屏幕字符选择器才能输入。 此外,为了提高打字速度和准确性,框架为字母键盘提供了特殊的功能,如自动首字母大写和切换/锁定 SHIFT 和 ALT 键。

    这种类型的键盘通常设计为用拇指打字。

  • FULL:一种 PC 式全键盘。

    全键盘的用法类似于 PC 的键盘。通过按键盘上的键可以直接输入所有符号,无需屏幕支持或诸如自动首字母大写等直观功能。

    这种类型的键盘通常设计为用双手打字。

  • SPECIAL_FUNCTION:一种仅用于执行系统控制功能(而非打字)的键盘。

    特殊功能键盘仅由并非实际用于打字的非输出键(如 HOME 和 POWER)组成。

Generic.kcmVirtual.kcm 按键字符映射都是 FULL 键盘。

按键声明

每个按键声明都包含关键字 key,后跟一个 Android 按键代码名称、一个左大括号、一组属性和行为以及一个右大括号。

key A {
    label:                              'A'
    base:                               'a'
    shift, capslock:                    'A'
    ctrl, alt, meta:                    none
}

属性

每个按键属性都会建立从按键到行为的映射。为了使按键字符映射文件更加紧凑,可以将多个属性(用逗号分隔)映射到同一个行为。

在上面的示例中,为 label 属性分配了 'A' 行为。 同样,同时为 ctrlaltmeta 属性分配了 none 行为。

系统可识别以下属性:

  • label:当按键包含一个字符时,指定物理打印在该按键上的标签。这是 KeyCharacterMap.getDisplayLabel 方法返回的值。

  • number:指定数字文本视图具有焦点时的行为(即应该输入的字符),例如用户在输入电话号码时。

    紧凑型键盘通常会将多个符号组合到一个按键上,这样可能会使用同一按键来输入 '1''a''#''q'。 对于这些按键,应设置 number 属性,以指示在数字上下文中应输入的符号(如有)。

    一些典型的“数字”符号为数字 '0''9''#''+''('')'',''.'

  • base:指定在没有按下辅助键时的行为(即应该输入的字符)。

  • <modifier> 或 <modifier1>+<modifier2>+...:指定在按下按键并且所有指定的辅助键处于活动状态时的行为(即应该输入的字符)。

    例如,辅助键属性 shift 指定了在按下 LEFT SHIFT 或 RIGHT SHIFT 辅助键时会应用的行为。

    同样,辅助键属性 rshift+ralt 指定了在同时按下 RIGHT SHIFT 和 RIGHT ALT 辅助键时会应用的行为。

将在辅助键属性中识别以下辅助键:

  • shift:在按下 LEFT SHIFT 或 RIGHT SHIFT 辅助键时应用。
  • lshift:在按下 LEFT SHIFT 辅助键时应用。
  • rshift:在按下 RIGHT SHIFT 辅助键时应用。
  • alt:在按下 LEFT ALT 或 RIGHT ALT 辅助键时应用。
  • lalt:在按下 LEFT ALT 辅助键时应用。
  • ralt:在按下 RIGHT ALT 辅助键时应用。
  • ctrl:在按下 LEFT CONTROL 或 RIGHT CONTROL 辅助键时应用。
  • lctrl:在按下 LEFT CONTROL 辅助键时应用。
  • rctrl:在按下 RIGHT CONTROL 辅助键时应用。
  • meta:在按下 LEFT META 或 RIGHT META 辅助键时应用。
  • lmeta:在按下 LEFT META 辅助键时应用。
  • rmeta:在按下 RIGHT META 辅助键时应用。
  • sym:在按下 SYMBOL 辅助键时应用。
  • fn:在按下 FUNCTION 辅助键时应用。
  • capslock:在 CAPS LOCK 辅助键被锁定时应用。
  • numlock:在 NUM LOCK 辅助键被锁定时应用。
  • scrolllock:在 SCROLL LOCK 辅助键被锁定时应用。

属性的列出顺序很重要。在将按键映射到行为时,系统会按顺序扫描所有相关属性,并返回找到的最后一个适用行为。

因此,对于给定按键,后面指定的属性会替换前面指定的属性。

行为

每个属性都会映射到一个行为。最常见的行为是输入字符,但还有其他行为。

将识别以下行为:

  • none:不输入字符。

    当没有指定字符时,此行为是默认行为。虽然指定 none 不是必需的,但它可以提高明确性。

  • 'X':输入指定的字符文字。

    此行为会使指定的字符输入到聚焦的文本视图中。字符文字可以是任何 ASCII 字符,也可以是以下转义序列之一:

    • '\\':输入反斜杠字符。
    • '\n':输入新行字符(用于 ENTER/RETURN)。
    • '\t':输入 TAB 字符。
    • '\'':输入撇号字符。
    • '\"':输入引号字符。
    • '\uXXXX':按照 XXXX 格式输入以十六进制形式提供码位的 Unicode 字符。
  • fallback <Android key code name>:如果应用未处理该按键,就执行默认操作。

    当应用本身不处理指定的按键时,此行为会导致系统模拟不同的按键操作。它用于支持新按键的默认行为,并非所有应用都知道如何处理此类按键,例如 ESCAPE 或数字拨号键盘按键(在未按下 numlock 时)。

    当执行回退行为时,应用将收到两个按键操作:一个用于原始键,另一个用于选定的回退键。 如果应用在松开按键期间处理原始键,回退键事件就会被取消(KeyEvent.isCanceled 将返回 true)。

系统保留两个 Unicode 字符来执行特殊功能:

  • '\uef00':执行此行为时,文本视图将使用并删除光标前的四个字符,将其转换为十六进制数字,并插入相应的 Unicode 代码点。

  • '\uef01':执行此行为时,文本视图显示包含杂项符号的字符选择器对话框。

系统将以下 Unicode 字符识别为组合变音静键字符:

  • '\u0300':重音符号。
  • '\u0301':尖音符号。
  • '\u0302':抑扬音符号。
  • '\u0303':腭化音符号。
  • '\u0308':元音变音符号。

如果在输入静键时后跟另一个字符,该静键和后面的字符将组合在一起。例如,如果用户在输入重音符号静键时后跟字母“a”,输出结果为“à”。

如需详细了解静键处理,请参阅 KeyCharacterMap.getDeadChar

评论

注释行以“#”开头,并持续到这一行的结束。示例如下:

# A comment!

空白行会被忽略。

如何将按键组合映射到行为

当用户按下某个键时,系统会查找与该按键组合和当前按下的修饰符关联的行为。

SHIFT + A

假设用户同时按下 A 和 SHIFT。系统会首先查找与 KEYCODE_A 关联的一组属性和行为。

key A {
    label:                              'A'
    base:                               'a'
    shift, capslock:                    'A'
    ctrl, alt, meta:                    none
}

系统按从头到尾、从左到右的顺序扫描属性,但会忽略 labelnumber 这两个特殊属性。

遇到的第一个属性是 base。无论按哪个辅助键,base 属性始终会应用于按键。它主要用于指定按键的默认行为,除非默认行为替换为后续属性。 由于 base 属性会应用于此按键操作,因此系统会如实记录其行为为 'a'(输入字符 a)。

系统继续扫描后续属性,如果其中出现任何比 base 更具体的属性,就会进行替换。这时,系统遇到也会应用于按键操作 SHIFT + A 的 shift。因此,系统决定忽略 base 属性的行为,并选择与 shift 属性关联的行为,即 'A'(输入字符 A)。

然后,系统继续扫描上述表格,但是没有其他属性会应用于此按键操作(CAPS LOCK 未锁定,CONTROL 键、ALT 键和 META 键均未按下)。

因此,组合键 SHIFT + A 生成的行为是 'A'

CONTROL + A

现在考虑一下,如果用户一起按下 A 和 CONTROL 将会发生什么。

如前所述,系统将扫描属性表。系统会注意到应用的 base 属性,但仍将继续扫描,直至最终实现 control 属性。恰巧的是,control 属性出现在 base 之后,因此前者行为会替换 base 行为。

因此,CONTROL + A 组合键生成的行为是 none

Esc

现在假设用户按下 Esc。

key ESCAPE {
    base:                               fallback BACK
    alt, meta:                          fallback HOME
    ctrl:                               fallback MENU
}

这次系统获得一种回退行为 fallback BACK。 由于没有显示字符文字,因此不会输入字符。

处理按键时,系统首先将 KEYCODE_ESCAPE 发送到应用。如果应用未处理按键,系统将再次尝试,但这次它将按照回退行为要求将 KEYCODE_BACK 发送到应用。

因此,能够识别并支持 KEYCODE_ESCAPE 的应用有机会按原样处理该按键,但没有机会按原样处理该按键的其他应用可以执行后备操作,将该按键作为 KEYCODE_BACK 一样对待。

带有或不带 NUM LOCK 的 NUMPAD_0

根据 NUM LOCK 键是否处于锁定状态,数字小键盘键的解释大有不同。

以下按键声明会确保,在按下 NUM LOCK 键时,KEYCODE_NUMPAD_0 输入 0。在未按下 NUM LOCK 键时,系统会照常将按键发送到应用;如果未处理该按键,系统将发送回退键 KEYCODE_INSERT

key NUMPAD_0 {
    label, number:                      '0'
    base:                               fallback INSERT
    numlock:                            '0'
    ctrl, alt, meta:                    none
}

正如我们所见,对于不能识别或直接支持 PC 式全键盘上所有按键的旧版应用,后备按键声明显著提高了与此类应用的兼容性。

示例

全键盘

# This is an example of part of a key character map file for a full keyboard
# include a few fallback behaviors for special keys that few applications
# handle themselves.

type FULL

key C {
    label:                              'C'
    base:                               'c'
    shift, capslock:                    'C'
    alt:                                '\u00e7'
    shift+alt:                          '\u00c7'
    ctrl, meta:                         none
}

key SPACE {
    label:                              ' '
    base:                               ' '
    ctrl:                               none
    alt, meta:                          fallback SEARCH
}

key NUMPAD_9 {
    label, number:                      '9'
    base:                               fallback PAGE_UP
    numlock:                            '9'
    ctrl, alt, meta:                    none
}

字母数字键盘

# This is an example of part of a key character map file for an alphanumeric
# thumb keyboard.  Some keys are combined, such as `A` and `2`.  Here we
# specify `number` labels to tell the system what to do when the user is
# typing a number into a dial pad.
#
# Also note the special character '\uef01' mapped to ALT+SPACE.
# Pressing this combination of keys invokes an on-screen character picker.

type ALPHA

key A {
    label:                              'A'
    number:                             '2'
    base:                               'a'
    shift, capslock:                    'A'
    alt:                                '#'
    shift+alt, capslock+alt:            none
}

key SPACE {
    label:                              ' '
    number:                             ' '
    base:                               ' '
    shift:                              ' '
    alt:                                '\uef01'
    shift+alt:                          '\uef01'
}

游戏手柄

# This is an example of part of a key character map file for a game pad.
# It defines fallback actions that enable the user to navigate the user interface
# by pressing buttons.

type SPECIAL_FUNCTION

key BUTTON_A {
    base:                               fallback BACK
}

key BUTTON_X {
    base:                               fallback DPAD_CENTER
}

key BUTTON_START {
    base:                               fallback HOME
}

key BUTTON_SELECT {
    base:                               fallback MENU
}

兼容性说明

在 Android Honeycomb 3.0 之前,Android 按键字符映射使用截然不同的语法进行指定,并在构建时编译成二进制文件格式 (.kcm.bin)。

虽然新格式使用相同的扩展名 .kcm,但语法完全不同(而且功能更强大)。

从 Android Honeycomb 3.0 开始,所有 Android 按键字符映射文件必须使用本文档中描述的新语法和纯文本文件格式。 系统不支持旧版语法,并且不会识别旧版 .kcm.bin 文件。

语言说明

Android 目前不支持多语言键盘。此外,内置的通用按键字符映射采用美式英文键盘布局。

如果是为其他语言设计键盘,我们建议原始设备制造商 (OEM) 为其键盘提供自定义按键字符映射。

未来版本的 Android 可能会为多语言键盘或用户可选型键盘布局提供更好的支持。

验证

确保使用验证按键映射工具验证您的按键字符映射文件。