按键字符映射文件

按键字符映射文件(.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':键入制表符。
    • '\'':键入撇号字符。
    • '\"':键入引号字符。
    • '\uXXXX':键入 Unicode 字符,其代码点由 XXXX 以十六进制给出。
  • fallback <Android 键码名称>:如果应用未处理按键,则执行默认操作。

    当应用未原生处理指定的按键时,此行为会导致系统模拟不同的按键按下。它用于支持并非所有应用都知道如何处理的新按键的默认行为,例如 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 属性,这些属性是特殊的。

遇到的第一个属性是 basebase 属性始终适用于按键,无论按下什么修饰键。它本质上指定了按键的默认行为,除非它被后面的属性覆盖。由于 base 属性适用于此按键按下,因此系统会记录其行为为 'a'(键入字符 a)的事实。

然后,系统继续扫描后续属性,以防其中任何一个属性比 base 更具体并覆盖它。它遇到了 shift,它也适用于按键按下 SHIFT + A。因此,系统决定忽略 base 属性的行为,并选择与 shift 属性关联的行为,即 'A'(键入字符 A)。

然后,它继续扫描表,但是没有其他属性适用于此按键按下(CAPS LOCK 未锁定,CONTROL 键、ALT 键和 META 键均未按下)。

因此,按键组合 SHIFT + A 的结果行为为 'A'

CONTROL + A

现在考虑如果用户同时按下 A 和 CONTROL 会发生什么情况。

与之前一样,系统会扫描属性表。它会注意到 base 属性适用,但也会继续扫描,直到最终到达 control 属性。碰巧的是,control 属性出现在 base 之后,因此其行为会覆盖 base 行为。

因此,按键组合 CONTROL + A 的结果行为为 none

ESCAPE

现在假设用户按下了 ESCAPE。

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 可能会为多语言键盘或用户可选择的键盘布局提供更好的支持。

验证

请务必使用验证按键映射工具来验证您的按键字符映射文件。