android input system(frameworks) analysis -- InputManager

对input系统在framework层的分析从一次触摸屏丢失上报事件开始:由于设备节点/dev/input/input0存在,而且getevent能响应点触摸屏的动作,所以把问题定位到了EventHub和InputManager这一层。


InputManager的结构很简单,对外开放

[plain]  view plain copy
  1. virtual status_t start();  
  2. virtual status_t stop();  
  3. virtual sp<InputReaderInterface> getReader();  
  4. virtual sp<InputDispatcherInterface> getDispatcher();  

四个成员函数,内部带有私有成员

[plain]  view plain copy
  1. sp<InputReaderInterface> mReader;  
  2. sp<InputReaderThread> mReaderThread;  
  3. sp<InputDispatcherInterface> mDispatcher;  
  4. sp<InputDispatcherThread> mDispatcherThread;  
其构造过程也很简单:

[plain]  view plain copy
  1. mDispatcher = new InputDispatcher(dispatcherPolicy);  -- 根据输入的参数构造一个dispatcher  
  2. mReader = new InputReader(eventHub, readerPolicy, mDispatcher); -- 根据参数构造一个inputreader  
  3. initialize();  

[plain]  view plain copy
  1. void InputManager::initialize() {  
  2.     mReaderThread = new InputReaderThread(mReader); -- 产生reader线程用于从设备节点读取input event  
  3.     mDispatcherThread = new InputDispatcherThread(mDispatcher); -- 产生dispachter线程分发event  
  4. }  
InputManager的start主要就是让这两个线程跑起来:

[plain]  view plain copy
  1. status_t InputManager::start() {  
  2.     status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);  
  3.                ...  
  4.     result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);  
  5.                ...  
  6.     return OK;  
  7. }  

====================================================================================================================

接着先来分析InputReader:

InputReaderThread run之后会重复的调用

[plain]  view plain copy
  1. bool InputReaderThread::threadLoop() {  
  2.     mReader->loopOnce();  
  3.     return true;  
  4. }  

亦即mReader->loopOnce();

[plain]  view plain copy
  1. void InputReader::loopOnce() {  
  2.     RawEvent rawEvent;  
  3.     mEventHub->getEvent(& rawEvent);  
  4.     process(& rawEvent);  
  5. }  


InputReader上来就找EventHub要数据(getEvent()),所以我们要先看看EventHub的getEvent都做了些什么工作:

[cpp]  view plain copy
  1. bool EventHub::getEvent(RawEvent* outEvent)  
  2. {  
  3.     outEvent->deviceId = 0;  
  4.           ...  
  5.   
  6.     // 第一次调用getEvent的时候,需要调用openPlatformInput来搜索输入系统来查找可用的设备  
  7.     if (!mOpened) {  
  8.         mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;  
  9.         mOpened = true;  
  10.         mNeedToSendFinishedDeviceScan = true;  
  11.     }  
  12. }  
[cpp]  view plain copy
  1. bool EventHub::openPlatformInput(void)  
  2. {  
  3.     // 为poll()调用作准备  
  4.     mFDCount = 1;  
  5.     mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));  
  6.     mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));  
  7.     mFDs[0].events = POLLIN;  
  8.     mFDs[0].revents = 0;  
  9.     mDevices[0] = NULL;  
  10.           ...  
  11.     // 上面有赋值device_path = "/dev/input"  
  12.     res = scanDir(device_path);  
  13.           ...  
  14.     return true;  
  15. }  


接着又绕到scanDir()里面,这个函数无非就是对/dev/input这个目录的每个文件执行openDevice(),后者才是真正干活的:

