Android事件分发完全解析之事件从何而来

尊重原创转载请注明:From AigeStudio()Power by Aige 侵权必究!

炮兵

镇楼

上一节Android事件分发完全解析之为什么是她中我们简略地分析了事件分发机制的由来,这里要说明一点,Android(或者说任何的驱动系统)都包含大量不同类型的事件,比如按键啦、轨迹球啦、鼠标啦、触摸啦、红外线啦等等等,这里为了简化问题也为了切合实际,我们只针对触摸事件进行分析,至于其他的一些杂七杂八的事件其实都很好理解就不多说了。

那么在Android中一个触摸事件究竟是从何而来的呢?对事件分发稍有了解的童鞋一定知道dispatchtouchevent方法,都知道View对触摸事件进行分发的起点,但是传入dispatchtouchevent方法中的触摸事件又是从何而来的呢?往上一步步追踪你会发现代码调用无穷无尽找不到头……有时候盲目地去read fuck source code反而会让你更困惑,其实用脑子想想理清逻辑就可以很快找到答案,我们都知道一个事件的产生肯定需要用户的交互,也就是说,只有当用户触摸屏幕或按下某个按键之类的操作之后系统才能做出事件响应,而每一个这样的操作我们都可将其当作事件的“源头”,那么捕获这些最原始交互信息的猎手应该是谁呢?还会是View?还会是Activity?还会是ViewRootImpl还会是WMS吗?这些framework中的构件相对于更底层的机制来说还是太“高级”了,我们知道Android是基于Linux的一款操作系统,Linux其本身就有一个很Perfect的Input子系统架构,Android虽然也实现了几个属于自己的机制,但是大部分底层的调用还是基于Linux所提供的操作接口,比如对Input驱动的编写就是基于Linux Input系统字符驱动的操作接口,关于Linux的这部分大家如果有兴趣可以去看看私房菜,,这里就不多扯了,这里你仅需要知道在Android中Linux的Input子系统会在/dev/input/路径下读写以event[NUMBER]为名的硬件输入设备节点。这些节点都是跟具体硬件有关的,所以呢可能每一款设备的具体节点名都是不一样的,比如在我的mx3中/dev/input/event0为mxhub-key而/dev/input/event1为gp2ap。具体的节点信息可通过Android提供的getevent工具查看,如果你的设备已经连接了PC或者模拟器已启动,adb shell后getevent即可获取事件读写的实时状态,当然各个设备是不一样的,比如mx3中通过getevent查看所有Input节点:

Aigestudio>adb shellshell@mx3:/ $ geteventgeteventadd device 1: /dev/input/event0 name:"mxhub-keys"add device 2: /dev/input/event4 name:"lsm330dlc_gyr"add device 3: /dev/input/event3 name:"lsm330dlc_acc"add device 4: /dev/input/event1 name:"gp2ap"could not get driver version for /dev/input/mouse0, Not a typewriteradd device 5: /dev/input/event5 name:"mx_ts"add device 6: /dev/input/event6 name:"gpio-keys"add device 7: /dev/input/event7 name:"Headset"add device 8: /dev/input/event2 name:"compass"could not get driver version for /dev/input/mice, Not a typewriter可见mx3中有8个Input子系统,分别为:

而mx3(不能说是Android哈这里针对mx3)就是从这些系统节点中读写设备的事件信息,以上信息我是在mx3灭屏时也就是按下电源键关闭屏幕后获取的,如果我们再次按下电源点亮屏幕,内核驱动就会不断地监控一些必要的读写事件,这里我们不想让我们的Terminal一直输出,使用getevent的-c参数设定最大的输出条数查看即可:

这里我设定了最大16条输出,亮屏后可见如上信息显示,如果不作输出限制,Terminal就会一直输出……也就是说加速度和红外线传感器的子系统会不断检测外部环境的变化,至于为什么,想想加速度感应和红外感应我想大家都应该能心知肚明。如果我们在getevent后在屏幕上快速Touch一下,那么event5节点下的子系统就回立即作出回应:

如上图中我们快速接触屏幕后得到的信息,可能不好懂对吧,给getevent加上-l参数格式化输出看看:

注:因为硬件设备、触摸区域力度、持续时间等因素的影响你的输出结果可能跟我不大一样,以具体你具体的输出为准,但输出信息大致是类似的。

这里拿第一条信息“/dev/input/event5: EV_ABS ABS_MT_TRACKING_ID 000008e0”来说,其中/dev/input/event5上面我们说了表示设备节点;EV_ABS表示type事件类型;ABS_MT_TRACKING_ID表示code事件的扫描码;000008e0则表示具体的事件值。这些信息的定义都在kernel/include/linux/input.h文件中作出了声明,比如type输入设备类型包括如下这些:

#define EV_SYN0x00#define EV_KEY0x01#define EV_REL0x02#define EV_ABS0x03#define EV_MSC0x04#define EV_LED0x11#define EV_SND0x12#define EV_REP0x14#define EV_FF0x15#define EV_PWR0x16#define EV_FF_STATUS0x17#define EV_MAX0x1f具体它们都代表什么就不多说了,都是些Linux的东西,一般来说比较常用的是EV_REL表示相对坐标类型、EV_ABS表示绝对坐标类型、EV_KEY表示物理键盘事件类型,EV_SYN表示同步事件类型等等,一个设备可以支持多个不同的事件类型而每个事件类型呢又可以设置不同的事件码,比如EV_SYN同步事件类型的事件码如下:

#define SYN_REPORT0 #define SYN_CONFIG1 #define SYN_MT_REPORT2 其它的就不一一列举了都可以在input.h文件中找到相应的定义。上面图例中的一次快速触屏后的反馈信息可以做如下描述:

/dev/input/event5: EV_ABSABS_MT_TRACKING_ID 000008e0 标志多点追踪信息的采集开始(需要设备支持)/dev/input/event5: EV_ABSABS_MT_POSITION_X 00000280 上报接触面的中心点X坐标/dev/input/event5: EV_ABSABS_MT_POSITION_Y 0000064b 上报接触面的中心点Y坐标/dev/input/event5: EV_ABSABS_MT_PRESSURE0000005b 上报手指压力/dev/input/event5: EV_ABSABS_MT_TOUCH_MAJOR 00000014 上报主接触面长轴/dev/input/event5: EV_SYNSYN_REPORT00000000 同步数据/dev/input/event5: EV_ABSABS_MT_PRESSURE00000057上报手指压力/dev/input/event5: EV_ABSABS_MT_TOUCH_MAJOR 00000012上报主接触面长轴/dev/input/event5: EV_SYNSYN_REPORT00000000 同步数据/dev/input/event5: EV_ABSABS_MT_TRACKING_ID ffffffff标志多点追踪信息的采集结束(需要设备支持)/dev/input/event5: EV_SYNSYN_REPORT00000000 同步数据如上过程只是一次快速触碰所产生的节点读取,如果我们做出更复杂的手势操作比如多点切西瓜那样的效果尼玛光是采集这些信息都不得了!不过值得庆幸的是,对这些原始信息的采集用不着应用层的开发者来做,对于应用开发来说我们往往更关心一次事件是单击呢还是双击还是长按等等,而不是面对这些庞大而又复杂的原始信息,So,Android在获取到这些原始数据后会对其进行一定的转化便于使用,当然如果你需要做驱动开发涉及到这些原始数据的操作也可以直接获取其使用亦可。

爱的力量大到可以使人忘记一切,

Android事件分发完全解析之事件从何而来

相关文章:

你感兴趣的文章:

标签云: