编写app,
1:完成对触摸屏和按键事件的捕捉
2:检测输入设备的插入和拔出(热插拔)
需要用到的activity类中的方法:
booleanonKeyDown(int keyCode,KeyEvent event) 按键
boolean onTouchEvent(MotionEvent event) 触摸屏
第二课
框架层分析:
下图为分析的框架
1.整体架构的分析(InputDispatcher是监听器,一旦InputReader接收到事件,便会通知InputDispatcher对事件进行处理)
进入inputmanager.cpp
-》status_t InputManager::start()此处产生俩个线程分支
分支1:主要负责分发事件(InputDispatcher:监听器)
-》mDispatcherThread->run("InputDispatcher",PRIORITY_URGENT_DISPLAY);
进入threads.cpp文件
-》status_t Thread::run(const char*name, int32_t priority, size_t stack)
-》res = androidCreateRawThreadEtc(_threadLoop,this, name, priority, stack, &mThread);
//调用线程对象中的_threadLoop函数
进入inputDispatcher.cpp
-》boolInputDispatcherThread::threadLoop()
-》void InputDispatcher::dispatchOnce()
分支2:主要负责读取事件(InputReader)
-》mReaderThread->run("InputReader",PRIORITY_URGENT_DISPLAY);
进入threads.cpp文件
-》status_t Thread::run(const char*name, int32_t priority, size_t stack)
-》res = androidCreateRawThreadEtc(_threadLoop,this, name, priority, stack, &mThread);
//调用线程对象中的_threadLoop函数
进入inputReader.cpp
-》bool InputReaderThread::threadLoop()
-》mReader->loopOnce();
-》size_tcount=mEventHub->getEvents(timeoutMillis,mEventBuffer,EVENT_BUFFER_SIZE);读取产生的输入事件
2.读取事件的流程:
进入inputmanager.cpp
-》status_t InputManager::start()此处产生俩个线程分支
-》mReaderThread->run("InputReader",PRIORITY_URGENT_DISPLAY);
进入threads.cpp文件
-》status_t Thread::run(const char*name, int32_t priority, size_t stack)
-》res = androidCreateRawThreadEtc(_threadLoop,this, name, priority, stack, &mThread);
//调用线程对象中的_threadLoop函数
进入inputReader.cpp
-》bool InputReaderThread::threadLoop()
-》mReader->loopOnce();
分支1:
-》mEventHub->getEvents(timeoutMillis,mEventBuffer, EVENT_BUFFER_SIZE);读取产生的输入事件,//mEventHub在EventHub.cpp中
进入EventHub.cpp
-》size_t EventHub::getEvents(int timeoutMillis,RawEvent* buffer, size_t bufferSize)
-》通过系统调用read函数读取事件
分支2:返回inputReader.cpp
-》mQueuedListener->flush(); //把读取的事件告诉inputdispatcher
进入inputlistener.cpp
-》void QueuedInputListener::flush()
-》args->notify(mInnerListener); //进入notify,mInnerListener其实就是mDispatcher
分支2.1按键事件
-》voidNotifyKeyArgs::notify(const sp<InputListenerInterface>&listener) const {
listener->notifyKey(this);(按键事件调用此notify)
-》voidInputDispatcher::notifyKey(const NotifyKeyArgs* args)调用inputdispatcher.cpp中的notifyKey(this)函数
分支2.2设备置位事件
-》voidNotifyDeviceResetArgs::notify(const sp<InputListenerInterface>&listener)
-》listener->notifyDeviceReset(this); //调用的是inputdispatcher.cpp中的notifyDeviceReset(this)函数
进入inputdispatcher.cpp
-》void InputDispatcher::notifyDeviceReset(constNotifyDeviceResetArgs* args)
mDispatcher(inputmanager.cpp)-》listener(inputreader.cpp)-》InnerListener(inputlistener.cpp)-》mInnerListener(inputlistener.cpp)-》Listener(inputlistener.cpp)
3.分发事件3.1对事件分类;3.2找到分发的目标3.3分发(socket机制)
-》进入inputmanager.cpp
-》status_t InputManager::start()此处产生俩个线程分支
分支1:主要负责分发事件(InputDispatcher:监听器)
-》mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
进入threads.cpp文件
-》status_t Thread::run(const char*name, int32_t priority, size_t stack)
-》res = androidCreateRawThreadEtc(_threadLoop,this, name, priority, stack, &mThread);
//调用线程对象中的_threadLoop函数
进入inputDispatcher.cpp
-》bool InputDispatcherThread::threadLoop()
-》void InputDispatcher::dispatchOnce()
-》dispatchOnceInnerLocked(&nextWakeupTime); //进入此函数
-》switch (mPendingEvent->type) {}//对inputreader传给的时间进行分类
-》如果是按键事件,就会调用:dispatchKeyLocked(currentTime,typedEntry, &dropReason, nextWakeupTime); //对事件进行处理
-》int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,entry,inputTargets, nextWakeupTime);确定分发目标,即发给那个窗口
-》dispatchEventLocked(currentTime,entry, inputTargets);//分发按键事件
-》ssize_t connectionIndex =getConnectionIndexLocked(inputTarget.inputChannel);建立连接
-》prepareDispatchCycleLocked(currentTime,connection, eventEntry, &inputTarget); //进行通信,进入分析
-》enqueueDispatchEntriesLocked(currentTime,connection, splitMotionEntry, inputTarget);
-》startDispatchCycleLocked(currentTime,connection); //进入分析
-》switch (eventEntry->type){}
-》(分发按键事件)Publish the key event.
status =connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
keyEntry->deviceId,keyEntry->source,
dispatchEntry->resolvedAction,dispatchEntry->resolvedFlags,
keyEntry->keyCode,keyEntry->scanCode,
keyEntry->metaState,keyEntry->repeatCount,keyEntry->downTime,
keyEntry->eventTime);
第三课(内核驱动分析)
1. input驱动编写流程:
Linux系统所支持的事件
第4课内核输入子系统原理分析
1子系统核心架构
2注册输入设备:
2.1那设备id和handle的id进行匹配,找到合适的处理者handler
2.2调用handler中的connect函数创建设备文件
进入input.c
-》int input_register_device(structinput_dev *dev)
-》list_for_each_entry(handler,&input_handler_list, node)input_attach_handler(dev, handler); //进入input_attach_handler函数//遍历input_handler_list链表中的所以handler,然后找出可以处理input_register_device(struct input_dev *dev)函数中
//传入的input_dev的handler
-》static intinput_attach_handler(struct input_dev *dev, struct input_handler *handler)
-》id = input_match_device(handler,dev); //通过设备和处理函数进行匹配,主要是通过事件驱动层的id和dev的id进行匹配
-》error = handler->connect(handler,dev, id); //如果匹配成功,开始建立连接
//如果是按键事件,就会调用evdev.c中struct input_handler evdev_handler 结构中的connect函数
-》static int evdev_connect(structinput_handler *handler, struct input_dev *dev,const struct input_device_id *id) 此函数会创建设备节点,并与在input.c中的input_init函数中注册的字符设备关联
3上报事件(以按键事件为例)
-》input_report_event() //在input.h中
-》input_event(dev, EV_KEY, code,!!value);
-》if (is_event_supported(type,dev->evbit, EV_MAX))//判断上报的事件之前是否用set_bit函数申明过
-》input_handle_event(dev, type, code,value); //进入分析
-》input_pass_event(dev, type, code,value); //进入分析
-》handle->handler->event(handle,type, code, value); //调用之前匹配好的handler中的event函数进行处,//如按键事件就会调用evdev.c中input_handler evdev_handler = {.event = evdev_event函数
-》static void evdev_event(structinput_handle *handle,unsigned int type, unsigned int code, int value)
-》对事件进行打包event.time.tv_sec = ts.tv_sec;
event.time.tv_usec = ts.tv_nsec /NSEC_PER_USEC;
event.type = type;
event.code = code;
event.value = value;
-》evdev_pass_event(client,&event); //进去此函数//把打包好的event事件保存在buffer中,当应用程序要读取事件是,就会从buffer中读取
4:应用程序读取事件过程;以read为例
进入input.c
-》static int __init input_init(void)
-》err = register_chrdev(INPUT_MAJOR,"input", &input_fops); //注册字符设备驱动
-》static const struct file_operationsinput_fops = {
.owner = THIS_MODULE,
.open = input_open_file, //进入打开函数
.llseek = noop_llseek,
};
-》static int input_open_file(structinode *inode, struct file *file)
-》new_fops = fops_get(handler->fops);//把handler中的操作函数集赋值给new_fops
-》 file->f_op= new_fops; //换成新的操作函数集
-》之后会进入event.c中,调用static struct input_handler evdev_handler = {
.event =evdev_event, //事件处理函数
.connect=evdev_connect, //连接函数,主要用于创建设备节点,并与input.c中input_init函数中注册的驱动关联
.disconnect = evdev_disconnect,
.fops =&evdev_fops,
.minor =EVDEV_MINOR_BASE,
.name ="evdev",
.id_table=evdev_ids,
};中的fops
-》static const struct file_operationsevdev_fops = {
.owner =THIS_MODULE,
.read =evdev_read,
.write =evdev_write,
.poll =evdev_poll,
.open =evdev_open,
.release =evdev_release,
.unlocked_ioctl = evdev_ioctl,
#ifdefCONFIG_COMPAT
.compat_ioctl = evdev_ioctl_compat,
#endif
.fasync =evdev_fasync,
.flush =evdev_flush,
.llseek =no_llseek,
};
-》static ssize_t evdev_read(struct file*file, char __user *buffer,size_t count, loff_t *ppos)
-》evdev_fetch_next_event(client,&event)) { //从buffer中读取保存的事件,
-》input_event_to_user(buffer + retval,&event) //把事件提交给用户空间
-》copy_to_user(buffer, event,sizeof(struct input_event))//在input-compat.c中