郑州网站制作_郑州网页制作_做网站设计_河南网站制作网,厦门做商城网站,口岸地区网站建设内容,行业网站域名选择1.介绍
一个硬件按键的处理流程大致为#xff1a;当用户按下或释放一个键时#xff0c;键盘硬件会生成一个扫描码scan code#xff0c;然后操作系统读取这个scan code#xff0c;并将scan code扫描码映射到虚拟键码key code#xff0c;最后操作系统根据映射的keycode生成…1.介绍
一个硬件按键的处理流程大致为当用户按下或释放一个键时键盘硬件会生成一个扫描码scan code然后操作系统读取这个scan code并将scan code扫描码映射到虚拟键码key code最后操作系统根据映射的keycode生成输入事件并将这些事件传递给应用程序或系统服务进而执行相应的操作。
scan code和key code通过Key layout file 映射Key layout file一般用于定义物理键盘上各个键的功能和映射关系。文件通常以 .kl 为后缀例如我们熟知的 Generic.kl文件。
2.scan code和key code
先来介绍下scan code和key code
scan code扫描码用于表示物理键盘或其他输入设备上按键的唯一标识符。scan code是硬件级别的编码用于告诉操作系统哪个键被按下。
key code键码是操作系统层面上用于识别和处理输入事件的编码可以将硬件层面的按键映射到更高层次的抽象使得应用程序能够处理输入事件而不必直接关心底层硬件的细节。key code定义在KeyEvent.java中一些常见的按键 public static final int KEYCODE_DPAD_UP 19;//方向上键的keycode为19public static final int KEYCODE_DPAD_DOWN 20;//方向下键public static final int KEYCODE_DPAD_LEFT 21;//方向左键public static final int KEYCODE_DPAD_RIGHT 22;//方向右键public static final int KEYCODE_DPAD_CENTER 23;//中间键
3.按键声明
按键映射关系声明在kl文件内下面以一些常见的按键声明来说明它的语法规则
frameworks/base/data/keyboards/Generic.klkey 103 DPAD_UP
key 104 PAGE_UP
key 105 DPAD_LEFT
key 106 DPAD_RIGHT
key 465 ESCAPE FUNCTION按键声明包含关键字 key后跟一个 Linux 按键代码编号和 Android 按键代码名称任何一项声明都可以后跟一组由空格分隔的可选 flag。
常见的 flag
FUNCTION按键应解读为如同也按下了 FUNCTION 键。 GESTURE按键由用户手势例如手掌摸触摸屏生成。 VIRTUAL按键是与主触摸屏相邻的虚拟软键电容式按钮。这会导致启用特殊的去抖动逻辑
上述例子表明scan code为103映射KeyEvent上的KEYCODE_DPAD_UP(后面以此类推)。
4.位置
按键布局文件由 USB vendor、product可能还包括versionID 或输入设备名称来确定位置。系统会按顺序查阅以下路径
/odm/usr/keylayout/Vendor_XXXX_Product_XXXX_Version_XXXX.kl
/vendor/usr/keylayout/Vendor_XXXX_Product_XXXX_Version_XXXX.kl
/system/usr/keylayout/Vendor_XXXX_Product_XXXX_Version_XXXX.kl
/data/system/devices/keylayout/Vendor_XXXX_Product_XXXX_Version_XXXX.kl
/odm/usr/keylayout/Vendor_XXXX_Product_XXXX.kl
/vendor/usr/keylayout/Vendor_XXXX_Product_XXXX.kl
/system/usr/keylayout/Vendor_XXXX_Product_XXXX.kl
/data/system/devices/keylayout/Vendor_XXXX_Product_XXXX.kl
/odm/usr/keylayout/DEVICE_NAME.kl
/vendor/usr/keylayout/DEVICE_NAME.kl
/system/usr/keylayout/DEVICE_NAME.kl
/data/system/devices/keylayout/DEVICE_NAME.kl
/odm/usr/keylayout/Generic.kl
/vendor/usr/keylayout/Generic.kl
/system/usr/keylayout/Generic.kl
/data/system/devices/keylayout/Generic.kl
5.Generic.kl
系统提供了一个常规按键布局文件名为 Generic.kl。此按键布局旨在支持各种标准外部键盘和操纵杆,一般情况下不要轻易修改这个文件。
6.自定义kl文件
Android支持为硬件设备自定义kl文件kl文件的定制需要遵循一定的规则以帮助系统和开发者区分不同的硬件设备或输入设备。
命名规则
命名规则通常包括硬件的制造商Vendor、设备型号Product以及布局类型等信息格式通常为
Vendor_XXX_Product_XXX.klVendor代表设备的制造商或供应商。通常是一个厂商的标识符或名称的缩写。 Product代表具体的硬件产品型号。这个部分通常与设备的具体型号相关联帮助区分不同的硬件设备。例如
某个厂商制造了一个键盘设备厂商ID为 abcd产品ID为 efgh则键盘布局文件的命名可能是 Vendor_abcd_Product_efgh.kl
除了基本的 Vendor、Product 形式外一些设备可能会使用其他的命名约定来包含更多的信息例如
Vendor_1234_Product_5678_Layout1.kl可能表示设备 5678 的布局1。 Vendor_1234_Product_5678_Pro.kl可能表示设备 5678 的专业版布局。
目录和位置 这些 .kl 文件通常存放在Android设备的系统目录中例如 /system/usr/keylayout/。系统会根据这些文件的定义来正确处理与物理键盘相关的输入事件。
文件内容 .kl 文件的内容包括键位定义和映射和Generic.kl语法一致
如果没有可用的设备专属kl文件则系统将使用默认Generic.kl文件。
7.加载流程
kl文件的加载流程主要是在EventHub.cpp里的openDeviceLocked()方法里进行的
frameworks/native/services/inputflinger/reader/EventHub.cpp
void EventHub::openDeviceLocked(const std::string devicePath) {......// Load the key map.// We need to do this for joysticks too because the key layout may specify axes, and for// sensor as well because the key layout may specify the axes to sensor data mapping.status_t keyMapStatus NAME_NOT_FOUND;if (device-classes.any(InputDeviceClass::KEYBOARD | InputDeviceClass::JOYSTICK |InputDeviceClass::SENSOR)) {// Load the keymap for the device.keyMapStatus device-loadKeyMapLocked();}......
}调用loadKeyMapLocked()方法继续加载
frameworks/native/services/inputflinger/reader/EventHub.cpp
status_t EventHub::Device::loadKeyMapLocked() {return keyMap.load(identifier, configuration.get());
} 调用frameworks/native/libs/input/Keyboard.cpp里的load方法用来加载和配置键盘映射
frameworks/native/libs/input/Keyboard.cpp
status_t KeyMap::load(const InputDeviceIdentifier deviceIdentifier,const PropertyMap* deviceConfiguration) {// Use the configured key layout if available.if (deviceConfiguration) {//如果.idc文件里有指定使用的kl文件则首先加载指定的文件std::optionalstd::string keyLayoutName deviceConfiguration-getString(keyboard.layout);//根据keyboard.layout字段来获取指定的.kl文件if (keyLayoutName.has_value()) {//如果存在指定的kl文件status_t status loadKeyLayout(deviceIdentifier, *keyLayoutName);//加载键盘布局if (status NAME_NOT_FOUND) {//未找到对应名称的kl文件ALOGE(Configuration for keyboard device %s requested keyboard layout %s but it was not found.,deviceIdentifier.name.c_str(), keyLayoutName-c_str());}}std::optionalstd::string keyCharacterMapName deviceConfiguration-getString(keyboard.characterMap);//根据keyboard.characterMap字段来获取字符映射表的名称一般是以.kcm结尾的文件if (keyCharacterMapName.has_value()) {status_t status loadKeyCharacterMap(deviceIdentifier, *keyCharacterMapName);//加载kcm文件。if (status NAME_NOT_FOUND) {//未找到对应名称字符映射表ALOGE(Configuration for keyboard device %s requested keyboard character map %s but it was not found.,deviceIdentifier.name.c_str(), keyCharacterMapName-c_str());}}if (isComplete()) {//加载完成之后返回return OK;}}// Try searching by device identifier.if (probeKeyMap(deviceIdentifier, )) {//通过设备标识符查找键盘映射即查找对应目录下是否有自定义的kl文件return OK;}// Fall back on the Generic key map.// TODO Apply some additional heuristics here to figure out what kind of// generic key map to use (US English, etc.) for typical external keyboards.if (probeKeyMap(deviceIdentifier, Generic)) {//如果没有找到合适的kl文件返回Generic.kl文件return OK;}// Try the Virtual key map as a last resort.if (probeKeyMap(deviceIdentifier, Virtual)) {//查找虚拟键盘return OK;}// Give up!ALOGE(Could not determine key map for device %s and no default key maps were found!,deviceIdentifier.name.c_str());return NAME_NOT_FOUND;//以上方式都找不到kl文件查找失败
}
可以看出kl文件的加载遵循以下顺序
1如果.idc文件里keyboard.layout何keyboard.characterMap有指定使用的kl、kcm文件则首先加载指定的kl、kcm文件
2如果.idc文件里没有配置指定的kl文件那么通过设备信息去查找kl文件一般为Vendor_XXX_Product_XXX(_Version_XXX).kl文件
3如果上述两种情况都没有找到kl文件那么加载默认的Generic.kl文件
4最后尝试加载虚拟键盘映射表