[cpp]  view plain copy
  1. int EventHub::openDevice(const char *deviceName) {  
  2.     int version;  
  3.     int fd;  
  4.     struct pollfd *new_mFDs;  
  5.     device_t **new_devices;  
  6.     char **new_device_names;  
  7.     char name[80];  
  8.     char location[80];  
  9.     char idstr[80];  
  10.     struct input_id id;  
  11.   
  12.     LOGV("Opening device: %s", deviceName);  
  13.   
  14.     AutoMutex _l(mLock);  
  15.     // 根据路径打开文件获取version, id, name等信息  
  16.     fd = open(deviceName, O_RDWR);  
  17.     if(fd < 0) ...  
  18.     if(ioctl(fd, EVIOCGVERSION, &version))   
  19.         ...  
  20.     if(ioctl(fd, EVIOCGID, &id))   
  21.         ...  
  22.     if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1)   
  23.         ...  
  24.     // check to see if the device is on our excluded list - 如果此设备在排除名单内,忽略它  
  25.     List<String8>::iterator iter = mExcludedDevices.begin();  
  26.     List<String8>::iterator end = mExcludedDevices.end();  
  27.     for ( ; iter != end; iter++) {  
  28.         ...  
  29.     }  
  30.     // 读取location, idstr等信息  
  31.     if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1)   
  32.         ...  
  33.     if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1)   
  34.         ...  
  35.     // 将设备文件设置为非阻塞  
  36.     if (fcntl(fd, F_SETFL, O_NONBLOCK))   
  37.         ...  
  38.     // 在mDeviceById数组中寻找“空位”,扩充mDeviceById的空间并把新device加到尾部  
  39.     int devid = 0;  
  40.     while (devid < mNumDevicesById) {  
  41.         if (mDevicesById[devid].device == NULL) {  
  42.             break;  
  43.         }  
  44.         devid++;  
  45.     }  
  46.     if (devid >= mNumDevicesById) {  
  47.         device_ent* new_devids = (device_ent*)realloc(mDevicesById,  
  48.                 sizeof(mDevicesById[0]) * (devid + 1));  
  49.         if (new_devids == NULL) {  
  50.             LOGE("out of memory");  
  51.             return -1;  
  52.         }  
  53.         mDevicesById = new_devids;  
  54.         mNumDevicesById = devid+1;  
  55.         mDevicesById[devid].device = NULL;  
  56.         mDevicesById[devid].seq = 0;  
  57.     }  
  58.   
  59.     mDevicesById[devid].seq = (mDevicesById[devid].seq+(1<<SEQ_SHIFT))&SEQ_MASK;  
  60.     if (mDevicesById[devid].seq == 0) {  
  61.         mDevicesById[devid].seq = 1<<SEQ_SHIFT;  
  62.     }  
  63.     // 为后面用poll()来获取kernel层上报的input event作准备  
  64.     new_mFDs = (pollfd*)realloc(mFDs, sizeof(mFDs[0]) * (mFDCount + 1));  
  65.     new_devices = (device_t**)realloc(mDevices, sizeof(mDevices[0]) * (mFDCount + 1));  
  66.     if (new_mFDs == NULL || new_devices == NULL) {  
  67.         LOGE("out of memory");  
  68.         return -1;  
  69.     }  
  70.     mFDs = new_mFDs;  
  71.     mDevices = new_devices;  
  72.   
  73.     device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName, name);  
  74.     if (device == NULL) {  
  75.         LOGE("out of memory");  
  76.         return -1;  
  77.     }  
  78.   
  79.     device->fd = fd;  
  80.     mFDs[mFDCount].fd = fd;  
  81.     mFDs[mFDCount].events = POLLIN;  
  82.     mFDs[mFDCount].revents = 0;  
  83.   
  84.     // Figure out the kinds of events the device reports.  
  85.     // 分辨本device的输入类型: keypad? touchscreen? gamepad?  
  86.     uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];  
  87.     memset(key_bitmask, 0, sizeof(key_bitmask));  
  88.     // 测试本device是否为键盘,是的话把key_bitmask保存下来  
  89.     LOGV("Getting keys...");  
  90.     if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) {  
  91.        ...  
  92.     }  
  93.     // 是否为轨迹球或鼠标  
  94.     // See if this is a trackball (or mouse).  
  95.     if (test_bit(BTN_MOUSE, key_bitmask)) {  
  96.         ...  
  97.     }  
  98.     // 是否为touchscreen,是否支持多点触摸  
  99.     // See if this is a touch pad.  
  100.     uint8_t abs_bitmask[sizeof_bit_array(ABS_MAX + 1)];  
  101.     memset(abs_bitmask, 0, sizeof(abs_bitmask));  
  102.     LOGV("Getting absolute controllers...");  
  103.     if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0) {  
  104.         ...  
  105.     }  
  106.   
  107. #ifdef EV_SW  
  108.     // 是否为switch设备,这个宏没有打开  
  109. #endif  
  110.     // 如果是键盘的话,加载keypad-layout,即/usr/keylayout/中的xxx.kl文件  
  111.     if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) {  
  112.            ...  
  113.         status_t status = device->layoutMap->load(keylayoutFilename);  
  114.         if (status) {  
  115.             LOGE("Error %d loading key layout.", status);  
  116.         }  
  117.            ...  
  118.         // tell the world about the devname (the descriptive name) - 找一个首选keyboard出来  
  119.         if (!mHaveFirstKeyboard && !defaultKeymap && strstr(name, "-keypad")) {  
  120.             // the built-in keyboard has a well-known device ID of 0,  
  121.             // this device better not go away.  
  122.             mHaveFirstKeyboard = true;  
  123.             mFirstKeyboardId = device->id;  
  124.             property_set("hw.keyboards.0.devname", name);  
  125.         } else {  
  126.             // ensure mFirstKeyboardId is set to -something-.  
  127.             if (mFirstKeyboardId == 0) {  
  128.                 mFirstKeyboardId = device->id;  
  129.             }  
  130.         }  
  131.         // 如果键盘有数字键,方向键,游戏控制键等特殊按钮,都一一标记到classes中  
  132.         if (hasKeycodeLocked(device, AKEYCODE_Q))   
  133.             ...  
  134.         if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) &&  
  135.                 hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) &&  
  136.                 hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) &&  
  137.                 hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) &&  
  138.                 hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) {  
  139.             device->classes |= INPUT_DEVICE_CLASS_DPAD;  
  140.         }  
  141.           
  142.         // See if this device has a gamepad.  
  143.         for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) {  
  144.             if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) {  
  145.                 device->classes |= INPUT_DEVICE_CLASS_GAMEPAD;  
  146.                 break;  
  147.             }  
  148.         }  
  149.   
  150.         LOGI("New keyboard: device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n",  
  151.                 device->id, name, propName, keylayoutFilename);  
  152.     }  
  153.   
  154.     // 如果不知道这个device是啥类型,忽略之  
  155.     if (device->classes == 0) {  
  156.        ...  
  157.     }  
  158.   
  159.     // 加到mDevicesById和mOpeningDevices中,回头getEvent()会处理mOpenningDevices链表中的新增device  
  160.   
  161.     mDevicesById[devid].device = device;  
  162.     device->next = mOpeningDevices;  
  163.     mOpeningDevices = device;  
  164.     mDevices[mFDCount] = device;  
  165.   
  166.     mFDCount++;  
  167.     return 0;  
  168. }  



