与用户交互的输入设备(触摸屏,键盘等)是获取用户意图的来源。由于硬件本身的物理特性及由各大硬件厂商的标准不一,这将导致我们从设备上获取到的键值存在一定的差异性,为了让系统能够正确处理用户的操作,我们就必须将从输入设备上获取到的键值正确转换为Android系统定义的键值以便正确处理。
二、Android中按键输入转换过程
扫描键码Scancode是由Linux 的input驱动定义的整形类型,扫描键码根据读取的kl配置文档内容的转化后,形成按键的标签KeycodeLaybel。按键的标签在经过数组KEYCODES的转换后形成keycode。应用程序对keycode进行处理。
Android默认提供的按键布局文件主要包括qwerty.kl 和AVRCP.kl(/system/usr/keylayout/目录下)。Qwerty.kl为全键盘的布局文件,是系统中默认使用的布局文件,AVRCP.kl用于多媒体控制。
三、Linux中按键定义的数据结构
3.1 Linux中input_event结构体
(定义按键在 linux/input.h中)
struct input_event {
struct timeval time; //按键时间
__u16 type; //类型,在下面有定义
__u16 code; //要模拟成什么按键
__s32 value;//是按下还是释放
};
1、Code
事件的代码.如果事件的类型代码是EV_KEY,该代码code为设备键盘代码.
代码值0~127为键盘上的按键代码,0x110~0x116 为鼠标上按键代码,
其中0x110(BTN_ LEFT)为鼠标左键,
0x111(BTN_RIGHT)为鼠标右键,
0x112(BTN_ MIDDLE)为鼠标中键.
如果事件的类型代码是EV_REL,code值表示轨迹的类型.如指示鼠标的X轴方向REL_X(代码为0x00),指示鼠标的Y轴方向REL_Y(代码 为0x01),指示鼠标中轮子方向REL_WHEEL(代码为0x08).
其它代码含义请参看include/linux/input.h文件.
2、Type
/*Event types参考值*/
#define EV_SYN 0x00
#define EV_KEY 0x01 //按键 常用的用红色标记出来
#define EV_REL 0x02 //相对坐标(轨迹球)
#define EV_ABS 0x03 //绝对坐标(鼠标)
#define EV_MSC 0x04 //其他
#define EV_SW 0x05
#define EV_LED 0x11 //LED
#define EV_SND 0x12//声音
#define EV_REP 0x14//repeat
#define EV_FF 0x15
#define EV_PWR 0x16
#define EV_FF_STATUS 0x17
#define EV_MAX 0x1f
#define EV_CNT (EV_MAX+1)
3、Value
事件的值.如果事件的类型代码是EV_KEY,当按键按下时值为1,松开时值为0;
如果事件的类型代码是EV_ REL,value的正数值和负数值分别代表两个不同方向的值.
3.2 Android RawEvent结构体
Android中将从底层获取到的按键按照一定规则处理后,用如下结构描述:
/* A raw event as retrieved from the EventHub.*/
struct RawEvent {
nsecs_t when; //时间
int32_t deviceId; //设备ID
int32_t type; //类型,Keyboard、 TouchScreen、TraceBall
int32_t scanCode; //扫描键码
int32_t keyCode; //按键码
int32_t value;
uint32_t flags;
};
四、Linux层获取event的原理
对eventX进行read/write来抓取event的各种信息;
1、打开event设备
event0_fd = open(“/dev/input/event0”, O_RDWR);
2、read设备
rd = read(event0_fd, &event0, sizeof(struct input_event) * 64);
3、判断事件类型
如果,(event[i].type == 3 && event[i].code == 0),为鼠标位置的x坐标值;
(event[i].type == 3 && event[i].code == 1),为鼠标位置的y坐标值;
如果,(event[i].type == 1 && event[i].value == 1),为按下key;
(event[i].type == 1 && event[i].value == 0),为松开key;
如果,(event[i].type ==其它事件(如轨迹球...声音控制...))
具体见源码。
4、保存键值
保存您想要的键盘值,(相对/绝对)x,y的值。
5、键盘映射
由于Android输入处理经过那两次映射;
1、事件码(input.h定义的键盘值)------------------------------------>字符串;
2、字符串--------------->Android中java的UI程序中自定义的键盘key;
由于有键盘映射关系,而我们想要的值是Android中java的Ui自定义值;为此我在代码中自定义了一个数组,用来进行事件码和java的UI程序中自定义的键盘key进行转换。
五、源码
#include
#include
#include
#include
static int event0_fd = -1;
struct input_event ev0[64];
//for handling event0, mouse/key/ts
static int handle_event0() {
int i, rd;
rd = read(event0_fd, ev0, sizeof(struct input_event) * 64);
if ( rd < sizeof(struct input_event) ) return 0;
for (i = 0; i < rd / sizeof(struct input_event); i++) {
printf("", ev0[i].type, ev0[i].code, ev0[i].value);
if (ev0[i].type == 3 && ev0[i].code == 0)
{
//realx = ev0[i].value;
printf("Touch event: X Value: %3d;\n",ev0[i].value);
}
else if (ev0[i].type == 3 && ev0[i].code == 1)
{
//realy = ev0[i].value;
printf("Touch event: Y Value: %3d;\n",ev0[i].value);
}
else if (ev0[i].type == 1&& ev0[i].value == 0) {
//realy = ev0[i].value;
printf("Key event: Key: %3d Up;\n",ev0[i].code);
}else if (ev0[i].type == 1&& ev0[i].value == 1) {
//realy = ev0[i].value;
printf("Key event: Key: %3d Down;\n",ev0[i].code);
} else if (ev0[i].type == 2) {
printf("Ball event: Type: %3d;\n",ev0[i].type);
}
else if(ev0[i].type == 0 && ev0[i].code == 0 && ev0[i].value == 0) {
printf("EV_SYN;\n");
}
}
return 1;
}
int main(void) {
int done = 1;
//printf("sizeof(struct input_event) = %d\n", sizeof(struct input_event));
printf("GetEvent Running;\n");
event0_fd = open("/dev/input/event0", O_RDWR);
if ( event0_fd < 0 )
return -1;
while ( done ) {
done = handle_event0();
}
if ( event0_fd > 0 ) {
close(event0_fd);
event0_fd = -1;
}
return 0;
}