Scancode到Keycode的映射
之前分析的InputReader讀取底層事件可以得知 InputReaderThead啟動(dòng)之后會(huì)通過(guò)mEventHub->getEvents讀取設(shè)備節(jié)點(diǎn)的所有事件,通過(guò)parsekey方法解析kl文件存入數(shù)據(jù)結(jié)構(gòu)map,在讀取節(jié)點(diǎn)事件之前先掃描設(shè)備,如果沒(méi)有打開(kāi)則打開(kāi)設(shè)備,在打開(kāi)設(shè)備時(shí)會(huì)將scancode和keycode一一映射,此篇文章記錄他們是如何建立映射關(guān)系的起來(lái)的
/frameworks/native/services/inputflinger/InputReader.cpp
/frameworks/native/services/inputflinger/EventHub.cpp
mEventHub->getEvents
/frameworks/native/services/inputflinger/EventHub.cpp
掃描設(shè)備"/dev/input"
打開(kāi)設(shè)備
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 }繼續(xù)調(diào)到Device的keyMap的load函數(shù),Device是EventHub內(nèi)部的結(jié)構(gòu)體
/frameworks/native/services/inputflinger/EventHub.h
繼續(xù)看KeyMap的load函數(shù)
/frameworks/native/libs/input/Keyboard.cpp
可以看到我這個(gè)設(shè)備有四個(gè)設(shè)備節(jié)點(diǎn),所以
mtk-tpd,ACCDET,fts_ts,mtk-kpd以及通用表都會(huì)解析的
probeKeyMap函數(shù)
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()函數(shù)
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 }繼續(xù)KeyLayoutMap::load
/frameworks/native/libs/input/KeyLayoutMap.cpp
繼續(xù)parser.parse(),開(kāi)始解析映射表
199 status_t KeyLayoutMap::Parser::parse() {//while循環(huán),一行一行地解析映射表項(xiàng) 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,
解析的規(guī)則如下:
keyword是"key",調(diào)用parseKey解析,如果解析出錯(cuò)則返回錯(cuò)誤
keyword是"axis",調(diào)用parseAxis解析,如果解析出錯(cuò)則返回錯(cuò)誤
keyword是"led",調(diào)用parseAxis解析,如果解析出錯(cuò)則返回錯(cuò)誤
如果還有其他不按規(guī)則的符號(hào)則返回BAD_VALUE
繼續(xù)parseKey()函數(shù)
242 status_t KeyLayoutMap::Parser::parseKey() { 243 ...... 256 //此函數(shù)解析得到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 }打開(kāi)上面的log開(kāi)關(guān)得到如下輸出:scancode和keycode的映射終于得到了,繼續(xù)看函數(shù)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 }調(diào)用了lookupValueByLabel函數(shù),我們來(lái)看 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這個(gè)宏定義作用是將傳進(jìn)去的鍵名稱拼接為AKEYCODE_XXX,比如我們傳一個(gè)POWER進(jìn)去得到的就是{ “POWER”, AKEYCODE_POWER }
而AKEYCODE_POWER,我們?nèi)炙阉饕幌?#xff0c;可以發(fā)現(xiàn)定義在
/frameworks/native/include/android/keycodes.h
并且在java層也是用的映射的keycode,這都是和native層一致的
frameworks/base/core/java/android/view/KeyEvent.java
到這里scancode與keycode的映射就創(chuàng)建完成,
用一個(gè)實(shí)際例子來(lái)總結(jié)一下映射關(guān)系
16進(jìn)制74對(duì)應(yīng)10進(jìn)制116,按鍵名稱POWER,經(jīng)過(guò)scancode到keycode的映射,POWER事件傳到native層變?yōu)榱薃KEYCODE_POWER,到j(luò)ava層變?yōu)榱薑EYCODE_POWER,keycode都一樣等于26,到此底層對(duì)上層事件的映射就已經(jīng)完成,之后會(huì)接著InputReader讀取設(shè)備事件,分析InputDispatcher是如何將事件給到應(yīng)用窗口的。
總結(jié)
以上是生活随笔為你收集整理的Scancode到Keycode的映射的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: import 下划线作用
- 下一篇: Object Detection : O