初始化折腾一番后,又回到了getEvent中来,getEvent除了在第一此进入需要加设备外,其主体就是一个大循环:

[cpp]  view plain copy
  1. bool EventHub::getEvent(RawEvent* outEvent)  
  2. {  
  3.       ....  
  4.   
  5.     // main loop here - 主循环体  
  6.     for (;;) {  
  7.         // Report any devices that had last been removed. - 当有设备从系统中移除时  
  8.         if (mClosingDevices != NULL) {  
  9.              ...  
  10.         }  
  11.   
  12.     // Report any devices that had last been added - 当有设备加入到系统中时  
  13.         if (mOpeningDevices != NULL) {  
  14.             device_t* device = mOpeningDevices;  
  15.             LOGV("Reporting device opened: id=0x%x, name=%s\n",  
  16.                  device->id, device->path.string());  
  17.             mOpeningDevices = device->next;  
  18.             if (device->id == mFirstKeyboardId) {  
  19.                 outEvent->deviceId = 0;  
  20.             } else {  
  21.                 outEvent->deviceId = device->id;  
  22.             }  
  23.             outEvent->type = DEVICE_ADDED;  
  24.             outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);  
  25.             mNeedToSendFinishedDeviceScan = true;  
  26.             return true// 一个设备上报一个DEVICE_ADDED事件  
  27.         }  
  28.   
  29.     // After finish scanning all input devices in system, send finished siganal at boot time   
  30.         if (mNeedToSendFinishedDeviceScan) {  
  31.             mNeedToSendFinishedDeviceScan = false;  
  32.             outEvent->type = FINISHED_DEVICE_SCAN;  
  33.             outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);  
  34.             return true;  
  35.         }  
  36.   
  37.         // 下面为普通event获取和上报过程  
  38.              ... ...  
  39.     }  
  40. }  

