和菜鸟一起学android4.0.3源码之按键驱动短长按功能


第一:按键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如下定义

[html]  view plain copy
  1. /*  
  2.  * Event types  
  3.  */  
  4. #define EV_SYN          0x00  
  5. #define EV_KEY          0x01  
  6. #define EV_REL          0x02  
  7. #define EV_ABS          0x03  
  8. #define EV_MSC          0x04  
  9. #define EV_SW           0x05  
  10. #define EV_LED          0x11  
  11. #define EV_SND          0x12  
  12. #define EV_REP          0x14  
  13. #define EV_FF           0x15  
  14. #define EV_PWR          0x16  
  15. #define EV_FF_STATUS        0x17  
  16. #define EV_MAX          0x1f  
  17. #define EV_CNT          (EV_MAX+1)  

一般来说,常用的是EV_KEY, EV_REL, EV_ABS, EV_SYN

分别对应keyboard, 相对坐标, 绝对坐标, 同步事件


EV_SYN则表示一组完整事件已经完成,需要处理,EV_SYN的code定义事件分发的类型

EV_SYN对应的code如下

[html]  view plain copy
  1. /*  
  2.  * Synchronization events.  
  3.  */  
  4. #define SYN_REPORT      0  
  5. #define SYN_CONFIG      1  
  6. #define SYN_MT_REPORT       2  

EV_KEY的code比较多,这里就不列出来了,可参照input.h


EV_REL对应的code

[html]  view plain copy
  1. /*  
  2.  * Relative axes  
  3.  */  
  4. #define REL_X           0x00  
  5. #define REL_Y           0x01  
  6. #define REL_Z           0x02  
  7. #define REL_RX          0x03  
  8. #define REL_RY          0x04  
  9. #define REL_RZ          0x05  
  10. #define REL_HWHEEL      0x06  
  11. #define REL_DIAL        0x07  
  12. #define REL_WHEEL       0x08  
  13. #define REL_MISC        0x09  
  14. #define REL_MAX         0x0f  
  15. #define REL_CNT         (REL_MAX+1)  

EV_ABS对应的code

[html]  view plain copy
  1. /*  
  2.  * Absolute axes  
  3.  */  
  4.   
  5. #define ABS_X           0x00  
  6. #define ABS_Y           0x01  
  7. #define ABS_Z           0x02  
  8. #define ABS_RX          0x03  
  9. #define ABS_RY          0x04  
  10. #define ABS_RZ          0x05  
  11. #define ABS_THROTTLE        0x06  
  12. #define ABS_RUDDER      0x07  
  13. #define ABS_WHEEL       0x08  
  14. #define ABS_GAS         0x09  
  15. #define ABS_BRAKE       0x0a  
  16. #define ABS_HAT0X       0x10  
  17. #define ABS_HAT0Y       0x11  
  18. #define ABS_HAT1X       0x12  
  19. #define ABS_HAT1Y       0x13  
  20. #define ABS_HAT2X       0x14  
  21. #define ABS_HAT2Y       0x15  
  22. #define ABS_HAT3X       0x16  
  23. #define ABS_HAT3Y       0x17  
  24. #define ABS_PRESSURE        0x18  
  25. #define ABS_DISTANCE        0x19  
  26. #define ABS_TILT_X      0x1a  
  27. #define ABS_TILT_Y      0x1b  
  28. #define ABS_TOOL_WIDTH      0x1c  
  29. #define ABS_VOLUME      0x20  
  30. #define ABS_MISC        0x28  
  31.   
  32. #define ABS_MT_TOUCH_MAJOR  0x30    /* Major axis of touching ellipse */  
  33. #define ABS_MT_TOUCH_MINOR  0x31    /* Minor axis (omit if circular) */  
  34. #define ABS_MT_WIDTH_MAJOR  0x32    /* Major axis of approaching ellipse */  
  35. #define ABS_MT_WIDTH_MINOR  0x33    /* Minor axis (omit if circular) */  
  36. #define ABS_MT_ORIENTATION  0x34    /* Ellipse orientation */  
  37. #define ABS_MT_POSITION_X   0x35    /* Center X ellipse position */  
  38. #define ABS_MT_POSITION_Y   0x36    /* Center Y ellipse position */  
  39. #define ABS_MT_TOOL_TYPE    0x37    /* Type of touching device */  
  40. #define ABS_MT_BLOB_ID      0x38    /* Group a set of packets as a blob */  
  41. #define ABS_MT_TRACKING_ID  0x39    /* Unique ID of initiated contact */  
  42. #define ABS_MT_PRESSURE     0x3a    /* Pressure on contact area */  
  43.   
  44. #define ABS_MAX         0x3f  
  45. #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事件



2>adb shell input 命令


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长按键功能和短按键功能表示不解。网上也很少讲到驱动时怎么取实现的。一直以为那个

