[Hi3751V811][Android8.0]系统按键的转换 - android键值的映射
平台 | 内核版本 | 安卓版本 |
---|---|---|
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...
定义<键名>字符串和android
的java
层键值对应关系
文件目录:/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, ...}
定位linux
到android
键转换映射文件
文件目录:hisi/android/frameworks/native/libs/input/Keyboard.cpp
- 提供函数
loadKeyLayout
和getPath
,定位linux
到android
键第一转换映射文件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
得到linux
层code
:
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;}
查询返回android
的java
键值
文件目录: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;}
更多相关文章
- Android Studio 中 layout 目录分类
- 〖Android〗Android App项目资源字符串检查(检查是否缺少对应的翻
- Android - 文件读写操作总结
- android 开发 文件读写应用案例分析
- [置顶] Android目录(更新中)
- android 资源文件命名规则 drawable mipmap一样的
- android判断文件类型是否为音频文件