从上面的代码段可知,对于mOpeningDevices中的device,getEvent()调用都是每读取一个马上上报DEVICE_ADDED事件并返回。所以如果我们的系统中有一个keypad和一个touchscreen,则在扫描阶段就会有3次getEvent()返回:键盘的DEVICE_ADDED,触摸屏的DEVICE_ADDED和表示扫描完成的FINISHED_DEVICE_SCAN。


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


上文对EventHub getEvent()的分析,InputReader::loopOnce()在getEvent()成功返回直接,就调用process(& rawEvent);开始分析报上来的rawEvent:

[cpp]  view plain copy
  1. void InputReader::process(const RawEvent* rawEvent) {  
  2.     switch (rawEvent->type) {  
  3.     case EventHubInterface::DEVICE_ADDED:  // 加入新设备  
  4.         addDevice(rawEvent->deviceId);  
  5.         break;  
  6.   
  7.     case EventHubInterface::DEVICE_REMOVED:  // 移除完成  
  8.         removeDevice(rawEvent->deviceId);  
  9.         break;  
  10.   
  11.     case EventHubInterface::FINISHED_DEVICE_SCAN: // 扫描完成,每次增加或移除设备后都会引发此事件  
  12.         handleConfigurationChanged(rawEvent->when);  
  13.         break;  
  14.   
  15.     default:  
  16.         consumeEvent(rawEvent); // 普通event,按键触摸屏事件就在这个分支上处理  
  17.         break;  
  18.     }  
  19. }  

rawEvent的type对应着getEvent里面上报的几种类型,下面根据不同的分支看看inputReader如何处理这样事件。先看看一些关键数据结构:

[cpp]  view plain copy
  1. struct RawEvent {  
  2.     nsecs_t when; // when this happened  
  3.     int32_t deviceId; // from which device  
  4.     int32_t type; // DEVICE_REMOVED, DEVICE_ADDED, FINISHED_DEVICE_SCAN or others  
  5.     int32_t scanCode; // original event code from kernel driver  
  6.     int32_t keyCode; // code after keycode-mapping while this is a EV_KEY event  
  7.     int32_t value; // event value  
  8.     uint32_t flags; // additional info  
  9. };  

DEVICE_ADD事件的处理:

[cpp]  view plain copy
  1. void InputReader::addDevice(int32_t deviceId) {  
  2.     String8 name = mEventHub->getDeviceName(deviceId); // eventHub根据自己的mDevicesById返回device的name和classes  
  3.     uint32_t classes = mEventHub->getDeviceClasses(deviceId);  
  4.     // 调用createDevice建立一个与底层input device一一对应的device  
  5.     InputDevice* device = createDevice(deviceId, name, classes);  
  6.     device->configure();  
  7.        ...  
  8.     bool added = false// 如果此device之前不存在,则加到名为mDevices的KeyedVector中  
  9.     { // acquire device registry writer lock  
  10.         RWLock::AutoWLock _wl(mDeviceRegistryLock);  
  11.   
  12.         ssize_t deviceIndex = mDevices.indexOfKey(deviceId);  
  13.         if (deviceIndex < 0) {  
  14.             mDevices.add(deviceId, device);  
  15.             added = true;  
  16.         }  
  17.     } // release device registry writer lock  
  18.         ....  
  19. }  
createDevice()函数中先new InputDevice创建对象,然后根据device的classes调用device->addMapper加入mapper,这些mapper对后面分析的普通event的处理有重要的作用。device->configure()函数做一些配置工作,如果device有校准数据的话会调用getInputDeviceCalibration进行校准,还会调用上述mapper的configure函数配置mapper,不过mapper的这个函数一般直接置空,只有TouchInputMapper::configure()会针对触摸屏校准做些工作:

[cpp]  view plain copy
  1. void InputDevice::configure() {  
  2.     if (! isIgnored()) {  
  3.         mContext->getPolicy()->getInputDeviceCalibration(mName, mCalibration);  
  4.     }  
  5.   
  6.     mSources = 0;  
  7.     // 调用mapper的configure和getSources来设置device的mSource来标示种类,但是mapper本身又是根据devices的classes来选的,很绕……  
  8.     size_t numMappers = mMappers.size();  
  9.     for (size_t i = 0; i < numMappers; i++) {  
  10.         InputMapper* mapper = mMappers[i];  
  11.         mapper->configure();  
  12.         mSources |= mapper->getSources();  
  13.     }  
  14. }  


