Android10 (.kl)按键布局文件的解析过程分析

.kl文件

简述

  kl文件也就是keylayout文件,它的作用是将Linux scancode转换为Android keycode。scancode就是硬件直接扫描到的数字,而这些数字会通过这个kl文件对应到字符串,也就是keycode。
  设备可以拥有自己专属的kl文件,命名规则和idc文件一样,这里就不重复说了。另外系统提供了一个特殊的内置常规按键布局文件,名为 Generic.kl。当找不到专属的kl时候就会用Generic.kl

示例

  下面示例是Generic.kl中一些键值对类型。当然设备的专属kl文件并不需要包含下方的所有类型,只需要包含会用到的就可以了

/odm/usr/keylayout/Generic.kl
/vendor/usr/keylayout/Generic.kl
/system/usr/keylayout/Generic.kl
/data/system/devices/keylayout/Generic.kl
# 键盘
key 1     ESCAPE
key 2     1
key 3     2
key 12    MINUS
key 13    EQUALS
key 14    DEL

# 系统控件
key 114   VOLUME_DOWN
key 115   VOLUME_UP
key 116   POWER

#电容式按钮
key 139    MENU           VIRTUAL
key 172    HOME           VIRTUAL
key 158    BACK           VIRTUAL
key 217    SEARCH         VIRTUAL

#耳机插孔媒体控件
key 163   MEDIA_NEXT
key 165   MEDIA_PREVIOUS
key 226   HEADSETHOOK

#操纵杆
key 304   BUTTON_A
key 305   BUTTON_B
key 307   BUTTON_X
key 308   BUTTON_Y

# Keys defined by HID usages
key usage 0x0c006F BRIGHTNESS_UP
key usage 0x0c0070 BRIGHTNESS_DOWN

EventHub::openDeviceLocked

  这个过程和加载idc一样也是从openDeviceLocked开始的,调用loadKeyMapLocked() 加载Kl文件

status_t EventHub::openDeviceLocked(const char* devicePath) {
   
    char buffer[80];
   
    // devicePath = /dev/input/eventx
    int fd = open(devicePath, O_RDWR | O_CLOEXEC | O_NONBLOCK);
    InputDeviceIdentifier identifier;
    ...

    // Load the key map.
    // We need to do this for joysticks too because the key layout may specify axes.
    status_t keyMapStatus = NAME_NOT_FOUND;
    if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) {
   
        // Load the keymap for the device.
        keyMapStatus = loadKeyMapLocked(device);
    }
    ...
    return OK;
}

  loadKeyMapLocked就直接调用keyMap.load了

status_t EventHub::loadKeyMapLocked(Device* device) {
   
    return device->keyMap.load(device->identifier, device->configuration);
}

KeyMap::load

  还记得我们之前解析idc文件的时候有去解析"keyboard.layout"和"keyboard.characterMap"这两项吗,在这个函数开头我们就是判断在该设备的idc文件中有没有指定kl和kcm文件,如果有的话我们就用idc文件中指定的,如果没有我们再通过probeKeyMap() 去各个目录下查找
  查找的话我们会先通过设备标识符去找它专属的kl文件,找不到就去找Generic,虽然有个最后的选择虚拟键盘映射,不过并不会用到它,因为Generic.kl总是存在的

\frameworks\native\libs\input\Keyboard.cpp
status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier,
        const PropertyMap* deviceConfiguration) {
   
    // Use the configured key layout if available.
    if (deviceConfiguration) {
   
        String8 keyLayoutName;
        if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
                keyLayoutName)) {
   
            status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName.c_str());
            if (status == NAME_NOT_FOUND) {
   
                ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
                        "it was not found.",
                        deviceIdenfifier.name.c_str(), keyLayoutName.string());
            }
        }

        String8 keyCharacterMapName;
        if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
                keyCharacterMapName)) {
   
            status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName.c_str());
            if (status == NAME_NOT_FOUND) {
   
                ALOGE("Configuration for keyboard device '%s' requested keyboard character "
                        "map '%s' but it was not found.",
                        deviceIdenfifier.name.c_str(), keyLayoutName.string());
            }
        }

        if (isComplete()) {
   
            return OK;
        }
    }

    // Try searching by device identifier.
    if (probeKeyMap(deviceIdenfifier, "")) {
   
        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(deviceIdenfifier, "Generic")) {
   
        return OK;
    }

    // Try the Virtual key map as a last resort.
    if (probeKeyMap(deviceIdenfifier, "Virtual")) {
   
        return OK;
    }

    // Give up!
    ALOGE("Could not determine key map for device '%s' and no default key maps were found!",
            deviceIdenfifier.name.c_str());
    return NAME_NOT_FOUND;
}

KeyMap::probeKeyMap

  接下来看一下probeKeyMap() 的实现,它会分别去加载kl和kcm文件

bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier,
        const std::string& keyMapName) {
   
    if (!haveKeyLayout()) {
   
        loadKeyLayout(deviceIdentifier, keyMapName);
    }
    if (!haveKeyCharacterMap()) {
   
        loadKeyCharacterMap(deviceIdentifier
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值