【转】Android-Input 按键字符映射文件&输入设备配置文件

时间:2022-11-30 05:01:57

https://source.android.com/devices/input/key-character-map-files

按键字符映射文件

按键字符映射文件(.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.kcm 和 Virtual.kcm 按键字符映射都是 FULL 键盘。

按键声明

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

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

属性

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

在上面的例子中,label 属性被分配了 'A' 行为。同样,ctrlalt 和 meta 属性同时被分配了 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 按键代码名称>:如果应用未处理该按键,则执行默认操作。

    当应用本身不处理指定的按键时,此行为会导致系统模拟不同的按键。它用于支持并非所有应用都知道如何处理的新按键的默认行为,例如 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
}
 

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

遇到的第一个属性是 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

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

验证

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

输入设备配置文件

输入设备配置文件(.idc 文件)包含特定设备的配置属性,这些属性会影响输入设备的行为。

输入设备配置文件通常并非标准外围设备(例如 HID 键盘和鼠标)所必需的,因为默认的系统行为通常可确保它们开箱即用。另一方面,内置的嵌入式设备(尤其是触摸屏)几乎总是需要输入设备配置文件来指定其行为。

基本原理

根据关联的 Linux 内核输入设备驱动程序报告的事件类型和属性,Android 会自动检测和配置大多数输入设备功能。

例如,如果输入设备支持 EV_REL 事件类型、代码 REL_X 和 REL_Y 以及 EV_KEY 事件类型和 BTN_MOUSE,则 Android 会将输入设备归类为鼠标。鼠标的默认行为是在屏幕上显示光标,光标跟踪鼠标的移动并在鼠标被点击时模拟触摸操作。虽然可以通过不同的方式配置鼠标,但是默认行为通常足以用于标准的鼠标外围设备。

某些类别的输入设备更加模糊。例如,多点触摸屏和触摸板都至少支持 EV_ABS 事件类型以及代码 ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y。不过,这些设备的主要用途千差万别,无法总能自动确定。此外,还需要其他信息才能了解触摸设备报告的压力和大小信息。因此,触摸设备(尤其是内置触摸屏)通常都需要 IDC 文件。

位置

输入设备配置文件由 USB 供应商、产品(及可选版本)ID 或输入设备名称定位。

按顺序查阅以下路径。

  • /odm/usr/idc/Vendor_XXXX_Product_XXXX_Version_XXXX.idc
  • /vendor/usr/idc/Vendor_XXXX_Product_XXXX_Version_XXXX.idc
  • /system/usr/idc/Vendor_XXXX_Product_XXXX_Version_XXXX.idc
  • /data/system/devices/idc/Vendor_XXXX_Product_XXXX_Version_XXXX.idc
  • /odm/usr/idc/Vendor_XXXX_Product_XXXX.idc
  • /vendor/usr/idc/Vendor_XXXX_Product_XXXX.idc
  • /system/usr/idc/Vendor_XXXX_Product_XXXX.idc
  • /data/system/devices/idc/Vendor_XXXX_Product_XXXX.idc
  • /odm/usr/idc/DEVICE_NAME.idc
  • /vendor/usr/idc/DEVICE_NAME.idc
  • /system/usr/idc/DEVICE_NAME.idc
  • /data/system/devices/idc/DEVICE_NAME.idc

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

句法

输入设备配置文件是由属性分配和注释组成的纯文本文件。

属性

属性分配均由属性名称、=、属性值和新行组成。例如:

property = value
 

属性名称为非空的文字文本标识符,不能包含空格。输入系统的每个组件都定义一组用于配置其功能的属性。

属性值为非空字符串文字、整数或浮点数。不能包含空格或保留字符 \ 或 "

属性名称和值区分大小写。

注释

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

# A comment!
 

空白行会被忽略。

示例

# This is an example of an input device configuration file.
# It might be used to describe the characteristics of a built-in touch screen. # This is an internal device, not an external peripheral attached to the USB
# or Bluetooth bus.
device.internal = 1 # The device should behave as a touch screen, which uses the same orientation
# as the built-in display.
touch.deviceType = touchScreen
touch.orientationAware = 1 # Additional calibration properties...
# etc...
 

通用属性

以下属性在所有输入设备类之间通用。

如需了解每个类所使用的特殊属性,请参阅各个输入设备类的文档。

device.internal

定义:device.internal = 0 | 1

指定输入设备属于内置组件,还是外部连接(很可能可拆卸)的外围设备。

  • 如果值为 0,则该设备为外部设备。

  • 如果值为 1,则该设备为内部设备。

  • 如果该值未指定,则 USB (BUS_USB) 或蓝牙 (BUS_BLUETOOTH) 总线上的所有设备的默认值均为 0,否则,值为 1

该属性决定有关唤醒事件的默认策略决定。

内部输入设备一般不从休眠状态中唤醒显示屏,除非关键布局文件或硬编码的策略规则中明确进行了相应配置。这种区别可防止按键和触摸意外唤醒您口袋中的手机。通常只定义几个唤醒键。

相反,外部输入设备通常会更主动地唤醒设备,因为它们在传输过程中被假定为关闭或未插入。例如,按下外部键盘上的任何一个键就能很好地说明用户希望唤醒设备并得到响应。

务必确保所有内部输入设备 device.internal 属性的值都得到正确设置。

验证

确保使用验证按键映射工具验证您的输入设备配置文件。

迁移指南

本文档介绍一些有助于迁移到新的 Android 版本的提示。

迁移到 Android Gingerbread 2.3

在 Gingerbread 中,我们新增了输入设备配置文件(在此版本中,又称为输入设备校准文件)的概念。

务必为所有触摸屏提供输入设备配置文件。特别是有必要花时间提供触摸尺寸信息的校准参考。

迁移到 Android Honeycomb 3.0

在 Honeycomb 中,我们修改了按键字符映射文件格式,并开始更好地利用输入设备配置文件。此外,我们还新增了对 PC 式全键盘的支持,并引入了全新的“通用”按键映射,以取代旧的特定于模拟器的“qwerty”按键映射(从未用作通用型按键映射)。

务必更新您的所有按键字符映射文件,以便使用新的语法。

如果您的外围设备依赖于旧的“qwerty”按键映射,则您可能需要提供特定于设备的新按键映射,以模拟旧行为。您应该为通过 USB 产品 ID/供应商 ID 或设备名称标识的每种设备创建新的按键映射。

为所有特殊功能输入设备提供按键字符映射文件尤为重要。这些文件应该只包含一个将键盘类型设置为 SPECIAL_FUNCTION 的行。

可确保所有内置输入设备均正确配置的一个方法是运行 dumpsys,然后使用 Generic.kcm 查找配置不正确的设备。

迁移到 Android Honeycomb 3.2

在 Honeycomb 3.2 中,我们新增了对操纵杆的支持,并扩展了按键布局文件格式以支持操纵杆轴映射。

迁移到 Android Ice Cream Sandwich 4.0

在 Ice Cream Sandwich 4.0 中,我们将触摸屏的设备驱动程序要求更改为遵循标准的 Linux 多点触控输入协议,并新增了对“B”协议的支持。我们还支持数字化仪平板电脑和基于触控笔的触屏设备。

您可能需要更新输入设备驱动程序,以按照标准正确实现 Linux 多点触控输入协议。

您还需要更新输入设备配置文件,因为某些更改后的属性更简单、更系统化。

要详细了解驱动程序要求,请参阅触屏设备