Recovery support touch


代码是基于android4.1的。

1recovery输入事件及处理分析

1.1时序图


1.2代码分析

1.2.1 输入事件初始化

Recovery的入口是recovery.cpp中的main函数,当然会根据参数的不同,进入recovery的模式也就不一样,这里我们就不一一介绍了,我们这里主要看图形界面模式,即有个人机交互的见面,用户可以通过按键选择不同的执行操作。

根据上面的时序图中,我们可以看到,在main函数中,需要做一些界面显示、输入事件的初始化工作。而在这里,我们就主要先关注输入事件的初始化工作,即在main函数中调用了ui.cppInit()方法,下面看看其代码:

void RecoveryUI::Init(){

   ev_init(input_callback, NULL); //输入事件初始化,并注册回调函数

   pthread_create(&input_t, NULL, input_thread, NULL);//创建新的线程读取输入事件

}

在该方法中,主要完成了两个动作,第一就是初始化话输入事件,注册了回调函数,当有输入事件的时候回调,第二就是创建了一个新的线程,用于读取输入事件的数据。

我们先看看events.c中的ev_init()方法,输入事件初始化,代码如下:

int ev_init(ev_callbackinput_cb, void *data)

  ......

    dir =opendir("/dev/input");//打开文件

   if(dir != 0) {

       while((de = readdir(dir))) {

           unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];

           if(strncmp(de->d_name,"event",5))continue;

           fd = openat(dirfd(dir),de->d_name, O_RDONLY); //打开设备节点

           if(fd < 0) continue;

           

           if (ioctl(fd, EVIOCGBIT(0,sizeof(ev_bits)), ev_bits) < 0){//获取节点特性

               close(fd);

               continue;

           }

           //判断是否是按键设备

           if (!test_bit(EV_KEY, ev_bits)&& !test_bit(EV_REL,ev_bits) ) {

               close(fd);

               continue;

           }

           //保存设备的信息

           ev_fds[ev_count].fd = fd;

           ev_fds[ev_count].events = POLLIN;

           ev_fdinfo[ev_count].cb = input_cb;

           ev_fdinfo[ev_count].data = data;

           ev_count++;

           ev_dev_count++;

           if(ev_dev_count == MAX_DEVICES) break;

       }

   }

   return 0;

}

#define test_bit(bit, array) \

   ((array)[(bit)/BITS_PER_LONG] & (1<< ((bit) %BITS_PER_LONG)))

代码看起来还是非常简单的,输入设备的设备节点都在/dev/input/目录下,所以需要扫面下面所有的设备节点。

调用openat()打开设备节点,这是linux的系统调用,这里就不说了。

调用ioctl,并用宏EVIOCGBIT产生参数,获取一个设备的特性,这里特性会说明该设备是按键设备还是触摸设备等,并将特性存在中数组ev_bits中。

定义了test_bit的宏,用于判断ev_bits中的特性是否是我们想要的,在linux input系统中,EV_KEY指的是按键设备,EV_REL值相对坐标,如光标移动。看到这里了,如果我们想要接受触摸消息,那么我将在这里添加EV_ABS的支持。后续会说明添加具体方法。

当打开的设备是我们想要监听的设备的时候,我们将设备节点的文件描述符等信息添加到ev_fds结构体数组中,还有将注册的回调函数input_cb添加到结构体数据ev_fdinfo中。

到此就完成了输入事件的初始化,接下来就看在创建的新线程中读取输入事件。

1.2.2 创建线程读取输入事件

在前面的RecoveryUI::Init()方法中,我们看到了这么一句:

 pthread_create(&input_t, NULL,input_thread, NULL); //创建新的线程读取输入事件

调用了pthread_create()方法创建新的线程,该方法的原型如下:

int pthread_create(pthread_t*restricttidp,const pthread_attr_t *restrict_attr,void**start_rtn)(void*),void *restrict arg);

若成功则返回0,否则返回出错编号  

返回成功时,由tidp指向的内存单元被设置为新创建线程的线程IDattr参数用于制定各种不同的线程属性。新创建的线程从start_rtn函数的地址开始运行,该函数只有一个万能指针参数arg,如果需要向start_rtn函数传递的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg的参数传入。

linux下用C开发多线程程序,Linux系统下的多线程遵循POSIX线程接口,称为pthread。  由restrict修饰的指针是最初唯一对指针所指向的对象进行存取的方法,仅当第二个指针基于第一个时,才能对对象进行存取。对对象的存取都限定于基于由restrict修饰的指针表达式中。restrict修饰的指针主要用于函数形参,或指向由malloc()分配的内存空间。restrict数据类型不改变程序的语义。编译器能通过作出restrict修饰的指针是存取对象的唯一方法的假设,更好地优化某些类型的例程。下面看四个参数:

第一个参数为指向线程标识符指针。  

第二个参数用来设置线程属性。  

第三个参数是线程运行函数的起始地址。  

第四个参数是运行函数的参数。  

另外,在编译时注意加上-lpthread参数,以调用链接库。因为pthread并非Linux系统的默认库。

在我们这里用到的代码中,第一个参数的定义为:pthread_t input_t;为指向线程标识符指针。接下来我们主要看新线程的入口函数input_thread()方法,代码如下:

void*RecoveryUI::input_thread(void *cookie)

{

    for(;;) {

       if(!ev_wait(-1)) //查看是否有输入事件

           ev_dispatch();//有输入事件,那么将派发输入事件

   }

   return NULL;

}

在一个循环里面不断的查询是否有输入事件,那么,我们看看events.c中的ev_wait()方法,代码如下:

int ev_wait(int timeout)

{

    intr;

    r =poll(ev_fds, ev_count,timeout);

    if(r <= 0)

       return -1;

   return 0;

}

还记得在输入事件初始化的时候,将按键等我们想监听的设备点信息添加到了ev_fds结构体中,在这里我们将用到了。

系统调用poll()方法,如果ev_fds包含的设备节点中有消息,那么返回的值r将大于0,所以ev_wait()方法的返回值为0。再回头看看input_thread()方法,当ev_wait()返回值等于零的时候,将调用ev_dispatch()派发输入消息。那么我们看看events.c中的该方法代码:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值