在讲解安卓输入系统之前,我们先了解一下Linux编程基础的inotify与epoll_P,在我们使用笔记本电脑的时候,感觉自带的键盘并不太好用,一般我们都会外接一个键盘,并且当我们按键按下的时候,笔记本能分辨是哪个键盘按下,都会有一下功能: 1.键盘即插即用。 2.可以使用任意一个键盘 那么出现了两个问题: 1.如何检测键盘的接入和拔出 2.怎么知道是哪个键盘按下按键 对于第一个问题有多个: 1.使用hotplug:内核发现键盘插入或者拔出,会启动一个hotplug进程,该进程会发送一个消息给输入系统,然后输入系统进行处理(android系统) 2.inotify:输入系统使用inotify来监测一个/dev/input目录,当有键盘接入或者拔出时,该目录下就会创建或者删除设备节点,该些变化通过inotify就会被察觉,然后传递消息给输入子系统,相对于hotplug少了【启动一个hotplug进程】 对于第二个问题:我们使用epoll机制,epoll可以监测多个文件,每个键盘对应一个文件,那个键盘有输入,对应的文件就会发生变化,这样就知道是哪个键盘在进行输入。
在编写代码之前,我们先简述一下流程 inotify的使用(检测目录/文件的变化)
1.fd = inotify_init()
2.inotify_add_watch(目录/文件,创建/删除)
3.read(fd):返回一个或者多个结构体如下
struct inotify_event {
__s32 wd; /* watch descriptor */
__u32 mask; /* watch mask(发生的变化,创建或者删除) */
__u32 cookie; /* cookie to synchronize two events */
__u32 len; /* length (including nulls) of name (那么的长度)*/
char name[0]; /* stub for possible name(发生变化的文件) */
};
下面我们编写程序,了解怎么实现inotify与epoll,可以参考:SDK/frameworks\native\services\inputflinger\EventHub.cpp
程序编写-inotify创建inotify.c文件,编写代码如下:
#include
#include
#include
#include
#include
/*
*参考: frameworks\native\services\inputflinger\EventHub.cpp
*/
/*Usage: inotify */
int read_process_inotify_fd(int fd)
{
int res;
char event_buf[512];
int event_size;
int event_pos = 0;
struct inotify_event *event;
/* read */
res = read(fd, event_buf, sizeof(event_buf));
if(res = (int)sizeof(*event)) {
event = (struct inotify_event *)(event_buf + event_pos);
//printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
if(event->len) {
if(event->mask & IN_CREATE) {
printf("create file: %s\n", event->name);
} else {
printf("delete file: %s\n", event->name);
}
}
event_size = sizeof(*event) + event->len;
res -= event_size;
event_pos += event_size;
}
return 0;
}
int main(int argc, char **argv)
{
int mINotifyFd;
int result;
if (argc != 2)
{
printf("Usage: %s \n", argv[0]);
return -1;
}
/* inotify_init */
mINotifyFd = inotify_init();
/* add watch */
result = inotify_add_watch(mINotifyFd, argv[1], IN_DELETE | IN_CREATE);
/* read */
while (1)
{
read_process_inotify_fd(mINotifyFd);
}
return 0;
}
该代码比较简单所以重诉一下大致流程(从main函数开始看起):
read_process_inotify_fd(int fd)
read(fd, event_buf, sizeof(event_buf));//当我们制定的目录删除或者创建了文件,该函数返回
event->mask & IN_CREATE //判断为创建或者删除
main()
mINotifyFd = inotify_init(); //获取一个句柄
inotify_add_watch(mINotifyFd, argv[1], IN_DELETE | IN_CREATE); //根据传入的argv[1]目录进行监测(监测:创建和删除)
while (1)
read_process_inotify_fd(mINotifyFd);
编写文件之后,我们下载到虚拟机上进行编译执行:gcc inotify.c -o inotify 然后创建一个目录: mkdir tmp 后台运行该程序:./inotify tmp/ & 然后在tmp目录下创建或者删除文件就能看见打印信息
下面我们开始编写epoll.c文件
程序编写-epoll.c在编写代码之前我们先讲解一个epoll的使用方法,用来检测多个文件(之前检测的目录): 1.有无数据读出 2.有无空间供写入 我们依旧还是参考SDK/frameworks\native\services\inputflinger\EventHub.cpp 创建epoll.c文件,编写代码如下:
#include
#include
#include
#include
#include
#include
#include
#if 0
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
#endif
#define DATA_MAX_LEN 500
/* usage: epoll [file2] [file3] ... */
int add_to_epoll(int fd, int epollFd)
{
int result;
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
eventItem.data.fd = fd;
result = epoll_ctl(epollFd, EPOLL_CTL_ADD, fd, &eventItem);
return result;
}
void rm_from_epoll(int fd, int epollFd)
{
epoll_ctl(epollFd, EPOLL_CTL_DEL, fd, NULL);
}
int main(int argc, char **argv)
{
int mEpollFd;
int i;
char buf[DATA_MAX_LEN];
// Maximum number of signalled FDs to handle at a time.
static const int EPOLL_MAX_EVENTS = 16;
// The array of pending epoll events and the index of the next event to be handled.
struct epoll_event mPendingEventItems[EPOLL_MAX_EVENTS];
if (argc
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?