平台 内核版本 安卓版本
Hi3751V811 Linux4.1 Android8.0

系统键值是通用的,其知识点是通用的,因此通过本次学习可以举一反三。

文章目录

    • getEvents
    • 定义 linux 键值和对应的键名字符串
    • 定义<键名>字符串和`android`的`java`层键值对应关系
    • 定位`linux`到`android`键转换映射文件
    • 查询返回`android`的`java`键值

getEvents

首先getEvents:
文件目录:android/frameworks/native/services/inputflinger/EventHub.cpp

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
getEvents()->scanDevicesLocked()->scanDirLocked()->openDeviceLocked()->loadKeyMapLocked()->keyMap.load()->KeyMap::probeKeyMap->KeyMap::loadKeyLayout

定义 linux 键值和对应的键名字符串

文件目录:/android/device/hisilicon/bigfish/prebuilts/Vendor_0001_Product_0001.kl

...key 102   HOMEkey 103   DPAD_UPkey 104   PAGE_UPkey 105   DPAD_LEFTkey 106   DPAD_RIGHTkey 107   MOVE_END...

定义<键名>字符串和androidjava层键值对应关系

文件目录:/home/nova/hisi/android/frameworks/native/include/android/keycodes.h

/* * Key codes. */enum {    AKEYCODE_FOCUS           = 80,    /** '+' key. */    AKEYCODE_PLUS            = 81,    /** Menu key. */    AKEYCODE_MENU            = 82,    ...    AKEYCODE_MUTE            = 91,    /** Page Up key. */    AKEYCODE_PAGE_UP         = 92,    /** Page Down key. */    AKEYCODE_PAGE_DOWN       = 93,    ...}

定位linuxandroid键转换映射文件

文件目录:hisi/android/frameworks/native/libs/input/Keyboard.cpp

  • 提供函数loadKeyLayoutgetPath,定位linuxandroid键第一转换映射文件Vendor_0001_Product_0001.kl
status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,        const String8& name) {    String8 path(getPath(deviceIdentifier, name,            INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));    if (path.isEmpty()) {        return NAME_NOT_FOUND;    }    //打开    status_t status = KeyLayoutMap::load(path, &keyLayoutMap);    if (status) {        return status;    }    keyLayoutFile.setTo(path);    return OK;}

其中INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT为:/android/frameworks/native/include/input/InputDevice.h

/* Types of input device configuration files. */enum InputDeviceConfigurationFileType {    INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION = 0,     /* .idc file */    INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT = 1,        /* .kl file */    INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP = 2, /* .kcm file */};

如下:这里才确定path为:/system/usr/keylayout/Vendor_0001_Product_0001.kl

String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,        const String8& name, InputDeviceConfigurationFileType type) {    return name.isEmpty()            ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)            : getInputDeviceConfigurationFilePathByName(name, type);}

其中KeyLayoutMap::load加载并解析函数定义如下:
文件目录:android/frameworks/native/libs/input/KeyLayoutMap.cpp

