打印

安卓底层开发学习经验第三十二期

[复制链接]
877|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
上一期我们学习了在Android中读取外设的消息,包括我们开发板中按键的消息,红外遥控器输入的消息,鼠标输入的消息等,这些输入消息是有实体的硬件与之相对应,这样我们才能捕获到相关的硬件设备所产生的输入消息,那么在安卓智能设备中,有些设备有些输入是没有的,比如我们常用的Android电视,或者Android的盒子,这些基本上都不会给我们配置触摸屏,那么如果我现在有一个需求,我想通过手机来控制我们的电视,通过触摸事件来控制电视,那么这时候应该怎样来做操作呢?首先我们要明确我们的Android电视或者盒子他的输入处理部分代码是完整的,他唯一和我们手机的一个不同是,有没有触摸屏。那么现在我们就可以做一种假设,我在这个电视的系统中虚拟出一个虚拟的触摸屏设备,而我们触摸屏的输入设备可以通过上层写一个应用,从我们手机端把触摸事件发送给电视上的一个接收端,接收端在通过一种方式写给我们虚拟的触摸屏外设,然后这个虚拟的触摸屏外设,再通过Android系统的输入系统把消息告诉给我们整个Android系统,那么我们这个电视也就拥有了一块虚拟的触摸屏。而我们虚拟触摸屏的实体就是我们的手机。我们在这里会涉及到下面几个知识点:第一我们如何来创建虚拟的touch设备;第二我们虚拟的消息的来源必须通过WiFi来进行传递,传递过程中我们需要将我们的值进行一下处理,比如我们触摸屏的move的一个过程以及触摸屏的一个点击过程,以及多点触摸的一个过程,都要和我们整个系统对应起来,这样我们才能完美的模拟一个触摸屏事件。再比如说我们的空鼠也可以采取这种方式,通过手机sensor的一个变化来进行一下判断。第一步还是创建一个虚拟的鼠标外设,然后在我们接收端接收相应的消息,然后将我们鼠标移动的一个值,比如说我们的sensor移动了一下,我们可以根据sensor判断的一个值来判断他是左移还是右移,从而发一个鼠标移动的消息过来,这时候就可以在电视上出现一个鼠标的图标,这时候就模拟成了一个鼠标。在一个就是我们虚拟的按键,我们也可以模拟一个虚拟的按键设备,然后监听我们手机发送过来的虚拟的按键值,这时候再把这些值报给我们的虚拟的设备,然后虚拟设备通过Android系统input系统向上报给我们整个Android系统,这样我们Android电视或者盒子就拥有了一套完整的输入设备,而我们的输入源就是我们的手机,这样就能达到一个多屏互动的概念。那么我们来看一下Android是如何创建虚拟的输入设备的
首先我们Android系统是基于Linux系统实现的,而在我们Linux内核中有一个uinput的驱动,这个驱动就可以模拟虚拟按键设备,首先要打开/dev/uinput这个目录,然后产生一个文件描述符,第二我们需要了解一个和uinput相关的一个结构,这个结构就是struct uinput_user_dev,在他下面有一些属性,一个是我们的name,还有struct input_id,这个结构其实就是device下面的一些信息,包括bustypevendorproductversion。在后面就是对应我们触摸屏的一些值的设置。第二步我们需要做的就是来设置这个结构,包括我们的vendorproductversionbus,做完这个操作还有一个具体的操作,调用ioctl命令,来设置我们设备支持的一些键值,也就是按键的类型和code的值,然后将这些值写入到打开的那个uinput的文件描述符中,然后调用ioctlfd,UI_DEV_CREATE)来创建一个设备,当我们执行完这个create之后,我们就会发现在我们input目录下会多出来一个eventxinput device下还会多一个描述信息,这个信息就是我们输入设备的一个信息。如果说我们模拟了一个虚拟设备,那么同样会多一个这样的信息,我们大概来看一下:I代表我们外设的一些具体信息,包括我们的BusVendorProductVersionN就是我们外设的名字。H代表这个外设对应的当前系统中具体的设备。这就是我们Android创建一个虚拟输入设备的一个过程。下面我们来看一下在我们Android系统中如何来创建一个虚拟的键盘
第一步就是打开我们的/dev/uinput这个目录,打开的方式就是使用读写的方式。第二个就需要设置我们的uinput_user_dev这个结构,这个结构中涉及的选项包括我们的namevendorproductbustype,设置完成之后我们就调用ioctl来设置这个输入设备他要支持EV_KEY这种类型。然后再来看这个write的操作,uinp_fd_key就是一个虚拟的按键,这个就是上边打开的fduinp_key代表我们虚拟键盘支持的所有的值,当我们把它所支持的键值写到文件描述符之后,我们就可以直接调用UI_DEV_CREATE,来创建一个设备,当设备创建完成之后就可以关闭掉,这样我们就创建了一个虚拟的按键设备,同样我们创建别的虚拟设备也是这样一个过程,只是需要的填充值不一样,我们切到Linux下看一下代码的实现。在这里已经写好了一个函数VirtualEvent.cpp,我们来看一下,找到main函数,首先这里会有一个simulate_device_create(),也就是一个假冒的设备创建,我们来看一下这个函数
首先打开dev/uinput,他返回的文件描述符是uinp_fd_key,首先我们要创建一个虚拟的按键,我们来看一下创建的过程,第一个我们要把uinp_key的变量清0,这个uinp_key的定义是uinput_user_dev也就是我们刚才所说的那个结构,我们来看一下这个结构的处理过程,首先他会把名字赋成Android virtual key device,然后写他的vendorproductversion,然后这个bustype就写BUS_VIRTUAL,虚拟设备都是写这个,然后可以使用ioctl来设置这个设备所支持的一些事件,当我们写入EV_KEY的时候就表明我们可以处理key这种type。再下面就是我们如何来让这个虚拟的键盘来支持我们的事件
我们在这里定义了一个keyMap,在这个keyMap中就是有9个值从0x010x09,然后通过ioctluinp_fd_keyUI_SET_KEYBIT,keyMap)来使我们这个设备支持我们这个keyMap,然后调用write的方法,把这个uinp_key写入到uinp_fd_key中,写入完之后就调用UI_DEV_CREATE来创建一个虚拟键盘,这时候虚拟键盘就创建完成了。下面我们来看一下如何创建一个虚拟的鼠标
他也是首先打开dev/uinput目录,然后初始化鼠标的一些参数以及创建我们的mouse设备,我们这个vendorproductversionbustype都是一样的,名字变成了Android virtual mouse device,当我们创建完成之后我们来设置一下鼠标所支持的具体的值,在这里它所设置的值包括我们的EV_KEYEV_REL,也就是xy,鼠标移动的一个过程,EV_KEY代表支持鼠标点击事件,支持滚轮事件,支持左击右击。然后还会直接把设置的值uinp_mouse写到我们uinp_fd_mouse中,写完之后直接调用UI_DEV_CTEATE来创建一个虚拟鼠标。
我们在来创建一个touch虚拟触摸屏,同样的还是打开dev/uinput目录,然后初始化我们的uinp_touch,我们这个vendorproductversionbustype还是都是一样的,名字变成了Android virtual touch device,然后后面有一点区别的
我们已经知道这个uinput device他有一些选项,这些选项就是为我们触摸屏所准备的,我们这个触摸屏他所支持的一些属性有ABS_MT_POSITION_XABS_MT_POSITION_YABS_MT_TRACKING_IDABS_MT_WIDTH_MAJORABS_MT_PRESSURE,设置完这些之后,当我们模拟触摸屏事件的时候,我们一定要记住我们支持的是哪些值,哪些值不支持,而我们后边那些基本上是不支持的,所以在我们写消息的时候会写这几个,他所支持的X轴方向的值最大是640Y轴是480,然后调用一下他所支持的EV_ABSABS_MT_POSITION_XABS_MT_POSITION_YABS_MT_TRACKING_IDABS_MT_WIDTH_MAJORABS_MT_PRESSURE,当我们把这个设置完之后就把uinp_touch写到uinp_fd_touch中,然后调用UI_DEV_CREATE,这样的话就完成了一个虚拟触摸屏的创建,当我们把这个过程完成之后,可以把它编译成二进制,然后放到我们的开发板上执行以下,可以使用getevent看一下我们dev/uinput目录下是否多出了这几个设备。

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

102

主题

315

帖子

16

粉丝