[html]  view plain copy
  1. input_report_key(btn_dev, KEY_POWER, 0);  
  2.   
  3. input_report_key(btn_dev, KEY_POWER, 1);  


这句话是表示按键的按下和抬起,其实错了,是value值为1的时候表示是按键按下,而value值是0的时候才是表示按键的抬起,而每次都需要发送一个

[html]  view plain copy
  1. input_sync(btn_dev);  


这样才表示是整个过程,才可以实现按键的长按和短按的功能。也就是下面的方式:

[html]  view plain copy
  1. input_report_key(btn_dev, KEY_POWER, 1);  
  2.   
  3. input_sync(btn_dev);  


这个表示的是按键被按下了。

[html]  view plain copy
  1. input_report_key(btn_dev, KEY_POWER, 0);  
  2.   
  3. input_sync(btn_dev);  


这个表示按键被抬起了。

这两个之间是表示按键按下的时间长度,android上层就是通过这个来实现按键的短按和长按的功能的。

下面用简单的驱动和简单的应用才实现android的按键的功能,无需真实的按键就可以测试了。

下面的驱动和我的那篇input子系统实例的驱动很类似

 

[html]  view plain copy
  1. #include <linux/slab.h>  
  2.   
  3. #include <linux/irq.h>  
  4.   
  5. #include <linux/interrupt.h>  
  6.   
  7. #include <linux/poll.h>  
  8.   
  9. #include <asm/io.h>  
  10.   
  11. #include <linux/delay.h>  
  12.   
  13. #include <linux/module.h>  
  14.   
  15. #include <linux/time.h>  
  16.   
  17. #include <linux/gpio.h>  
  18.   
  19. #include <linux/wait.h>  
  20.   
  21. #include <linux/input.h>  
  22.   
  23. #include <linux/init.h>  
  24.   
  25.    
  26.   
  27. #define CODENUM 3  
  28.   
  29. struct input_dev *btn_dev;      //input设备的结构体,这里定义了btn_dev  
  30.   
  31.    
  32.   
  33. static keycode[] = {  
  34.   
  35.        KEY_POWER,  
  36.   
  37.        KEY_VOLUMEUP,  
  38.   
  39.        KEY_VOLUMEDOWN  
  40.   
  41. };  
  42.   
  43.    
  44.   
  45. static int __init button_init(void)  
  46.   
  47. {  
  48.   
  49.     int error;  
  50.   
  51.     //分配input设备  
  52.   
  53.     btn_dev = input_allocate_device();  
  54.   
  55.     if(!btn_dev)  
  56.   
  57.     {  
  58.   
  59.               printk(KERN_ERR "button: not enough memory\n");  
  60.   
  61.         error = -ENOMEM;  
  62.   
  63.               return error;  
  64.   
  65.     }  
  66.   
  67.       
  68.   
  69.     //把相应的按键给置上  
  70.   
  71. btn_dev->evbit[0] = BIT_MASK(EV_KEY);  
  72.   
  73. for(i = 0; i < CODENUM; i++)  
  74.   
  75.            btn_dev->keybit[BIT_WORK(keycode[i])] |= BIT_MASK(keycode[i]);  
  76.   
  77.       
  78.   
  79.     //注册input设备  
  80.   
  81.     error = input_register_device(btn_dev);  
  82.   
  83.     if(error)  
  84.   
  85.     {  
  86.   
  87.               printk(KERN_ERR "button: failed to register device\n");  
  88.   
  89. return error;      
  90.   
  91.     }  
  92.   
  93.          
  94.   
  95.     return 0;    
  96.   
  97. }  
  98.   
  99.    
  100.   
  101. static void __exit button_exit(void)  
  102.   
  103. {  
  104.   
  105.     input_free_device(btn_dev);  
  106.   
  107. }  
  108.   
  109.    
  110.   
  111. module_init(button_init);  
  112.   
  113. module_exit(button_exit);  
  114.   
  115. MODULE_LICENSE("GPL");  
  116.   
  117. MODULE_AUTHOR("eastmoon");  


 

上面的驱动其实主要就是注册一个input设备,然后再注册要用到的按键的code而已,下面就是要用的应用程序来实现那个长按和短按的功能了。

 

[html]  view plain copy
  1. #include <stdio.h>  
  2.   
  3. #include <sys/ioctl.h>  
  4.   
  5. #include <unistd.h>  
  6.   
  7. #include <fcntl.h>  
  8.   
  9. #include <sys/types.h>  
  10.   
  11. #include <sys/stat.h>  
  12.   
  13. #include <sys/select.h>  
  14.   
  15. #include <sys/time.h>  
  16.   
  17. #include <linux/input.h>  
  18.   
  19. #include <stdlib.h>  
  20.   
  21.    
  22.   
  23. #define DEVICE "/dev/input/event0"   //这个根据自己的平台来的,不一定是event0的  
  24.   
  25.    
  26.   
  27. int main(int argc, char *argv[])  
  28.   
  29. {  
  30.   
  31.     struct input_event btn;  
  32.   
  33.     int fd, rev;  
  34.   
  35.     unsigned short type;  
  36.   
  37.     unsigned short code;  
  38.   
  39.     int value;  
  40.   
  41.        int longbt = 1;  
  42.   
  43.        int delay = 0;    
  44.   
  45.    
  46.   
  47.     fd = open(DEVICE, O_RDWR);  
  48.   
  49.     if(fd < 0)  
  50.   
  51.     {  
  52.   
  53.         printf("Open file %s failed!\n", DEVICE);  
  54.   
  55.         return -1;  
  56.   
  57.     }  
  58.   
  59.    
  60.   
  61.        if(argv[2] == NULL)  
  62.   
  63.        {  
  64.   
  65.               Longbt = 0;     //命令行如果输入2个参数的话那么就默认的短按了  
  66.   
  67. }  
  68.   
  69.        else                  
  70.   
  71. {  
  72.   
  73.        longbt = atoi(argv[2]);  
  74.   
  75.        if(longbt >= 10 || longbt < 0)  
  76.   
  77.        {  
  78.   
  79.               Printf(“Please input the longbt  0------9”);  
  80.   
  81.               return 0;  
  82.   
  83. }  
  84.   
  85. delay = longbt *100000;           //longbt表示长按的时间,步进100ms。  
  86.   
  87. }  
  88.   
  89.    
  90.   
  91. btn.type = EV_KEY;                                               //表示按键按下了  
  92.   
  93. btn.code = atoi(argv[1]);  
  94.   
  95.        btn.value = 1;   
  96.   
  97.        rev = write(fd, &btn, sizeof(struct input_event));  
  98.   
  99.        if(rev > 0)  
  100.   
  101. {  
  102.   
  103.               printf(“ok1\n”);  
  104.   
  105. }  
  106.   
  107.    
  108.   
  109.    
  110.   
  111. btn.type = EV_SYN;                                        //上报表示这个过程  
  112.   
  113. btn.code = SYN_REPORT;  
  114.   
  115.        btn.value = 0;   
  116.   
  117.        rev = write(fd, &btn, sizeof(struct input_event));  
  118.   
  119.        if(rev > 0)  
  120.   
  121. {  
  122.   
  123.               printf(“ok3\n”);  
  124.   
  125. }  
  126.   
  127.    
  128.   
  129.        usleep(delay);               //按键按的时间  
  130.   
  131.    
  132.   
  133. btn.type = EV_KEY;                                                             //表示按键抬起了  
  134.   
  135. btn.code = atoi(argv[1]);  
  136.   
  137.        btn.value = 0;   
  138.   
  139.        rev = write(fd, &btn, sizeof(struct input_event));  
  140.   
  141.        if(rev > 0)  
  142.   
  143. {  
  144.   
  145.               printf(“ok2\n”);  
  146.   
  147. }  
  148.   
  149.    
  150.   
  151. btn.type = EV_SYN;                                               //上报表示这个过程好了  
  152.   
  153. btn.code = SYN_REPORT;  
  154.   
  155.        btn.value = 0;   
  156.   
  157.        rev = write(fd, &btn, sizeof(struct input_event));  
  158.   
  159.        if(rev > 0)  
  160.   
  161. {  
  162.   
  163.               printf(“ok3\n”);  
  164.   
  165. }  
  166.   
  167.    
  168.   
  169.     close(fd);  
  170.   
  171.    
  172.   
  173.     return 0;  
  174.   
  175. }  


 

至于怎么在android下编译一个应用程序的话,网上也讲得很多了,这里也还是讲讲吧。

首先在androidexternal/下新建个input_app目录,然后在下面建个.c文件就是上面这段代码,命名为vitual.c好了。然后建一个Android.mk文件

内容如下:

[html]  view plain copy
  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3.    
  4.   
  5. include $(CLEAR_VARS)  
  6.   
  7.    
  8.   
  9. LOCAL_SRC_FILE := \  
  10.   
  11.        virtual.c  
  12.   
  13.    
  14.   
  15. LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)  
  16.   
  17. LOCAL_MODULE_TAGS :eng  
  18.   
  19. LOCAL_MODULE :virtual  
  20.   
  21.    
  22.   
  23. include $(BUILD_EXECUTABLE)  


 

然后在input_appmm后就可以得到一个vitualbin文件了,再把这个可执行文件拷贝到system/bin下就可以了。

然后就可以执行

[html]  view plain copy
  1. virtual  116    //这个表示短按会锁屏或者解锁,其中116就是那个电源键的code了  
  2.   
  3. virtual  116 6    //这个就可以表示长按了,然后会出来一个选择框,让你选择是否要关机了。  


 

至此,关于android的按键功能就实现了,其短按、长按的功能也得以实现了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值