平台 内核版本 安卓版本
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. Android Studio 中 layout 目录分类
  2. 〖Android〗Android App项目资源字符串检查(检查是否缺少对应的翻
  3. Android - 文件读写操作总结
  4. android 开发 文件读写应用案例分析
  5. [置顶] Android目录(更新中)
  6. android 资源文件命名规则 drawable mipmap一样的
  7. android判断文件类型是否为音频文件

随机推荐

  1. Android(安卓)快速打包工具(真的很快)
  2. 新版本Android(安卓)SDK 找不到adb.exe的
  3. Android中实现照片滑动时左右进出的动画
  4. android fragment 标签使用
  5. 纯色titlebar抗遮挡布局的实现
  6. Android(安卓)Studio实现简单的登陆界面
  7. Android(安卓)SurfaceFlinger 学习之路(
  8. Android(安卓)mvparms 踩坑
  9. Android内存分析AndroidStudio的运用
  10. Android(安卓)Camera从App层到framework