DEVICE_REMOVED事件的处理:

[cpp]  view plain copy
  1. void InputReader::removeDevice(int32_t deviceId) {  
  2.     bool removed = false;  
  3.     InputDevice* device = NULL;  
  4.     { // acquire device registry writer lock  
  5.         RWLock::AutoWLock _wl(mDeviceRegistryLock);  
  6.         // 最主要的是从mDevices中将其移除  
  7.         ssize_t deviceIndex = mDevices.indexOfKey(deviceId);  
  8.         if (deviceIndex >= 0) {  
  9.             device = mDevices.valueAt(deviceIndex);  
  10.             mDevices.removeItemsAt(deviceIndex, 1);  
  11.             removed = true;  
  12.         }  
  13.     } // release device registry writer lock  
  14.         ...  
  15.     device->reset(); // reset会引发devices的mapper的reset()  
  16.       
  17.     delete device;  
  18. }  

FINISHED_DEVICE_SCAN事件的处理:

[cpp]  view plain copy
  1. void InputReader::handleConfigurationChanged(nsecs_t when) {  
  2.     // Reset global meta state because it depends on the list of all configured devices.  
  3.     updateGlobalMetaState();  
  4.   
  5.     // Update input configuration.更新inputReader当前的设置  
  6.     updateInputConfiguration();  
  7.   
  8.     // Enqueue configuration changed.通知dispatcher了  
  9.     mDispatcher->notifyConfigurationChanged(when);  
  10. }  


普通输入事件的处理:

在函数consumeEvent中会根据rawEvent的deviceId从mDevices中选择上报事件的device然后调用device->process(rawEvent)来处理,device再调用自己mapper的process来处理,因此对于不同的mapper就有了不同的process具体实现。下面选择MultiTouchInputMapper的process函数分析:

[cpp]  view plain copy
  1. void MultiTouchInputMapper::process(const RawEvent* rawEvent) {  
  2.     switch (rawEvent->type) {  
  3.     case EV_ABS: {  
  4.         uint32_t pointerIndex = mAccumulator.pointerCount;  
  5.         Accumulator::Pointer* pointer = & mAccumulator.pointers[pointerIndex];  
  6.   
  7.         switch (rawEvent->scanCode) {  
  8.         case ABS_MT_POSITION_X:  
  9.             LOGE("-MT X-");           
  10.             pointer->fields |= Accumulator::FIELD_ABS_MT_POSITION_X;  
  11.             pointer->absMTPositionX = rawEvent->value;  
  12.             break;  
  13.         case ABS_MT_POSITION_Y:  
  14.              LOGE("-MT Y-");              
  15.             pointer->fields |= Accumulator::FIELD_ABS_MT_POSITION_Y;  
  16.             pointer->absMTPositionY = rawEvent->value;  
  17.             break;  
  18.         case ABS_MT_TOUCH_MAJOR:  
  19.             pointer->fields |= Accumulator::FIELD_ABS_MT_TOUCH_MAJOR;  
  20.             pointer->absMTTouchMajor = rawEvent->value;  
  21.             break;  
  22.         case ABS_MT_TOUCH_MINOR:  
  23.             pointer->fields |= Accumulator::FIELD_ABS_MT_TOUCH_MINOR;  
  24.             pointer->absMTTouchMinor = rawEvent->value;  
  25.             break;  
  26.         case ABS_MT_WIDTH_MAJOR:  
  27.             pointer->fields |= Accumulator::FIELD_ABS_MT_WIDTH_MAJOR;  
  28.             pointer->absMTWidthMajor = rawEvent->value;  
  29.             break;  
  30.         case ABS_MT_WIDTH_MINOR:  
  31.             pointer->fields |= Accumulator::FIELD_ABS_MT_WIDTH_MINOR;  
  32.             pointer->absMTWidthMinor = rawEvent->value;  
  33.             break;  
  34.         case ABS_MT_ORIENTATION:  
  35.             pointer->fields |= Accumulator::FIELD_ABS_MT_ORIENTATION;  
  36.             pointer->absMTOrientation = rawEvent->value;  
  37.             break;  
  38.         case ABS_MT_TRACKING_ID:  
  39.             pointer->fields |= Accumulator::FIELD_ABS_MT_TRACKING_ID;  
  40.             pointer->absMTTrackingId = rawEvent->value;  
  41.             break;  
  42.         case ABS_MT_PRESSURE:  
  43.             pointer->fields |= Accumulator::FIELD_ABS_MT_PRESSURE;  
  44.             pointer->absMTPressure = rawEvent->value;  
  45.             break;  
  46.         }  
  47.         break;  
  48.     }  
  49.   
  50.     case EV_SYN:  
  51.         switch (rawEvent->scanCode) { // 对于多点触摸来说,一次可以向dispatcher报1~10个pointer的数据(10点是android2.3的上限)  
  52.         case SYN_MT_REPORT: {  // 一次SYN_MT_REPORT表示一个手指的触摸数据已经接收完毕,包括X,Y,PRESSURE等  
  53.             // MultiTouch Sync: The driver has returned all data for *one* of the pointers.  
  54.             uint32_t pointerIndex = mAccumulator.pointerCount;  
  55.             LOGE("-ONE-");  
  56.             if (mAccumulator.pointers[pointerIndex].fields) {  
  57.                 if (pointerIndex == MAX_POINTERS) {  
  58.                     LOGW("MultiTouch device driver returned more than maximum of %d pointers.",  
  59.                             MAX_POINTERS);  
  60.                 } else {  
  61.                     pointerIndex += 1;  
  62.                     mAccumulator.pointerCount = pointerIndex;  
  63.                 }  
  64.             }  
  65.   
  66.             mAccumulator.pointers[pointerIndex].clear();  
  67.             break;  
  68.         }  
  69.         // 当多点的数据都齐全之后会收到SYN_REPORT事件,这时可以向dispatcher发送了  
  70.         case SYN_REPORT:  
  71.             LOGE("-SYN MT-");              
  72.             sync(rawEvent->when);  
  73.             break;  
  74.         }  
  75.         break;  
  76.     }  
  77. }  


