第一:按键ADB调试
1> adb shell getevent中获取到的屏幕事件的坐标转换
通过使用adb shell getevent,可以得到如下设备操作后的指令,具体表示的含义,可以参考网上很多的文章,这里就不再叙述
这里的0035和0036分别表示屏幕上的X坐标和Y坐标,后面的值表示具体的坐标点,通过16进制转换可以得到值1142和1527,而我手机的屏幕分辨率为800*480的,很明显两个点是完全不匹配,那如何转换呢?
在cmd中输入adb shell getevent -p
找到您的屏幕设备中0035和0036的含义,我的手机中可以看到x的值min为0,max为1172,y的值min为0,max为1900。
这样就找到您的设备的坐标具体大小值,这里计算公式如下:
x=(x-xmin)*480/(xmax-xmin) ;
y=(y-ymin)*800/(ymax-ymin);
这样算出的坐标值就跟您手机的屏幕分辨率相匹配了。
该公式是通过查看androidvncserver源码,然后反向推出的公式,目前碰到的手机min都为0,未测试过不过为0的情况,如果不为0的情况这个公式是错误的,请各位同学补充。
getevent/sendevent源码
这两个命令的源码在system/core/toolbox/下,sendevent.c getevent.c
getevent
使用getevent获得/dev/input/eventX设备汇报的事件,这个命令还会输出所有event设备的基本信息,如下:
add device 1: /dev/input/event1
name: "mxc_ts"
add device 2: /dev/input/event0
name: "mxckpd"
表明系统有两个event设备,分别对应着input设备touchscreen,keyboard
Android可以使用sendevent来模拟触屏,键盘以及其他类型的event事件,
sendevent /dev/input/eventX type code value
/dev/input/eventX 对应一个event设备,可以通过getevent获得可用的event设备
type, code, value的定义可参看kernel/include/linux/input.h
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
- #define EV_SND 0x12
- #define EV_REP 0x14
- #define EV_FF 0x15
- #define EV_PWR 0x16
- #define EV_FF_STATUS 0x17
- #define EV_MAX 0x1f
- #define EV_CNT (EV_MAX+1)
一般来说,常用的是EV_KEY, EV_REL, EV_ABS, EV_SYN
分别对应keyboard, 相对坐标, 绝对坐标, 同步事件
EV_SYN则表示一组完整事件已经完成,需要处理,EV_SYN的code定义事件分发的类型
EV_SYN对应的code如下
- /*
- * Synchronization events.
- */
- #define SYN_REPORT 0
- #define SYN_CONFIG 1
- #define SYN_MT_REPORT 2
EV_KEY的code比较多,这里就不列出来了,可参照input.h
EV_REL对应的code
- /*
- * Relative axes
- */
- #define REL_X 0x00
- #define REL_Y 0x01
- #define REL_Z 0x02
- #define REL_RX 0x03
- #define REL_RY 0x04
- #define REL_RZ 0x05
- #define REL_HWHEEL 0x06
- #define REL_DIAL 0x07
- #define REL_WHEEL 0x08
- #define REL_MISC 0x09
- #define REL_MAX 0x0f
- #define REL_CNT (REL_MAX+1)
EV_ABS对应的code
- /*
- * Absolute axes
- */
- #define ABS_X 0x00
- #define ABS_Y 0x01
- #define ABS_Z 0x02
- #define ABS_RX 0x03
- #define ABS_RY 0x04
- #define ABS_RZ 0x05
- #define ABS_THROTTLE 0x06
- #define ABS_RUDDER 0x07
- #define ABS_WHEEL 0x08
- #define ABS_GAS 0x09
- #define ABS_BRAKE 0x0a
- #define ABS_HAT0X 0x10
- #define ABS_HAT0Y 0x11
- #define ABS_HAT1X 0x12
- #define ABS_HAT1Y 0x13
- #define ABS_HAT2X 0x14
- #define ABS_HAT2Y 0x15
- #define ABS_HAT3X 0x16
- #define ABS_HAT3Y 0x17
- #define ABS_PRESSURE 0x18
- #define ABS_DISTANCE 0x19
- #define ABS_TILT_X 0x1a
- #define ABS_TILT_Y 0x1b
- #define ABS_TOOL_WIDTH 0x1c
- #define ABS_VOLUME 0x20
- #define ABS_MISC 0x28
- #define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
- #define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */
- #define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */
- #define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */
- #define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */
- #define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */
- #define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */
- #define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */
- #define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */
- #define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */
- #define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */
- #define ABS_MAX 0x3f
- #define ABS_CNT (ABS_MAX+1)
input keyevent
如果想模拟按键,send event用起来比较繁琐,可以用input keyevent代替
下面是input keyevent几个比较常用的用法:
input keyevent 3 // Home
input keyevent 4 // Back
input keyevent 19 //Up
input keyevent 20 //Down
input keyevent 21 //Left
input keyevent 22 //Right
input keyevent 23 //Select/Ok
input keyevent 24 //Volume+
input keyevent 25 // Volume-
input keyevent 82 // Menu 菜单
用senevent 模拟触屏事件
sendevent /dev/input/event1 0003 0000 0000015e // ABS x 坐标
sendevent /dev/input/event1: 0003 0001 000000df // ABS y 坐标
sendevent /dev/input/event1: 0001 014a 00000001 // BTN touch事件 值为1
sendevent /dev/input/event1: 0003 0018 00000000 // ABS pressure事件
sendevent /dev/input/event1: 0001 014a 00000000 // BTN touch事件 值为0
sendevent /dev/input/event1: 0000 0000 00000000 // sync事件
adb命令可以模拟简单的按键事件,当触摸屏不好使的时候就可以用咯。上篇有提到adb devices命令,就是用usb连接到手机或平板,这个时候就可以用adb shell 命令打开手机或平板终端了。输入input 回车有:
$ input
usage: input [text|keyevent]
input text <string>
input keyevent <event_code>
你可以输入:input text "字符串"
或一些按键事件:input keyevent Num
解锁:input keyevent 83
向上:input keyevent 19
向下:input keyevent 20
向左:input keyevent 21
向右:input keyevent 22
等等。。。。
以下就是约定的按键键码:
0 --> "KEYCODE_UNKNOWN"
1 --> "KEYCODE_MENU"
2 --> "KEYCODE_SOFT_RIGHT"
3 --> "KEYCODE_HOME"
4 --> "KEYCODE_BACK"
5 --> "KEYCODE_CALL"
6 --> "KEYCODE_ENDCALL"
7 --> "KEYCODE_0"
8 --> "KEYCODE_1"
9 --> "KEYCODE_2"
10 --> "KEYCODE_3"
11 --> "KEYCODE_4"
12 --> "KEYCODE_5"
13 --> "KEYCODE_6"
14 --> "KEYCODE_7"
15 --> "KEYCODE_8"
16 --> "KEYCODE_9"
17 --> "KEYCODE_STAR"
18 --> "KEYCODE_POUND"
19 --> "KEYCODE_DPAD_UP"
20 --> "KEYCODE_DPAD_DOWN"
21 --> "KEYCODE_DPAD_LEFT"
22 --> "KEYCODE_DPAD_RIGHT"
23 --> "KEYCODE_DPAD_CENTER"
24 --> "KEYCODE_VOLUME_UP"
25 --> "KEYCODE_VOLUME_DOWN"
26 --> "KEYCODE_POWER"
27 --> "KEYCODE_CAMERA"
28 --> "KEYCODE_CLEAR"
29 --> "KEYCODE_A"
30 --> "KEYCODE_B"
31 --> "KEYCODE_C"
32 --> "KEYCODE_D"
33 --> "KEYCODE_E"
34 --> "KEYCODE_F"
35 --> "KEYCODE_G"
36 --> "KEYCODE_H"
37 --> "KEYCODE_I"
38 --> "KEYCODE_J"
39 --> "KEYCODE_K"
40 --> "KEYCODE_L"
41 --> "KEYCODE_M"
42 --> "KEYCODE_N"
43 --> "KEYCODE_O"
44 --> "KEYCODE_P"
45 --> "KEYCODE_Q"
46 --> "KEYCODE_R"
47 --> "KEYCODE_S"
48 --> "KEYCODE_T"
49 --> "KEYCODE_U"
50 --> "KEYCODE_V"
51 --> "KEYCODE_W"
52 --> "KEYCODE_X"
53 --> "KEYCODE_Y"
54 --> "KEYCODE_Z"
55 --> "KEYCODE_COMMA"
56 --> "KEYCODE_PERIOD"
57 --> "KEYCODE_ALT_LEFT"
58 --> "KEYCODE_ALT_RIGHT"
59 --> "KEYCODE_SHIFT_LEFT"
60 --> "KEYCODE_SHIFT_RIGHT"
61 --> "KEYCODE_TAB"
62 --> "KEYCODE_SPACE"
63 --> "KEYCODE_SYM"
64 --> "KEYCODE_EXPLORER"
65 --> "KEYCODE_ENVELOPE"
66 --> "KEYCODE_ENTER"
67 --> "KEYCODE_DEL"
68 --> "KEYCODE_GRAVE"
69 --> "KEYCODE_MINUS"
70 --> "KEYCODE_EQUALS"
71 --> "KEYCODE_LEFT_BRACKET"
72 --> "KEYCODE_RIGHT_BRACKET"
73 --> "KEYCODE_BACKSLASH"
74 --> "KEYCODE_SEMICOLON"
75 --> "KEYCODE_APOSTROPHE"
76 --> "KEYCODE_SLASH"
77 --> "KEYCODE_AT"
78 --> "KEYCODE_NUM"
79 --> "KEYCODE_HEADSETHOOK"
80 --> "KEYCODE_FOCUS"
81 --> "KEYCODE_PLUS"
82 --> "KEYCODE_MENU"
83 --> "KEYCODE_NOTIFICATION"
84 --> "KEYCODE_SEARCH"
85 --> "TAG_LAST_KEYCODE"
3>底层驱动
一切再次回到原点,一切都又开始了正常的路线,上班,下班。每每一个人回到那小小的屋子,觉得什么也不是。想离开,又不知道要去哪。日子还是一天天过去,地球不因任何人改变它的转速,月亮也不会为了谁而改变她的形状。平静,也许就是一种幸福。
上周由于其他部门需要用我们的芯片,得模拟个input设备,用以mcu按键传递过来后的处理。所以只能屁颠屁颠地去实现了,还好以前做过类似的驱动,于是很快就实现了这个功能。但是一直对于android长按键功能和短按键功能表示不解。网上也很少讲到驱动时怎么取实现的。一直以为那个
- input_report_key(btn_dev, KEY_POWER, 0);
- input_report_key(btn_dev, KEY_POWER, 1);
这句话是表示按键的按下和抬起,其实错了,是value值为1的时候表示是按键按下,而value值是0的时候才是表示按键的抬起,而每次都需要发送一个
- input_sync(btn_dev);
这样才表示是整个过程,才可以实现按键的长按和短按的功能。也就是下面的方式:
- input_report_key(btn_dev, KEY_POWER, 1);
- input_sync(btn_dev);
这个表示的是按键被按下了。
- input_report_key(btn_dev, KEY_POWER, 0);
- input_sync(btn_dev);
这个表示按键被抬起了。
这两个之间是表示按键按下的时间长度,android上层就是通过这个来实现按键的短按和长按的功能的。
下面用简单的驱动和简单的应用才实现android的按键的功能,无需真实的按键就可以测试了。
下面的驱动和我的那篇input子系统实例的驱动很类似
- #include <linux/slab.h>
- #include <linux/irq.h>
- #include <linux/interrupt.h>
- #include <linux/poll.h>
- #include <asm/io.h>
- #include <linux/delay.h>
- #include <linux/module.h>
- #include <linux/time.h>
- #include <linux/gpio.h>
- #include <linux/wait.h>
- #include <linux/input.h>
- #include <linux/init.h>
- #define CODENUM 3
- struct input_dev *btn_dev; //input设备的结构体,这里定义了btn_dev
- static keycode[] = {
- KEY_POWER,
- KEY_VOLUMEUP,
- KEY_VOLUMEDOWN
- };
- static int __init button_init(void)
- {
- int error;
- //分配input设备
- btn_dev = input_allocate_device();
- if(!btn_dev)
- {
- printk(KERN_ERR "button: not enough memory\n");
- error = -ENOMEM;
- return error;
- }
- //把相应的按键给置上
- btn_dev->evbit[0] = BIT_MASK(EV_KEY);
- for(i = 0; i < CODENUM; i++)
- btn_dev->keybit[BIT_WORK(keycode[i])] |= BIT_MASK(keycode[i]);
- //注册input设备
- error = input_register_device(btn_dev);
- if(error)
- {
- printk(KERN_ERR "button: failed to register device\n");
- return error;
- }
- return 0;
- }
- static void __exit button_exit(void)
- {
- input_free_device(btn_dev);
- }
- module_init(button_init);
- module_exit(button_exit);
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("eastmoon");
上面的驱动其实主要就是注册一个input设备,然后再注册要用到的按键的code而已,下面就是要用的应用程序来实现那个长按和短按的功能了。
- #include <stdio.h>
- #include <sys/ioctl.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/select.h>
- #include <sys/time.h>
- #include <linux/input.h>
- #include <stdlib.h>
- #define DEVICE "/dev/input/event0" //这个根据自己的平台来的,不一定是event0的
- int main(int argc, char *argv[])
- {
- struct input_event btn;
- int fd, rev;
- unsigned short type;
- unsigned short code;
- int value;
- int longbt = 1;
- int delay = 0;
- fd = open(DEVICE, O_RDWR);
- if(fd < 0)
- {
- printf("Open file %s failed!\n", DEVICE);
- return -1;
- }
- if(argv[2] == NULL)
- {
- Longbt = 0; //命令行如果输入2个参数的话那么就默认的短按了
- }
- else
- {
- longbt = atoi(argv[2]);
- if(longbt >= 10 || longbt < 0)
- {
- Printf(“Please input the longbt 0------9”);
- return 0;
- }
- delay = longbt *100000; //longbt表示长按的时间,步进100ms。
- }
- btn.type = EV_KEY; //表示按键按下了
- btn.code = atoi(argv[1]);
- btn.value = 1;
- rev = write(fd, &btn, sizeof(struct input_event));
- if(rev > 0)
- {
- printf(“ok1\n”);
- }
- btn.type = EV_SYN; //上报表示这个过程
- btn.code = SYN_REPORT;
- btn.value = 0;
- rev = write(fd, &btn, sizeof(struct input_event));
- if(rev > 0)
- {
- printf(“ok3\n”);
- }
- usleep(delay); //按键按的时间
- btn.type = EV_KEY; //表示按键抬起了
- btn.code = atoi(argv[1]);
- btn.value = 0;
- rev = write(fd, &btn, sizeof(struct input_event));
- if(rev > 0)
- {
- printf(“ok2\n”);
- }
- btn.type = EV_SYN; //上报表示这个过程好了
- btn.code = SYN_REPORT;
- btn.value = 0;
- rev = write(fd, &btn, sizeof(struct input_event));
- if(rev > 0)
- {
- printf(“ok3\n”);
- }
- close(fd);
- return 0;
- }
至于怎么在android下编译一个应用程序的话,网上也讲得很多了,这里也还是讲讲吧。
首先在android的external/下新建个input_app目录,然后在下面建个.c文件就是上面这段代码,命名为vitual.c好了。然后建一个Android.mk文件
内容如下:
- LOCAL_PATH := $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_SRC_FILE := \
- virtual.c
- LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
- LOCAL_MODULE_TAGS := eng
- LOCAL_MODULE := virtual
- include $(BUILD_EXECUTABLE)
然后在input_app下mm后就可以得到一个vitual的bin文件了,再把这个可执行文件拷贝到system/bin下就可以了。
然后就可以执行
- virtual 116 //这个表示短按会锁屏或者解锁,其中116就是那个电源键的code了
- virtual 116 6 //这个就可以表示长按了,然后会出来一个选择框,让你选择是否要关机了。
至此,关于android的按键功能就实现了,其短按、长按的功能也得以实现了。