Scancode到Keycode的映射
之前分析的InputReader讀取底層事件可以得知 InputReaderThead啟動之后會通過mEventHub->getEvents讀取設備節點的所有事件,通過parsekey方法解析kl文件存入數據結構map,在讀取節點事件之前先掃描設備,如果沒有打開則打開設備,在打開設備時會將scancode和keycode一一映射,此篇文章記錄他們是如何建立映射關系的起來的
/frameworks/native/services/inputflinger/InputReader.cpp
/frameworks/native/services/inputflinger/EventHub.cpp
mEventHub->getEvents
/frameworks/native/services/inputflinger/EventHub.cpp
掃描設備"/dev/input"
打開設備
1237 status_t EventHub::openDeviceLocked(const char* devicePath) { 1238 //省略了很多代碼,主要看loadKeyMapLocked 1258 ...... 1350 ...... 1429 // Load the key map. 1430 // We need to do this for joysticks too because the key layout may specify axes. 1431 status_t keyMapStatus = NAME_NOT_FOUND; 1432 if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) { 1433 // Load the keymap for the device. 1434 keyMapStatus = loadKeyMapLocked(device); 1435 } }主要看scancode和keycode如何一一映射的
1685 status_t EventHub::loadKeyMapLocked(Device* device) { 1686 return device->keyMap.load(device->identifier, device->configuration); 1687 }繼續調到Device的keyMap的load函數,Device是EventHub內部的結構體
/frameworks/native/services/inputflinger/EventHub.h
繼續看KeyMap的load函數
/frameworks/native/libs/input/Keyboard.cpp
可以看到我這個設備有四個設備節點,所以
mtk-tpd,ACCDET,fts_ts,mtk-kpd以及通用表都會解析的
probeKeyMap函數
95 bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, 96 const std::string& keyMapName) { 97 if (!haveKeyLayout()) { 98 loadKeyLayout(deviceIdentifier, keyMapName); 99 } 100 if (!haveKeyCharacterMap()) { 101 loadKeyCharacterMap(deviceIdentifier, keyMapName); 102 } 103 return isComplete(); 104 }loadKeyLayout()函數
106 status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, 107 const std::string& name) { 108 std::string path(getPath(deviceIdentifier, name, 109 INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT)); 110 if (path.empty()) { 111 return NAME_NOT_FOUND; 112 } 113 114 status_t status = KeyLayoutMap::load(path, &keyLayoutMap); 115 if (status) { 116 return status; 117 } 118 119 keyLayoutFile = path; 120 return OK; 121 }繼續KeyLayoutMap::load
/frameworks/native/libs/input/KeyLayoutMap.cpp
繼續parser.parse(),開始解析映射表
199 status_t KeyLayoutMap::Parser::parse() {//while循環,一行一行地解析映射表項 200 while (!mTokenizer->isEof()) { 201 #if DEBUG_PARSER/*11-22 04:27:06.719 908 1162 D KeyLayoutMap: Parsing /system/usr/keylayout/Generic.kl:160: '# key 138 "KEY_HELP"'. 11-22 04:27:06.719 908 1162 D KeyLayoutMap: Parsing /system/usr/keylayout/Generic.kl:161: 'key 139 MENU'. 11-22 04:27:06.719 908 1162 D KeyLayoutMap: Parsing /system/usr/keylayout/Generic.kl:151: '# key 129 "KEY_AGAIN"'. 11-22 04:27:06.719 908 1162 D KeyLayoutMap: Parsing /system/usr/keylayout/Generic.kl:152: '# key 130 "KEY_PROPS"'. 11-22 04:27:06.719 908 1162 D KeyLayoutMap: Parsing /system/usr/keylayout/Generic.kl:153: '# key 131 "KEY_UNDO"'. 11-22 04:27:06.719 908 1162 D KeyLayoutMap: Parsing /system/usr/keylayout/Generic.kl:154: '# key 132 "KEY_FRONT"'.*///這條log的輸入,部分 202 ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), 203 mTokenizer->peekRemainderOfLine().string()); 204 #endif 206 mTokenizer->skipDelimiters(WHITESPACE); 208 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { 209 String8 keywordToken = mTokenizer->nextToken(WHITESPACE); 210 if (keywordToken == "key") { 211 mTokenizer->skipDelimiters(WHITESPACE); 212 status_t status = parseKey(); 213 if (status) return status; 214 } else if (keywordToken == "axis") { 215 mTokenizer->skipDelimiters(WHITESPACE); 216 status_t status = parseAxis(); 217 if (status) return status; 218 } else if (keywordToken == "led") { 219 mTokenizer->skipDelimiters(WHITESPACE); 220 status_t status = parseLed(); 221 if (status) return status; 222 } else { 223 ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(), 224 keywordToken.string()); 225 return BAD_VALUE; 226 } 227 228 mTokenizer->skipDelimiters(WHITESPACE); 229 if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { 230 ALOGE("%s: Expected end of line or trailing comment, got '%s'.", 231 mTokenizer->getLocation().string(), 232 mTokenizer->peekRemainderOfLine().string()); 233 return BAD_VALUE; 234 } 235 } 237 mTokenizer->nextLine(); 238 } 239 return NO_ERROR; 240 }mTokenizer->getLocation()這代表哪一張映射表,mTokenizer->peekRemainderOfLine()代表映射表中的scancode,
解析的規則如下:
keyword是"key",調用parseKey解析,如果解析出錯則返回錯誤
keyword是"axis",調用parseAxis解析,如果解析出錯則返回錯誤
keyword是"led",調用parseAxis解析,如果解析出錯則返回錯誤
如果還有其他不按規則的符號則返回BAD_VALUE
繼續parseKey()函數
242 status_t KeyLayoutMap::Parser::parseKey() { 243 ...... 256 //此函數解析得到keycode 267 int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string()); 268 ......//11-22 04:55:50.301 852 1162 D KeyLayoutMap: Parsed key scan code: code=85, keyCode=211, flags=0x00000000. 294 #if DEBUG_PARSER 295 ALOGD("Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.", 296 mapUsage ? "usage" : "scan code", code, keyCode, flags); 297 #endif 298 Key key; 299 key.keyCode = keyCode; 300 key.flags = flags; 301 map.add(code, key); 302 return NO_ERROR; 303 }打開上面的log開關得到如下輸出:scancode和keycode的映射終于得到了,繼續看函數getKeyCodeByLabel
11-22 04:55:50.301 852 1162 D KeyLayoutMap: Parsed key scan code: code=83, keyCode=158, flags=0x00000000. 11-22 04:55:50.301 852 1162 D KeyLayoutMap: Parsed key scan code: code=85, keyCode=211, flags=0x00000000. 11-22 04:55:50.306 852 1162 D KeyLayoutMap: Parsed key scan code: code=173, keyCode=285, flags=0x00000000. 11-22 04:55:50.316 852 1162 D KeyLayoutMap: Parsed key scan code: code=483, keyCode=47, flags=0x00000004./frameworks/native/include/input/InputEventLabels.h
434 static inline int32_t getKeyCodeByLabel(const char* label) { 435 return int32_t(lookupValueByLabel(label, KEYCODES)); 436 }調用了lookupValueByLabel函數,我們來看 KEYCODES是什么,里面是所有的鍵
23 #define DEFINE_KEYCODE(key) { #key, AKEYCODE_##key } 39 static const InputEventLabel KEYCODES[] = { 40 // NOTE: If you add a new keycode here you must also add it to several other files. 41 // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. 44 ...... 45 DEFINE_KEYCODE(HOME), 46 DEFINE_KEYCODE(BACK), 47 DEFINE_KEYCODE(CALL), 48 DEFINE_KEYCODE(ENDCALL), 49 DEFINE_KEYCODE(0), 50 DEFINE_KEYCODE(1), 51 DEFINE_KEYCODE(2), 52 DEFINE_KEYCODE(3), 53 DEFINE_KEYCODE(4), 54 DEFINE_KEYCODE(5), 55 DEFINE_KEYCODE(6), 56 DEFINE_KEYCODE(7), 57 DEFINE_KEYCODE(8), 58 DEFINE_KEYCODE(9), 59 DEFINE_KEYCODE(STAR), 60 DEFINE_KEYCODE(POUND), 61 DEFINE_KEYCODE(DPAD_UP), 62 DEFINE_KEYCODE(DPAD_DOWN), 63 DEFINE_KEYCODE(DPAD_LEFT), 64 DEFINE_KEYCODE(DPAD_RIGHT), 65 DEFINE_KEYCODE(DPAD_CENTER), 66 DEFINE_KEYCODE(VOLUME_UP), 67 DEFINE_KEYCODE(VOLUME_DOWN), 68 DEFINE_KEYCODE(POWER), 69 DEFINE_KEYCODE(CAMERA), 70 DEFINE_KEYCODE(CLEAR),......DEFINE_KEYCODE這個宏定義作用是將傳進去的鍵名稱拼接為AKEYCODE_XXX,比如我們傳一個POWER進去得到的就是{ “POWER”, AKEYCODE_POWER }
而AKEYCODE_POWER,我們全局搜索一下,可以發現定義在
/frameworks/native/include/android/keycodes.h
并且在java層也是用的映射的keycode,這都是和native層一致的
frameworks/base/core/java/android/view/KeyEvent.java
到這里scancode與keycode的映射就創建完成,
用一個實際例子來總結一下映射關系
16進制74對應10進制116,按鍵名稱POWER,經過scancode到keycode的映射,POWER事件傳到native層變為了AKEYCODE_POWER,到java層變為了KEYCODE_POWER,keycode都一樣等于26,到此底層對上層事件的映射就已經完成,之后會接著InputReader讀取設備事件,分析InputDispatcher是如何將事件給到應用窗口的。
總結
以上是生活随笔為你收集整理的Scancode到Keycode的映射的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: import 下划线作用
- 下一篇: Object Detection : O