status_t KeyLayoutMap::load(const String8& filename, sp<KeyLayoutMap>* outMap) {    outMap->clear();    Tokenizer* tokenizer;    status_t status = Tokenizer::open(filename, &tokenizer);    if (status) {        ALOGE("Error %d opening key layout map file %s.", status, filename.string());    } else {        sp<KeyLayoutMap> map = new KeyLayoutMap();        if (!map.get()) {            ALOGE("Error allocating key layout map.");            status = NO_MEMORY;        } else {#if DEBUG_PARSER_PERFORMANCE            nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);#endif            Parser parser(map.get(), tokenizer);            status = parser.parse();#if DEBUG_PARSER_PERFORMANCE            nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;            ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.",                    tokenizer->getFilename().string(), tokenizer->getLineNumber(),                    elapsedTime / 1000000.0);#endif            if (!status) {                *outMap = map;            }        }        delete tokenizer;    }    return status;}

其中重点:parser.parse()

status_t KeyLayoutMap::Parser::parse() {    while (!mTokenizer->isEof()) {#if DEBUG_PARSER        ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),                mTokenizer->peekRemainderOfLine().string());#endif        mTokenizer->skipDelimiters(WHITESPACE);        if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {            String8 keywordToken = mTokenizer->nextToken(WHITESPACE);            if (keywordToken == "key") {                mTokenizer->skipDelimiters(WHITESPACE);                status_t status = parseKey();                if (status) return status;            } else if (keywordToken == "axis") {                mTokenizer->skipDelimiters(WHITESPACE);                status_t status = parseAxis();                if (status) return status;            } else if (keywordToken == "led") {                mTokenizer->skipDelimiters(WHITESPACE);                status_t status = parseLed();                if (status) return status;            } else {                ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),                        keywordToken.string());                return BAD_VALUE;            }            mTokenizer->skipDelimiters(WHITESPACE);            if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {                ALOGE("%s: Expected end of line or trailing comment, got '%s'.",                        mTokenizer->getLocation().string(),                        mTokenizer->peekRemainderOfLine().string());                return BAD_VALUE;            }        }        mTokenizer->nextLine();    }    return NO_ERROR;}

其中重点parseKey()解析Vendor_0001_Product_0001.kl得到linuxcode:

status_t KeyLayoutMap::Parser::parseKey() {    String8 codeToken = mTokenizer->nextToken(WHITESPACE);    bool mapUsage = false;    if (codeToken == "usage") {        mapUsage = true;        mTokenizer->skipDelimiters(WHITESPACE);        codeToken = mTokenizer->nextToken(WHITESPACE);    }    char* end;    int32_t code = int32_t(strtol(codeToken.string(), &end, 0));    if (*end) {        ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),                mapUsage ? "usage" : "scan code", codeToken.string());        return BAD_VALUE;    }    KeyedVector<int32_t, Key>& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;    if (map.indexOfKey(code) >= 0) {        ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),                mapUsage ? "usage" : "scan code", codeToken.string());        return BAD_VALUE;    }    mTokenizer->skipDelimiters(WHITESPACE);    String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);    int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());    if (!keyCode) {        ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),                keyCodeToken.string());        return BAD_VALUE;    }    uint32_t flags = 0;    for (;;) {        mTokenizer->skipDelimiters(WHITESPACE);        if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break;        String8 flagToken = mTokenizer->nextToken(WHITESPACE);        uint32_t flag = getKeyFlagByLabel(flagToken.string());        if (!flag) {            ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(),                    flagToken.string());            return BAD_VALUE;        }        if (flags & flag) {            ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(),                    flagToken.string());            return BAD_VALUE;        }        flags |= flag;    }#if DEBUG_PARSER    ALOGD("Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.",            mapUsage ? "usage" : "scan code", code, keyCode, flags);#endif    Key key;    key.keyCode = keyCode;    key.flags = flags;    map.add(code, key);    return NO_ERROR;}

查询返回androidjava键值

文件目录:android/frameworks/native/include/input/InputEventLabels.h
提供函数getKeyCodeByLabel,查询code对应的android层键值keyCode

static inline int32_t getKeyCodeByLabel(const char* label) {    return int32_t(lookupValueByLabel(label, KEYCODES));}

其中调用lookupValueByLabel

static int lookupValueByLabel(const char* literal, const InputEventLabel *list) {    while (list->literal) {        if (strcmp(literal, list->literal) == 0) {            return list->value;        }        list++;    }    return list->value;}

可以看出此函数是查找的过程,查找对象就是我们的键值名,如下所示:

#define DEFINE_KEYCODE(key) { #key, AKEYCODE_##key }static const InputEventLabel KEYCODES[] = {    // NOTE: If you add a new keycode here you must also add it to several other files.    //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.    DEFINE_KEYCODE(UNKNOWN),    DEFINE_KEYCODE(SOFT_LEFT),    DEFINE_KEYCODE(SOFT_RIGHT),    DEFINE_KEYCODE(HOME),    DEFINE_KEYCODE(BACK),    ...    DEFINE_KEYCODE(MUTE),    DEFINE_KEYCODE(PAGE_UP),    DEFINE_KEYCODE(PAGE_DOWN),    DEFINE_KEYCODE(PICTSYMBOLS),    DEFINE_KEYCODE(SWITCH_CHARSET),    ... }    ......
static int lookupValueByLabel(const char* literal, const InputEventLabel *list) {    while (list->literal) {        if (strcmp(literal, list->literal) == 0) {            return list->value;        }        list++;    }    return list->value;}

更多相关文章

  1. 【Java CV与Android】在Android工程里配置JavaCV
  2. Android加密之文件级加密
  3. 如何监控android的流量信息
  4. Android(安卓)程序适应多种多分辨率
  5. 在Android上调用OpenCV 2.4.10库函数
  6. Android(安卓)Studio 中 layout 目录分类
  7. Android中String资源文件的format方法
  8. Android编译系统简要介绍和学习计划
  9. NPM 和webpack 的基础使用

随机推荐

  1. Qt on Android:图文详解QT开发Andriod入门
  2. Android仿今日头条详情页实现
  3. android中Timer+TimerTask+Handler配合,重
  4. Android(安卓)NDK开发(六)——使用开源LA
  5. GMTC分享——当插件化遇到 Android(安卓)
  6. Android(安卓)定时器
  7. Android事件总线分发库EventBus3.0的简单
  8. Android也创富:开发者月入1.3万美元
  9. 【Android(安卓)UI设计与开发】第05期:引
  10. Android之Volley