概述
映射表基本概念
由于Android调用getEvents得到的key是linux发送过来的scan code,而Android处理的是类似于KEY_UP这种统一类型的key code,因此需要有映射表把scan code转换成key code。映射表在板子上的位置是/system/usr/keylayout/xxx.kl,先看一下映射表是什么样子的,下面截选了一段。
key 2
1
key 3
2
key 4
3
key 5
4
key 6
5
key 7
6
key 8
7
key 9
8
key 10
9
key 11
0
key 28
DPAD_CENTER
key 102
HOME
key 103
DPAD_UP
WAKE_DROPPED
key 105
DPAD_LEFT
WAKE_DROPPED
key 106
DPAD_RIGHT
WAKE_DROPPED
key 108
DPAD_DOWN
WAKE_DROPPED
key 111
DEL
key 113
VOLUME_MUTE
key 114
VOLUME_DOWN
key 115
VOLUME_UP
key 116
POWER
可以看到每行都是一个映射项,映射项格式如下:
key [scan code] [key label] [flag label] [flag label] ...
- key是关键字,表明这个映射项是作为键值映射
- scan code是从linux device取得的键值
- key label是把scan code映射到key code中间的关键字,通过该关键字可以得到key code。
- flag label即按键的标记的关键字,通过flag label可以得到flag,一行映射项后面可以有多个flag label
从3和4可以知道,还有一个key label到key code的过程,以及flag label到flag的过程
另外,映射表是设备相关的。由于不同设备发送到Android的scan code可能会不同,因此每个设备需要用自身对应的映射表才能正确解析出key code。
映射表加载过程
1. 获取设备相关信息
在构造EventHub的时候,就决定了需要扫描输入设备。然后会在第一次getEvents进行一次扫描。
扫描输入设备主要有两个目的:
- 得到该设备的各种信息,如:设备名称,设备版本,设备产品码等,这些信息都可以作为该设备的标识。
- 知道该设备所发送事件的类型,如:按键事件,触控事件,滑动事件,开关事件,xy坐标等;通过所发送事件的类型,就能定位出设备的类型。
EventHub::EventHub(void) :
mNeedToScanDevices(true),
{...}
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
if (mNeedToScanDevices) {
mNeedToScanDevices = false;
scanDevicesLocked();
mNeedToSendFinishedDeviceScan = true;
}
}
void EventHub::scanDevicesLocked() {
status_t res = scanDirLocked(DEVICE_PATH);
if(res < 0) {
ALOGE("scan dir failed for %sn", DEVICE_PATH);
}
if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) {
createVirtualKeyboardLocked();
}
}
扫描的目录是/dev/input,linux中每加入一个输入设备,都会在该目录下创建设备文件。
status_t EventHub::scanDirLocked(const char *dirname)
{
char devname[PATH_MAX];
char *filename;
DIR *dir;
struct dirent *de;
dir = opendir(dirname);
if(dir == NULL)
return -1;
strcpy(devname, dirname);
filename = devname + strlen(devname);
*filename++ = '/';
while((de = readdir(dir))) {
if(de->d_name[0] == '.' &&
(de->d_name[1] == '