MultiTouchInputMapper::sync的主要作用是,把process中接收到的多个pointer数据做审核,例如屏蔽掉不合要求的点,对缺失的参数设置成默认等。

[cpp]  view plain copy
  1. void MultiTouchInputMapper::sync(nsecs_t when) {  
  2.     static const uint32_t REQUIRED_FIELDS =  
  3.             Accumulator::FIELD_ABS_MT_POSITION_X | Accumulator::FIELD_ABS_MT_POSITION_Y;  
  4.   
  5.     uint32_t inCount = mAccumulator.pointerCount;  
  6.     uint32_t outCount = 0;  
  7.     bool havePointerIds = true;  
  8.   
  9.     mCurrentTouch.clear();  
  10.   
  11.     for (uint32_t inIndex = 0; inIndex < inCount; inIndex++) {  
  12.         const Accumulator::Pointer& inPointer = mAccumulator.pointers[inIndex];  
  13.         uint32_t fields = inPointer.fields;  
  14.   
  15.         if ((fields & REQUIRED_FIELDS) != REQUIRED_FIELDS) {  
  16.             // Some drivers send empty MT sync packets without X / Y to indicate a pointer up.  
  17.             // Drop this finger.  
  18.             continue;  
  19.         }  
  20.   
  21.         PointerData& outPointer = mCurrentTouch.pointers[outCount];  
  22.         outPointer.x = inPointer.absMTPositionX;  
  23.         outPointer.y = inPointer.absMTPositionY;  
  24.   
  25.         if (fields & Accumulator::FIELD_ABS_MT_PRESSURE) {  
  26.             if (inPointer.absMTPressure <= 0) {  
  27.                 // Some devices send sync packets with X / Y but with a 0 pressure to indicate  
  28.                 // a pointer going up.  Drop this finger.  
  29.                 continue;  
  30.             }  
  31.             outPointer.pressure = inPointer.absMTPressure;  
  32.         } else {  
  33.             // Default pressure to 0 if absent.  
  34.             outPointer.pressure = 0;  
  35.         }  
  36.              .... // 设置FIELD_ABS_MT_WIDTH_MAJOR等等field  
  37.   
  38.         // Assign pointer id using tracking id if available.  
  39.         if (havePointerIds) {  
  40.             if (fields & Accumulator::FIELD_ABS_MT_TRACKING_ID) {  
  41.                 uint32_t id = uint32_t(inPointer.absMTTrackingId);  
  42.   
  43.                 if (id > MAX_POINTER_ID) {  
  44.                     // 利用id来跟踪多个手指的触摸事件  
  45.                     havePointerIds = false;  
  46.                 }  
  47.                 else {  
  48.                     outPointer.id = id;  
  49.                     mCurrentTouch.idToIndex[id] = outCount;  
  50.                     mCurrentTouch.idBits.markBit(id);  
  51.                 }  
  52.             } else {  
  53.                 havePointerIds = false;  
  54.             }  
  55.         }  
  56.   
  57.         outCount += 1;  
  58.     }  
  59.   
  60.     mCurrentTouch.pointerCount = outCount;  
  61.   
  62.     syncTouch(when, havePointerIds);  
  63.   
  64.     mAccumulator.clear();  
  65. }  
