Scancode到Keycode的映射
之前分析的InputReader读取底层事件可以得知 InputReaderThead启动之后会通过mEventHub->getEvents读取设备节点的所有事件,通过parsekey方法解析kl文件存入数据结构map,在读取节点事件之前先扫描设备,如果没有打开则打开设备,在打开设备时会将scancode和keycode一一映射,此篇文章记录他们是如何建立映射关系的起来的 /frameworks/native/services/inputflinger/InputReader.cpp
void InputReader::loopOnce() {
......
343 size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
344
345 { // acquire lock
346 AutoMutex _l(mLock);
347 mReaderIsAliveCondition.broadcast();
348
349 if (count) {
350 processEventsLocked(mEventBuffer, count);
351 }
352
/frameworks/native/services/inputflinger/EventHub.cpp
mEventHub->getEvents
851 size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
852 ......
860 bool awoken = false;
861 for (;;) {
862 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
......
875 // Report any devices that had last been added/removed.
876 while (mClosingDevices) {
877 Device* device = mClosingDevices;
878 ALOGV("Reporting device closed: id=%d, name=%s\n",
879 device->id, device->path.c_str());
880 ......
891 }
892
893 if (mNeedToScanDevices) {
894 mNeedToScanDevices = false;
895 scanDevicesLocked();
896 mNeedToSendFinishedDeviceScan = true;
897 }
......
}
/frameworks/native/services/inputflinger/EventHub.cpp
扫描设备"/dev/input"
static const char *DEVICE_PATH = "/dev/input";
1130 void EventHub::scanDevicesLocked() {
//DEVICE_PATH = "/dev/input"
1131 status_t result = scanDirLocked(DEVICE_PATH);
1132 ......
1144 }
1908 status_t EventHub::scanDirLocked(const char *dirname)
1909 {
1910 ......
//扫描/dev/input/下的所有设备
1920 while((de = readdir(dir))) {
1921 if(de->d_name[0] == '.' &&
1922 (de->d_name[1] == '\0' ||
1923 (de->d_name[1] == '.' && de->d_name[2] == '\0')))
1924 continue;
1925 strcpy(filename, de->d_name);
//打开设备
1926 openDeviceLocked(devname);
1927 }
1928 closedir(dir);
1929 return 0;
1930 }
打开设备
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
41 status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier,
42 const PropertyMap* deviceConfiguration) {
43 // Use the configured key layout if available.
44 if (deviceConfiguration) {
45 String8 keyLayoutName;
//通过设备的配置文件去加载配置文件内制定好的映射表
46 if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
47 keyLayoutName)) {
48 status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName.c_str());
49 if (status == NAME_NOT_FOUND) {
52 deviceIdenfifier.name.c_str(), keyLayoutName.string());
53 }
54 }
55
56 String8 keyCharacterMapName;
57 if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
58 keyCharacterMapName)) {
59 status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName.c_str());
60 if (status == NAME_NOT_FOUND) {
61 ALOGE("Configuration for keyboard device '%s' requested keyboard character "
62 "map '%s' but it was not found.",
63 deviceIdenfifier.name.c_str(), keyLayoutName.string());
64 }
65 }
67 if (isComplete()) {
68 return OK;
69 }
70 }
72 // Try searching by device identifier.通过设备信息查找对应的映射表
73 if (probeKeyMap(deviceIdenfifier, "")) {
74 return OK;
75 }
77 // Fall back on the Generic key map.
78 // TODO Apply some additional heuristics here to figure out what kind of
79 // generic key map to use (US English, etc.) for typical external keyboards.查找通用的映射表
80 if (probeKeyMap(deviceIdenfifier, "Generic")) {
81 return OK;
82 }
83
84 // Try the Virtual key map as a last resort.查找虚拟映射表
85 if (probeKeyMap(deviceIdenfifier, "Virtual")) {
86 return OK;
87 }
88
89 // Give up!
90 ALOGE("Could not determine key map for device '%s' and no default key maps were found!",
91 deviceIdenfifier.name.c_str());
92 return NAME_NOT_FOUND;
93 }
可以看到我这个设备有四个设备节点,所以
mtk-tpd,ACCDET,fts_ts,mtk-kpd以及通用表都会解析的
Tokyo_TF:/system/usr $ getevent
add device 1: /dev/input/event3
name: "mtk-tpd"
add device 2: /dev/input/event0
name: "ACCDET"
add device 3: /dev/input/event1
name: "mtk-kpd"
add device 4: /dev/input/event2
name: "fts_ts"
/dev/input/event1: 0001 0074 00000001
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0001 0074 00000000
/dev/input/event1: 0000 0000 00000000
Tokyo_TF:/system/usr $
Tokyo_TF:/system/usr $ find -name "mtk-kpd*"
./keylayout/mtk-kpd.kl
Tokyo_TF:/system/usr $
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
52 status_t KeyLayoutMap::load(const std::string& filename, sp<KeyLayoutMap>* outMap) {
54 ......
55 Tokenizer* tokenizer;
56 status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
57 if (status) {
58 ......
59 } else {
60 sp<KeyLayoutMap> map = new KeyLayoutMap();
61 if (!map.get()) {
62 ......
64 } else {
68 Parser parser(map.get(), tokenizer);
//解析map
69 status = parser.parse();
70 ......
82 return status;
83 }
继续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
51 /**
52 * Key codes.
53 */
54 enum {
55 /** Unknown key code. */
56 AKEYCODE_UNKNOWN = 0,
57 /** Soft Left key.
58 * Usually situated below the display on phones and used as a multi-function
59 * feature key for selecting a software defined function shown on the bottom left
60 * of the display. */
61 AKEYCODE_SOFT_LEFT = 1,
62 /** Soft Right key.
63 * Usually situated below the display on phones and used as a multi-function
64 * feature key for selecting a software defined function shown on the bottom right
65 * of the display. */
66 AKEYCODE_SOFT_RIGHT = 2,
67 /** Home key.
68 * This key is handled by the framework and is never delivered to applications. */
69 AKEYCODE_HOME = 3,
70 /** Back key. */
71 AKEYCODE_BACK = 4,
72 /** Call key. */
73 AKEYCODE_CALL = 5,
74 /** End Call key. */
75 AKEYCODE_ENDCALL = 6,
76 /** '0' key. */
77 AKEYCODE_0 = 7,
78 /** '1' key. */
79 AKEYCODE_1 = 8,
80 /** '2' key. */
81 AKEYCODE_2 = 9,
82 /** '3' key. */
83 AKEYCODE_3 = 10,
84 /** '4' key. */
85 AKEYCODE_4 = 11,
86 /** '5' key. */
87 AKEYCODE_5 = 12,
88 /** '6' key. */
89 AKEYCODE_6 = 13,
90 /** '7' key. */
91 AKEYCODE_7 = 14,
92 /** '8' key. */
93 AKEYCODE_8 = 15,
94 /** '9' key. */
95 AKEYCODE_9 = 16,
96 /** '*' key. */
97 AKEYCODE_STAR = 17,
98 /** '#' key. */
99 AKEYCODE_POUND = 18,
100 /** Directional Pad Up key.
101 * May also be synthesized from trackball motions. */
102 AKEYCODE_DPAD_UP = 19,
103 /** Directional Pad Down key.
104 * May also be synthesized from trackball motions. */
105 AKEYCODE_DPAD_DOWN = 20,
106 /** Directional Pad Left key.
107 * May also be synthesized from trackball motions. */
108 AKEYCODE_DPAD_LEFT = 21,
109 /** Directional Pad Right key.
110 * May also be synthesized from trackball motions. */
111 AKEYCODE_DPAD_RIGHT = 22,
112 /** Directional Pad Center key.
113 * May also be synthesized from trackball motions. */
114 AKEYCODE_DPAD_CENTER = 23,
115 /** Volume Up key.
116 * Adjusts the speaker volume up. */
117 AKEYCODE_VOLUME_UP = 24,
118 /** Volume Down key.
119 * Adjusts the speaker volume down. */
120 AKEYCODE_VOLUME_DOWN = 25,
121 /** Power key. */
122 AKEYCODE_POWER = 26,
......
}
并且在java层也是用的映射的keycode,这都是和native层一致的
frameworks/base/core/java/android/view/KeyEvent.java
88 public class KeyEvent extends InputEvent implements Parcelable {
89 /** Key code constant: Unknown key code. */
90 public static final int KEYCODE_UNKNOWN = 0;
91 /** Key code constant: Soft Left key.
92 * Usually situated below the display on phones and used as a multi-function
93 * feature key for selecting a software defined function shown on the bottom left
94 * of the display. */
95 public static final int KEYCODE_SOFT_LEFT = 1;
96 /** Key code constant: Soft Right key.
97 * Usually situated below the display on phones and used as a multi-function
98 * feature key for selecting a software defined function shown on the bottom right
99 * of the display. */
100 public static final int KEYCODE_SOFT_RIGHT = 2;
101 /** Key code constant: Home key.
102 * This key is handled by the framework and is never delivered to applications. */
103 public static final int KEYCODE_HOME = 3;
104 /** Key code constant: Back key. */
105 public static final int KEYCODE_BACK = 4;
106 /** Key code constant: Call key. */
107 public static final int KEYCODE_CALL = 5;
108 /** Key code constant: End Call key. */
109 public static final int KEYCODE_ENDCALL = 6;
110 /** Key code constant: '0' key. */
111 public static final int KEYCODE_0 = 7;
112 /** Key code constant: '1' key. */
113 public static final int KEYCODE_1 = 8;
114 /** Key code constant: '2' key. */
115 public static final int KEYCODE_2 = 9;
116 /** Key code constant: '3' key. */
117 public static final int KEYCODE_3 = 10;
118 /** Key code constant: '4' key. */
119 public static final int KEYCODE_4 = 11;
120 /** Key code constant: '5' key. */
121 public static final int KEYCODE_5 = 12;
122 /** Key code constant: '6' key. */
123 public static final int KEYCODE_6 = 13;
124 /** Key code constant: '7' key. */
125 public static final int KEYCODE_7 = 14;
126 /** Key code constant: '8' key. */
127 public static final int KEYCODE_8 = 15;
128 /** Key code constant: '9' key. */
129 public static final int KEYCODE_9 = 16;
130 /** Key code constant: '*' key. */
131 public static final int KEYCODE_STAR = 17;
132 /** Key code constant: '#' key. */
133 public static final int KEYCODE_POUND = 18;
134 /** Key code constant: Directional Pad Up key.
135 * May also be synthesized from trackball motions. */
136 public static final int KEYCODE_DPAD_UP = 19;
137 /** Key code constant: Directional Pad Down key.
138 * May also be synthesized from trackball motions. */
139 public static final int KEYCODE_DPAD_DOWN = 20;
140 /** Key code constant: Directional Pad Left key.
141 * May also be synthesized from trackball motions. */
142 public static final int KEYCODE_DPAD_LEFT = 21;
143 /** Key code constant: Directional Pad Right key.
144 * May also be synthesized from trackball motions. */
145 public static final int KEYCODE_DPAD_RIGHT = 22;
146 /** Key code constant: Directional Pad Center key.
147 * May also be synthesized from trackball motions. */
148 public static final int KEYCODE_DPAD_CENTER = 23;
149 /** Key code constant: Volume Up key.
150 * Adjusts the speaker volume up. */
151 public static final int KEYCODE_VOLUME_UP = 24;
152 /** Key code constant: Volume Down key.
153 * Adjusts the speaker volume down. */
154 public static final int KEYCODE_VOLUME_DOWN = 25;
155 /** Key code constant: Power key. */
156 public static final int KEYCODE_POWER = 26;
......
}
到这里scancode与keycode的映射就创建完成,
用一个实际例子来总结一下映射关系
Tokyo_TF:/ $ getevent
add device 1: /dev/input/event3
name: "mtk-tpd"
add device 2: /dev/input/event0
name: "ACCDET"
add device 3: /dev/input/event1
name: "mtk-kpd"
add device 4: /dev/input/event2
name: "fts_ts"
/dev/input/event1: 0001 0074 00000001
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0001 0074 00000000
/dev/input/event1: 0000 0000 00000000
Tokyo_TF:/ $ cat system/usr/keylayout/mtk-kpd.kl |grep -i POWER
key 116 POWER
16进制74对应10进制116,按键名称POWER,经过scancode到keycode的映射,POWER事件传到native层变为了AKEYCODE_POWER,到java层变为了KEYCODE_POWER,keycode都一样等于26,到此底层对上层事件的映射就已经完成,之后会接着InputReader读取设备事件,分析InputDispatcher是如何将事件给到应用窗口的。