贴一段kernel的触摸屏driver上报事件的代码:

[cpp]  view plain copy
  1.              for (i = 0; i < 10; i++){  
  2.     if (stored_size[i]){  
  3.         active_touches++;  
  4.         input_report_abs(mxt->input,   
  5.                 ABS_MT_TRACKING_ID,  
  6.                 i);  
  7.         input_report_abs(mxt->input,  
  8.                 ABS_MT_TOUCH_MAJOR,  
  9.                 stored_size[i]);  
  10.         input_report_abs(mxt->input,  
  11.                 ABS_MT_POSITION_X,  
  12.                 stored_x[i]);  
  13.         input_report_abs(mxt->input,  
  14.                 ABS_MT_POSITION_Y,  
  15.                 stored_y[i]);  
  16.         input_mt_sync(mxt->input);  
  17.     }  
  18. }  
  19. if (active_touches == 0)  
  20.     input_mt_sync(mxt->input);  
  21. input_sync(mxt->input);  
可以看到,这个触摸屏也是最多支持10点触摸的,其中的ABS_MT_TRACKING_ID就是追踪每个手指的移动轨迹标示,具体哪个点属于哪个手指的轨迹则是由电容屏的IC确定的,怪不得电容屏成本比较高。经过sync函数的处理后,mCurrentTouch里面就带有整个多点触摸事件的所有数据,可以调用基类TouchInputMapper的syncTouch了:

[cpp]  view plain copy
  1. void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) {  
  2.     uint32_t policyFlags = 0;  
  3.   
  4.     // Preprocess pointer data.  
  5.   
  6.     if (mParameters.useBadTouchFilter) {  
  7.         if (applyBadTouchFilter()) {  
  8.             havePointerIds = false;  
  9.         }  
  10.     }  
  11.   
  12.     if (mParameters.useJumpyTouchFilter) {  
  13.         if (applyJumpyTouchFilter()) {  
  14.             havePointerIds = false;  
  15.         }  
  16.     }  
  17.   
  18.     if (! havePointerIds) {  
  19.         calculatePointerIds();  
  20.     }  
  21.   
  22.     TouchData temp;  
  23.     TouchData* savedTouch;  
  24.     if (mParameters.useAveragingTouchFilter) {  
  25.         temp.copyFrom(mCurrentTouch);  
  26.         savedTouch = & temp;  
  27.   
  28.         applyAveragingTouchFilter();  
  29.     } else {  
  30.         savedTouch = & mCurrentTouch;  
  31.     }  
  32.   
  33.     // Process touches and virtual keys.  
  34.   
  35.     TouchResult touchResult = consumeOffScreenTouches(when, policyFlags);  
  36.     if (touchResult == DISPATCH_TOUCH) {  
  37.         detectGestures(when);  
  38.         dispatchTouches(when, policyFlags);  
  39.     }  
  40.   
  41.     // Copy current touch to last touch in preparation for the next cycle.  
  42.   
  43.     if (touchResult == DROP_STROKE) {  
  44.         mLastTouch.clear();  
  45.     } else {  
  46.         mLastTouch.copyFrom(*savedTouch);  
  47.     }  
  48. }  
在syncTouch里,多点触摸的数据(单点触摸事件也会经过这里)还得通过applyBadTouchFilter,applyJumpyTouchFilter,applyAveragingTouchFilter(视情况)的处理才能到consumeOffScreenTouches这步,这个函数中在处理完一些policy的东西之后就会调

 getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
            keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);

通知dispatcher有事件来了,dispatcher的分析在下篇开始。


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值