Android input系统原理二

ops/2024/10/22 7:46:48/

1.inputmanager启动源码分析

在SystemServer.java中构造了 inputmanagerservice的对象,在其构造函数中,最重要的是这个nativeInit函数。 下面是核心代码

java">inputManager = new InputManagerService(context);public InputManagerService(Context context) {
.........mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
.........LocalServices.addService(InputManagerInternal.class, new LocalService());
}

nativeinit函数

对应的jni函数文件名:com_android_server_input_InputManagerService.cpp

nativeInit 构造了一个NativeInputManager,核心代码中构造了一个EventHub和一个InputManager,并且将EventHub传递给了InputManager。那么InputManager就持有了EventHub类。后续可以看到这个EventHub是读取驱动节点数据的核心类。有用到epoll来监听节点

EventHub::EventHub(void) :mEpollFd = epoll_create(EPOLL_SIZE_HINT);}

在InputManager的构造函数中可以看到接收了InputReaderPolicyInterface 和  InputDispatcherPolicyInterface 虚基类的两个子类对象,因为外部传入的两个this,说明NativeInputManager是继承了这两个虚基类的,这里就不放代码了。

NativeInputManager::NativeInputManager(jobject contextObj,jobject serviceObj, const sp<Looper>& looper) :mLooper(looper), mInteractive(true) {
...........sp<EventHub> eventHub = new EventHub();mInputManager = new InputManager(eventHub, this, this);
}InputManager::InputManager(const sp<EventHubInterface>& eventHub,const sp<InputReaderPolicyInterface>& readerPolicy,const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {mDispatcher = new InputDispatcher(dispatcherPolicy);mReader = new InputReader(eventHub, readerPolicy, mDispatcher);initialize();
}

然后去创建了继承了线程的对象

void InputManager::initialize() {mReaderThread = new InputReaderThread(mReader);mDispatcherThread = new InputDispatcherThread(mDispatcher);
}

线程的启动是在nativeStart,最后走到InputManager.cpp中的start函数启动线程

status_t InputManager::start() {status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);if (result) {ALOGE("Could not start InputDispatcher thread due to error %d.", result);return result;}result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);if (result) {ALOGE("Could not start InputReader thread due to error %d.", result);mDispatcherThread->requestExit();return result;}return OK;
}

2.inputReader源码

启动后调用到InputReader.cpp的loopOnce,

void InputReader::loopOnce() {
.........size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
.........
}在InputReader.h中可以看到mEventBuffer的声明和定义,相当于给getEvents传递了一个长度为256 类型为RawEvent的数组
// The event queue.
static const int EVENT_BUFFER_SIZE = 256;
RawEvent mEventBuffer[EVENT_BUFFER_SIZE];在EventHub.h可以看到RawEvent的声明,结构体中的这些变量和getevent命令看到的数据非常类似。
/** A raw event as retrieved from the EventHub.*/
struct RawEvent {nsecs_t when;int32_t deviceId;int32_t type;int32_t code;int32_t value;
};

在getEvents 函数中,代码量过大,因此贴核心代码

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {struct input_event readBuffer[bufferSize];//创建了input_event 的数组,结构体中的数据和RawEvent实际上大差不差RawEvent* event = buffer;//event 指向数组头size_t capacity = bufferSize;bool awoken = false;for (;;) {if (mNeedToScanDevices) {//默认第一次进来需要扫描设备mNeedToScanDevices = false;scanDevicesLocked();mNeedToSendFinishedDeviceScan = true;}
.........
//看后面代码继续分析
}

scanDevicesLocked函数的详细解释 

static const char *DEVICE_PATH = "/dev/input";void EventHub::scanDevicesLocked() {status_t res = scanDirLocked(DEVICE_PATH);if(res < 0) {ALOGE("scan dir failed for %s\n", DEVICE_PATH);}if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) {createVirtualKeyboardLocked();}
}//打开文件夹/dev/input,读取文件夹下面所有节点,然后在分别打开对应的文件openDeviceLocked
//有了这些信息之后,可以通过这些信息去创建Device对象, 对对应设备加载配置文件或者配置属性
status_t EventHub::scanDirLocked(const char *dirname)
{char devname[PATH_MAX];char *filename;DIR *dir;struct dirent *de;dir = opendir(dirname);if(dir == NULL)return -1;strcpy(devname, dirname);filename = devname + strlen(devname);*filename++ = '/';while((de = readdir(dir))) {if(de->d_name[0] == '.' &&(de->d_name[1] == '\0' ||(de->d_name[1] == '.' && de->d_name[2] == '\0')))continue;strcpy(filename, de->d_name);openDeviceLocked(devname);}closedir(dir);return 0;
}//这个函数很长,核心就是通过ioctl获取一些device 的信息,
status_t EventHub::openDeviceLocked(const char *devicePath) {// Get device driver version.int driverVersion;if(ioctl(fd, EVIOCGVERSION, &driverVersion)) {ALOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno));close(fd);return -1;}// Get device identifier.struct input_id inputId;if(ioctl(fd, EVIOCGID, &inputId)) {ALOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno));close(fd);return -1;}// Allocate device.  (The device object takes ownership of the fd at this point.)int32_t deviceId = mNextDeviceId++;Device* device = new Device(fd, deviceId, String8(devicePath), identifier);// Load the configuration file for the device.loadConfigurationLocked(device);//加载配置文件// See if this is a touch pad.//对触摸屏配置属性  判断是不是多指触摸// Is this a new modern multi-touch driver?if (test_bit(ABS_MT_POSITION_X, device->absBitmask)&& test_bit(ABS_MT_POSITION_Y, device->absBitmask)) {// Some joysticks such as the PS3 controller report axes that conflict// with the ABS_MT range.  Try to confirm that the device really is// a touch screen.if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) {device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;}// Is this an old style single-touch driver?} else if (test_bit(BTN_TOUCH, device->keyBitmask)&& test_bit(ABS_X, device->absBitmask)&& test_bit(ABS_Y, device->absBitmask)) {device->classes |= INPUT_DEVICE_CLASS_TOUCH;// Is this a BT stylus?} else if ((test_bit(ABS_PRESSURE, device->absBitmask) ||test_bit(BTN_TOUCH, device->keyBitmask))&& !test_bit(ABS_X, device->absBitmask)&& !test_bit(ABS_Y, device->absBitmask)) {device->classes |= INPUT_DEVICE_CLASS_EXTERNAL_STYLUS;// Keyboard will try to claim some of the buttons but we really want to reserve those so we// can fuse it with the touch screen data, so just take them back. Note this means an// external stylus cannot also be a keyboard device.device->classes &= ~INPUT_DEVICE_CLASS_KEYBOARD;}// Load the key map.//加载按键的配置文件// We need to do this for joysticks too because the key layout may specify axes.status_t keyMapStatus = NAME_NOT_FOUND;if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) {// Load the keymap for the device.keyMapStatus = loadKeyMapLocked(device);}if (registerDeviceForEpollLocked(device) != OK) {delete device;return -1;}configureFd(device);addDeviceLocked(device);添加device  将所有扫描到的device通过头插的方式用链表链接起来}注册监听fd
status_t EventHub::registerDeviceForEpollLocked(Device* device) {struct epoll_event eventItem;memset(&eventItem, 0, sizeof(eventItem));eventItem.events = EPOLLIN;if (mUsingEpollWakeup) {eventItem.events |= EPOLLWAKEUP;}eventItem.data.u32 = device->id;if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, device->fd, &eventItem)) {ALOGE("Could not add device fd to epoll instance.  errno=%d", errno);return -errno;}return OK;
}//这一段检查输入设备是否为键盘(INPUT_DEVICE_CLASS_KEYBOARD),然后通过 ioctl 调用 EVIOCSREP //来禁用内核的键盘按键重复功能,因为用户态代码会自己处理按键重复逻辑void EventHub::configureFd(Device* device) {// Set fd parameters with ioctl, such as key repeat, suspend block, and clock typeif (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) {// Disable kernel key repeat since we handle it ourselvesunsigned int repeatRate[] = {0, 0};if (ioctl(device->fd, EVIOCSREP, repeatRate)) {ALOGW("Unable to disable kernel key repeat for %s: %s",device->path.string(), strerror(errno));}}String8 wakeMechanism("EPOLLWAKEUP");
//这里是为设备配置挂起阻止机制。当 mUsingEpollWakeup 未被启用时,它会尝试通过 ioctl 调用 //EVIOCSSUSPENDBLOCK 来阻止设备进入挂起状态。这个机制用于保证当设备处于挂起状态时,仍然能够唤醒//系统处理输入事件if (!mUsingEpollWakeup) {
#ifndef EVIOCSSUSPENDBLOCK// uapi headers don't include EVIOCSSUSPENDBLOCK, and future kernels// will use an epoll flag instead, so as long as we want to support// this feature, we need to be prepared to define the ioctl ourselves.
#define EVIOCSSUSPENDBLOCK _IOW('E', 0x91, int)
#endifif (ioctl(device->fd, EVIOCSSUSPENDBLOCK, 1)) {wakeMechanism = "<none>";} else {wakeMechanism = "EVIOCSSUSPENDBLOCK";}}
//设置输入设备使用单调时钟(CLOCK_MONOTONIC)来记录事件的时间戳。单调时钟保证时间总是向前移动,//避免系统时钟调整(如夏令时变化)对输入事件的时间戳产生影响// Tell the kernel that we want to use the monotonic clock for reporting timestamps// associated with input events.  This is important because the input system// uses the timestamps extensively and assumes they were recorded using the monotonic// clock.int clockId = CLOCK_MONOTONIC;bool usingClockIoctl = !ioctl(device->fd, EVIOCSCLOCKID, &clockId);ALOGI("wakeMechanism=%s, usingClockIoctl=%s", wakeMechanism.string(),toString(usingClockIoctl));
}void EventHub::addDeviceLocked(Device* device) {mDevices.add(device->id, device);device->next = mOpeningDevices;mOpeningDevices = device;
}

scanDevicesLocked 总结就是扫描监听文件,通过ioctl去驱动中获取不同设备的信息,不同输入设陪配置流程不同,加载配置文件,创建Device,最后将Device存起来。

//这段代码就是将刚才形成链表的device分别遍历将id取出来,赋值给event存起来。
while (mOpeningDevices != NULL) {Device* device = mOpeningDevices;ALOGV("Reporting device opened: id=%d, name=%s\n",device->id, device->path.string());mOpeningDevices = device->next;event->when = now;event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;event->type = DEVICE_ADDED;event += 1;mNeedToSendFinishedDeviceScan = true;if (--capacity == 0) {break;}
}
//这里为true,如果有5个device的话,这里在添加一个,那么就总共有6个了。
if (mNeedToSendFinishedDeviceScan) {mNeedToSendFinishedDeviceScan = false;event->when = now;event->type = FINISHED_DEVICE_SCAN;event += 1;if (--capacity == 0) {break;}
}

接下来就会执行这里,因为第一次扫描设备,其它代码都不会执行

// Return now if we have collected any events or if we were explicitly awoken.
if (event != buffer || awoken) {break;
}//break之后,返回扫描到的设备数
// All done, return the number of events we read.
return event - buffer;

在InputReader.cpp中,在getEvents函数之后会返回设备数,如果扫描到了5个设备,那么这里会返回6,具体可以看上面getEvents的函数源码解析

void InputReader::loopOnce() {int32_t oldGeneration;int32_t timeoutMillis;bool inputDevicesChanged = false;
..........size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);{ // acquire lockAutoMutex _l(mLock);mReaderIsAliveCondition.broadcast();if (count) {processEventsLocked(mEventBuffer, count);}if (mNextTimeout != LLONG_MAX) {nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);if (now >= mNextTimeout) {
#if DEBUG_RAW_EVENTSALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endifmNextTimeout = LLONG_MAX;timeoutExpiredLocked(now);}}if (oldGeneration != mGeneration) {inputDevicesChanged = true;getInputDevicesLocked(inputDevices);}} // release lock// Send out a message that the describes the changed input devices.if (inputDevicesChanged) {mPolicy->notifyInputDevicesChanged(inputDevices);}// Flush queued events out to the listener.// This must happen outside of the lock because the listener could potentially call// back into the InputReader's methods, such as getScanCodeState, or become blocked// on another thread similarly waiting to acquire the InputReader lock thereby// resulting in a deadlock.  This situation is actually quite plausible because the// listener is actually the input dispatcher, which calls into the window manager,// which occasionally calls into the input reader.mQueuedListener->flush();
}

就下来会进入到processEventsLocked对device进行处理,很明显,根据device type,这里将会进入addDeviceLocked

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {for (const RawEvent* rawEvent = rawEvents; count;) {int32_t type = rawEvent->type;size_t batchSize = 1;if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {int32_t deviceId = rawEvent->deviceId;while (batchSize < count) {if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT|| rawEvent[batchSize].deviceId != deviceId) {break;}batchSize += 1;}
#if DEBUG_RAW_EVENTSALOGD("BatchSize: %zu Count: %zu", batchSize, count);
#endifprocessEventsForDeviceLocked(deviceId, rawEvent, batchSize);} else {switch (rawEvent->type) {case EventHubInterface::DEVICE_ADDED:addDeviceLocked(rawEvent->when, rawEvent->deviceId);break;case EventHubInterface::DEVICE_REMOVED:removeDeviceLocked(rawEvent->when, rawEvent->deviceId);break;case EventHubInterface::FINISHED_DEVICE_SCAN:handleConfigurationChangedLocked(rawEvent->when);break;default:ALOG_ASSERT(false); // can't happenbreak;}}count -= batchSize;rawEvent += batchSize;}
}void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
//这里验证deviceId是否在mDevices中存在,如果存在,就不需要再添加一遍了ssize_t deviceIndex = mDevices.indexOfKey(deviceId);if (deviceIndex >= 0) {ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId);return;}//根据deviceId去获取device的相关信息InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);uint32_t classes = mEventHub->getDeviceClasses(deviceId);int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId);//创建InputDeviceInputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);device->configure(when, &mConfig, 0);device->reset(when);if (device->isIgnored()) {ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId,identifier.name.string());} else {ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId,identifier.name.string(), device->getSources());}//将InputDevice放入到mDevices存起来mDevices.add(deviceId, device);bumpGenerationLocked();if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {notifyExternalStylusPresenceChanged();}
}//这里是给每个InputDevice都添加了一个Mapper,由Mapper将原始数据转换为真正的触摸数据
InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,const InputDeviceIdentifier& identifier, uint32_t classes) {InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),controllerNumber, identifier, classes);// External devices.if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {device->setExternal(true);}// Devices with mics.if (classes & INPUT_DEVICE_CLASS_MIC) {device->setMic(true);}// Switch-like devices.if (classes & INPUT_DEVICE_CLASS_SWITCH) {device->addMapper(new SwitchInputMapper(device));}// Scroll wheel-like devices.if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) {device->addMapper(new RotaryEncoderInputMapper(device));}// Vibrator-like devices.if (classes & INPUT_DEVICE_CLASS_VIBRATOR) {device->addMapper(new VibratorInputMapper(device));}// Keyboard-like devices.uint32_t keyboardSource = 0;int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {keyboardSource |= AINPUT_SOURCE_KEYBOARD;}if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;}if (classes & INPUT_DEVICE_CLASS_DPAD) {keyboardSource |= AINPUT_SOURCE_DPAD;}if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {keyboardSource |= AINPUT_SOURCE_GAMEPAD;}if (keyboardSource != 0) {device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));}// Cursor-like devices.if (classes & INPUT_DEVICE_CLASS_CURSOR) {device->addMapper(new CursorInputMapper(device));}// Touchscreens and touchpad devices.if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {device->addMapper(new MultiTouchInputMapper(device));} else if (classes & INPUT_DEVICE_CLASS_TOUCH) {device->addMapper(new SingleTouchInputMapper(device));}// Joystick-like devices.if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {device->addMapper(new JoystickInputMapper(device));}// External stylus-like devices.if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {device->addMapper(new ExternalStylusInputMapper(device));}return device;
}

在processEventsLocked中,会循环处理每个device。

然后循环第二次进入getevent,前面的流程都不会执行,在这里会等待事件的发生,如果有事件发生,那么mPendingEventItems中将会存储eventItem

mPendingEventIndex = 0;release_wake_lock(WAKE_LOCK_ID);int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);

 如果有事件发生,那么mPendingEventIndex将会为0,mPendingEventCount至少也是1.就会进入这个while循环中。

while (mPendingEventIndex < mPendingEventCount) {const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];//判断是否有新的节点添加或删除if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {if (eventItem.events & EPOLLIN) {mPendingINotify = true;} else {ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);}continue;}........//获取对应device,通过device来读取event,最多读取256个inputeventssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);if (deviceIndex < 0) {ALOGW("Received unexpected epoll event 0x%08x for unknown device id %d.",eventItem.events, eventItem.data.u32);continue;}Device* device = mDevices.valueAt(deviceIndex);if (eventItem.events & EPOLLIN) {int32_t readSize = read(device->fd, readBuffer,sizeof(struct input_event) * capacity);if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
..........} else if (readSize < 0) {
..........} else if ((readSize % sizeof(struct input_event)) != 0) {
..........} else {int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;//计算读取到了多少个input_eventsize_t count = size_t(readSize) / sizeof(struct input_event);for (size_t i = 0; i < count; i++) {struct input_event& iev = readBuffer[i];ALOGV("%s got: time=%d.%06d, type=%d, code=%d, value=%d",device->path.string(),(int) iev.time.tv_sec, (int) iev.time.tv_usec,iev.type, iev.code, iev.value);// Some input devices may have a better concept of the time// when an input event was actually generated than the kernel// which simply timestamps all events on entry to evdev.// This is a custom Android extension of the input protocol// mainly intended for use with uinput based device drivers.if (iev.type == EV_MSC) {if (iev.code == MSC_ANDROID_TIME_SEC) {device->timestampOverrideSec = iev.value;continue;} else if (iev.code == MSC_ANDROID_TIME_USEC) {device->timestampOverrideUsec = iev.value;continue;}}if (device->timestampOverrideSec || device->timestampOverrideUsec) {iev.time.tv_sec = device->timestampOverrideSec;iev.time.tv_usec = device->timestampOverrideUsec;if (iev.type == EV_SYN && iev.code == SYN_REPORT) {device->timestampOverrideSec = 0;device->timestampOverrideUsec = 0;}ALOGV("applied override time %d.%06d",int(iev.time.tv_sec), int(iev.time.tv_usec));}// Use the time specified in the event instead of the current time// so that downstream code can get more accurate estimates of// event dispatch latency from the time the event is enqueued onto// the evdev client buffer.//// The event's timestamp fortuitously uses the same monotonic clock// time base as the rest of Android.  The kernel event device driver// (drivers/input/evdev.c) obtains timestamps using ktime_get_ts().// The systemTime(SYSTEM_TIME_MONOTONIC) function we use everywhere// calls clock_gettime(CLOCK_MONOTONIC) which is implemented as a// system call that also queries ktime_get_ts().event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL+ nsecs_t(iev.time.tv_usec) * 1000LL;ALOGV("event time %" PRId64 ", now %" PRId64, event->when, now);// Bug 7291243: Add a guard in case the kernel generates timestamps// that appear to be far into the future because they were generated// using the wrong clock source.//// This can happen because when the input device is initially opened// it has a default clock source of CLOCK_REALTIME.  Any input events// enqueued right after the device is opened will have timestamps// generated using CLOCK_REALTIME.  We later set the clock source// to CLOCK_MONOTONIC but it is already too late.//// Invalid input event timestamps can result in ANRs, crashes and// and other issues that are hard to track down.  We must not let them// propagate through the system.//// Log a warning so that we notice the problem and recover gracefully.if (event->when >= now + 10 * 1000000000LL) {// Double-check.  Time may have moved on.nsecs_t time = systemTime(SYSTEM_TIME_MONOTONIC);if (event->when > time) {ALOGW("An input event from %s has a timestamp that appears to ""have been generated using the wrong clock source ""(expected CLOCK_MONOTONIC): ""event time %" PRId64 ", current time %" PRId64", call time %" PRId64 ".  ""Using current time instead.",device->path.string(), event->when, time, now);event->when = time;} else {ALOGV("Event time is ok but failed the fast path and required ""an extra call to systemTime: ""event time %" PRId64 ", current time %" PRId64", call time %" PRId64 ".",event->when, time, now);}}//在将inputevent转化为RawEventevent->deviceId = deviceId;event->type = iev.type;event->code = iev.code;event->value = iev.value;event += 1;capacity -= 1;}if (capacity == 0) {// The result buffer is full.  Reset the pending event index// so we will try to read the device again on the next iteration.mPendingEventIndex -= 1;break;}}}到这里又因为event != buffer退出循环了,后续去处理RawEvent
// Return now if we have collected any events or if we were explicitly awoken.
if (event != buffer || awoken) {break;
}

 调用processEventsLocked对数据进行处理,这里本质上是找出同一个设备产生的一些了device进行处理

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {for (const RawEvent* rawEvent = rawEvents; count;) {int32_t type = rawEvent->type;size_t batchSize = 1;//使用这个逻辑对具体时间进行处理//1.如果某个设备产生了10个数据,预期是把这10个数据同时处理掉,但是如果这10个数据之间//有其它设备产生的数据,那么就会退出下面这个while循环。先处理同一个设备产生的数据。if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {int32_t deviceId = rawEvent->deviceId;while (batchSize < count) {if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT|| rawEvent[batchSize].deviceId != deviceId) {break;}batchSize += 1;}
#if DEBUG_RAW_EVENTSALOGD("BatchSize: %zu Count: %zu", batchSize, count);
#endif//在这里处理由同一个device产生的一连串的数据processEventsForDeviceLocked(deviceId, rawEvent, batchSize);} else {
....
....}count -= batchSize;rawEvent += batchSize;}
}

 processEventsForDeviceLocked中找出id对应的InputDevice调用process进行处理

void InputReader::processEventsForDeviceLocked(int32_t deviceId,const RawEvent* rawEvents, size_t count) {ssize_t deviceIndex = mDevices.indexOfKey(deviceId);if (deviceIndex < 0) {ALOGW("Discarding event for unknown deviceId %d.", deviceId);return;}InputDevice* device = mDevices.valueAt(deviceIndex);if (device->isIgnored()) {//ALOGD("Discarding event for ignored deviceId %d.", deviceId);return;}device->process(rawEvents, count);
}

 在InputDevice::process函数中,默认mDropUntilNextSync为false,所以调用mapper->process进行处理

void InputDevice::process(const RawEvent* rawEvents, size_t count) {// Process all of the events in order for each mapper.// We cannot simply ask each mapper to process them in bulk because mappers may// have side-effects that must be interleaved.  For example, joystick movement events and// gamepad button presses are handled by different mappers but they should be dispatched// in the order received.size_t numMappers = mMappers.size();for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
#if DEBUG_RAW_EVENTSALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64,rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value,rawEvent->when);
#endifif (mDropUntilNextSync) {if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {mDropUntilNextSync = false;
#if DEBUG_RAW_EVENTSALOGD("Recovered from input event buffer overrun.");
#endif} else {
#if DEBUG_RAW_EVENTSALOGD("Dropped input event while waiting for next input sync.");
#endif}} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {//是一种异常情况,不具体分析ALOGI("Detected input event buffer overrun for device %s.", getName().string());mDropUntilNextSync = true;reset(rawEvent->when);} else {for (size_t i = 0; i < numMappers; i++) {InputMapper* mapper = mMappers[i];mapper->process(rawEvent);}}--count;}
}

如果设备是触摸屏,那么会调用MultiTouchInputMapper的process进行处理,对照数据进行分析

void MultiTouchInputMapper::process(const RawEvent* rawEvent) {TouchInputMapper::process(rawEvent);mMultiTouchMotionAccumulator.process(rawEvent);
}void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {if (rawEvent->type == EV_ABS) {//最开始数据是ABS类型bool newSlot = false;//是不是用的slot协议,一般都是这种协议if (mUsingSlotsProtocol) {//code最开始是ABS_MT_SLOTif (rawEvent->code == ABS_MT_SLOT) {//将触点id保存mCurrentSlot = rawEvent->value;//表示有新的slotnewSlot = true;}} else if (mCurrentSlot < 0) {mCurrentSlot = 0;}//mCurrentSlot 到这里不会小于0,触点大于等于16时将会报错不支持。  第一次slot判断到此结束if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) {
#if DEBUG_POINTERSif (newSlot) {ALOGW("MultiTouch device emitted invalid slot index %d but it ""should be between 0 and %zd; ignoring this slot.",mCurrentSlot, mSlotCount - 1);}
#endif} else {//当mCurrentSlot为0时Slot* slot = &mSlots[mCurrentSlot];switch (rawEvent->code) {case ABS_MT_POSITION_X:slot->mInUse = true;slot->mAbsMTPositionX = rawEvent->value;break;case ABS_MT_POSITION_Y:slot->mInUse = true;slot->mAbsMTPositionY = rawEvent->value;break;case ABS_MT_TOUCH_MAJOR:slot->mInUse = true;slot->mAbsMTTouchMajor = rawEvent->value;break;case ABS_MT_TOUCH_MINOR:slot->mInUse = true;slot->mAbsMTTouchMinor = rawEvent->value;slot->mHaveAbsMTTouchMinor = true;break;case ABS_MT_WIDTH_MAJOR:slot->mInUse = true;slot->mAbsMTWidthMajor = rawEvent->value;break;case ABS_MT_WIDTH_MINOR:slot->mInUse = true;slot->mAbsMTWidthMinor = rawEvent->value;slot->mHaveAbsMTWidthMinor = true;break;case ABS_MT_ORIENTATION:slot->mInUse = true;slot->mAbsMTOrientation = rawEvent->value;break;//abs 数据第二次处理,value不为0,表示触点没松开,触点松开时value为1case ABS_MT_TRACKING_ID:if (mUsingSlotsProtocol && rawEvent->value < 0) {// The slot is no longer in use but it retains its previous contents,// which may be reused for subsequent touches.slot->mInUse = false;} else {slot->mInUse = true;slot->mAbsMTTrackingId = rawEvent->value;}break;case ABS_MT_PRESSURE:slot->mInUse = true;slot->mAbsMTPressure = rawEvent->value;break;case ABS_MT_DISTANCE:slot->mInUse = true;slot->mAbsMTDistance = rawEvent->value;break;case ABS_MT_TOOL_TYPE:slot->mInUse = true;slot->mAbsMTToolType = rawEvent->value;slot->mHaveAbsMTToolType = true;break;}}} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) {// MultiTouch Sync: The driver has returned all data for *one* of the pointers.mCurrentSlot += 1;} else if (rawEvent->type == EV_MSC && rawEvent->code == MSC_TIMESTAMP) {mDeviceTimestamp = rawEvent->value;}
}void TouchInputMapper::process(const RawEvent* rawEvent) {mCursorButtonAccumulator.process(rawEvent);mCursorScrollAccumulator.process(rawEvent);mTouchButtonAccumulator.process(rawEvent);//同步尾if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {sync(rawEvent->when);}
}void TouchInputMapper::sync(nsecs_t when) {const RawState* last = mRawStatesPending.isEmpty() ?&mCurrentRawState : &mRawStatesPending.top();// Push a new state.mRawStatesPending.push();RawState* next = &mRawStatesPending.editTop();next->clear();next->when = when;// Sync button state.next->buttonState = mTouchButtonAccumulator.getButtonState()| mCursorButtonAccumulator.getButtonState();// Sync scrollnext->rawVScroll = mCursorScrollAccumulator.getRelativeVWheel();next->rawHScroll = mCursorScrollAccumulator.getRelativeHWheel();mCursorScrollAccumulator.finishSync();// Sync touchsyncTouch(when, next);// Assign pointer ids.if (!mHavePointerIds) {assignPointerIds(last, next);}#if DEBUG_RAW_EVENTSALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, ""hovering ids 0x%08x -> 0x%08x",last->rawPointerData.pointerCount,next->rawPointerData.pointerCount,last->rawPointerData.touchingIdBits.value,next->rawPointerData.touchingIdBits.value,last->rawPointerData.hoveringIdBits.value,next->rawPointerData.hoveringIdBits.value);
#endifprocessRawTouches(false /*timeout*/);
}void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {//获取slotcount  值为16size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();size_t outCount = 0;BitSet32 newPointerIdBits;mHavePointerIds = true;//这里遍历每个slot  判断触点是不是还在,如果触点不在,直接略过for (size_t inIndex = 0; inIndex < inCount; inIndex++) {const MultiTouchMotionAccumulator::Slot* inSlot =mMultiTouchMotionAccumulator.getSlot(inIndex);if (!inSlot->isInUse()) {continue;}if (outCount >= MAX_POINTERS) {
#if DEBUG_POINTERSALOGD("MultiTouch device %s emitted more than maximum of %d pointers; ""ignoring the rest.",getDeviceName().string(), MAX_POINTERS);
#endifbreak; // too many fingers!}//构建一个触点对象,数据来自slotRawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount];outPointer.x = inSlot->getX();outPointer.y = inSlot->getY();outPointer.pressure = inSlot->getPressure();outPointer.touchMajor = inSlot->getTouchMajor();outPointer.touchMinor = inSlot->getTouchMinor();outPointer.toolMajor = inSlot->getToolMajor();outPointer.toolMinor = inSlot->getToolMinor();outPointer.orientation = inSlot->getOrientation();outPointer.distance = inSlot->getDistance();outPointer.tiltX = 0;outPointer.tiltY = 0;outPointer.toolType = inSlot->getToolType();if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {outPointer.toolType = mTouchButtonAccumulator.getToolType();if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;}}bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE&& (mTouchButtonAccumulator.isHovering()|| (mRawPointerAxes.pressure.valid && inSlot->getPressure() <= 0));outPointer.isHovering = isHovering;// Assign pointer id using tracking id if available.if (mHavePointerIds) {int32_t trackingId = inSlot->getTrackingId();int32_t id = -1;if (trackingId >= 0) {for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) {//查找并清除第一个被标记的位(即值为 1 的位),然后返回该位的索引uint32_t n = idBits.clearFirstMarkedBit();if (mPointerTrackingIdMap[n] == trackingId) {id = n;}}//第一次在这里id小于0,并且mPointerIdBits没有满if (id < 0 && !mPointerIdBits.isFull()) {id = mPointerIdBits.markFirstUnmarkedBit();//第一次这里返回0,标记第一个没有被标记过的下标,并返回索引//保存trackingIdmPointerTrackingIdMap[id] = trackingId;}}if (id < 0) {mHavePointerIds = false;outState->rawPointerData.clearIdBits();newPointerIdBits.clear();} else {//记录idoutPointer.id = id;//第一个触点outState->rawPointerData.idToIndex[id] = outCount;outState->rawPointerData.markIdBit(id, isHovering);newPointerIdBits.markBit(id);}}outCount += 1;}outState->deviceTimestamp = mMultiTouchMotionAccumulator.getDeviceTimestamp();outState->rawPointerData.pointerCount = outCount;mPointerIdBits = newPointerIdBits;mMultiTouchMotionAccumulator.finishSync();
}void TouchInputMapper::processRawTouches(bool timeout) {//这里判断是不是某个状态抛弃所有触摸数据if (mDeviceMode == DEVICE_MODE_DISABLED) {// Drop all input if the device is disabled.mCurrentRawState.clear();mRawStatesPending.clear();return;}// Drain any pending touch states. The invariant here is that the mCurrentRawState is always// valid and must go through the full cook and dispatch cycle. This ensures that anything// touching the current state will only observe the events that have been dispatched to the// rest of the pipeline.const size_t N = mRawStatesPending.size();size_t count;for(count = 0; count < N; count++) {//取出RawState对象的数据,数据在syncTouch时填入const RawState& next = mRawStatesPending[count];// A failure to assign the stylus id means that we're waiting on stylus data// and so should defer the rest of the pipeline.if (assignExternalStylusId(next, timeout)) {break;}// All ready to go.clearStylusDataPendingFlags();//拷贝一份数据mCurrentRawState.copyFrom(next);if (mCurrentRawState.when < mLastRawState.when) {mCurrentRawState.when = mLastRawState.when;}//关键方法cookAndDispatch(mCurrentRawState.when);}if (count != 0) {mRawStatesPending.removeItemsAt(0, count);}if (mExternalStylusDataPending) {if (timeout) {nsecs_t when = mExternalStylusFusionTimeout - STYLUS_DATA_LATENCY;clearStylusDataPendingFlags();mCurrentRawState.copyFrom(mLastRawState);
#if DEBUG_STYLUS_FUSIONALOGD("Timeout expired, synthesizing event with new stylus data");
#endifcookAndDispatch(when);} else if (mExternalStylusFusionTimeout == LLONG_MAX) {mExternalStylusFusionTimeout = mExternalStylusState.when + TOUCH_DATA_TIMEOUT;getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);}}
}

分析cookAndDispatch

void TouchInputMapper::cookAndDispatch(nsecs_t when) {// Always start with a clean state.//初始化变量mCurrentCookedState.clear();// Apply stylus buttons to current raw state.applyExternalStylusButtonState(when);// Handle policy on initial down or hover events.bool initialDown = mLastRawState.rawPointerData.pointerCount == 0&& mCurrentRawState.rawPointerData.pointerCount != 0;uint32_t policyFlags = 0;bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState;if (initialDown || buttonsPressed) {// If this is a touch screen, hide the pointer on an initial down.if (mDeviceMode == DEVICE_MODE_DIRECT) {getContext()->fadePointer();}if (mParameters.wake) {policyFlags |= POLICY_FLAG_WAKE;}}// Consume raw off-screen touches before cooking pointer data.// If touches are consumed, subsequent code will not receive any pointer data.if (consumeRawTouches(when, policyFlags)) {//mCurrentRawState.rawPointerData.clear();}// Cook pointer data.  This call populates the mCurrentCookedState.cookedPointerData structure// with cooked pointer data that has the same ids and indices as the raw data.// The following code can use either the raw or cooked data, as needed.//关键方法cookPointerData();// Apply stylus pressure to current cooked state.applyExternalStylusTouchState(when);// Synthesize key down from raw buttons if needed.synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState);// Dispatch the touches either directly or by translation through a pointer on screen.if (mDeviceMode == DEVICE_MODE_POINTER) {for (BitSet32 idBits(mCurrentRawState.rawPointerData.touchingIdBits);!idBits.isEmpty(); ) {uint32_t id = idBits.clearFirstMarkedBit();const RawPointerData::Pointer& pointer =mCurrentRawState.rawPointerData.pointerForId(id);if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS|| pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {mCurrentCookedState.stylusIdBits.markBit(id);} else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER|| pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {mCurrentCookedState.fingerIdBits.markBit(id);} else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) {mCurrentCookedState.mouseIdBits.markBit(id);}}for (BitSet32 idBits(mCurrentRawState.rawPointerData.hoveringIdBits);!idBits.isEmpty(); ) {uint32_t id = idBits.clearFirstMarkedBit();const RawPointerData::Pointer& pointer =mCurrentRawState.rawPointerData.pointerForId(id);if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS|| pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {mCurrentCookedState.stylusIdBits.markBit(id);}}// Stylus takes precedence over all tools, then mouse, then finger.PointerUsage pointerUsage = mPointerUsage;if (!mCurrentCookedState.stylusIdBits.isEmpty()) {mCurrentCookedState.mouseIdBits.clear();mCurrentCookedState.fingerIdBits.clear();pointerUsage = POINTER_USAGE_STYLUS;} else if (!mCurrentCookedState.mouseIdBits.isEmpty()) {mCurrentCookedState.fingerIdBits.clear();pointerUsage = POINTER_USAGE_MOUSE;} else if (!mCurrentCookedState.fingerIdBits.isEmpty() ||isPointerDown(mCurrentRawState.buttonState)) {pointerUsage = POINTER_USAGE_GESTURES;}dispatchPointerUsage(when, policyFlags, pointerUsage);} else {if (mDeviceMode == DEVICE_MODE_DIRECT&& mConfig.showTouches && mPointerController != NULL) {mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);mPointerController->setButtonState(mCurrentRawState.buttonState);mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords,mCurrentCookedState.cookedPointerData.idToIndex,mCurrentCookedState.cookedPointerData.touchingIdBits);}if (!mCurrentMotionAborted) {dispatchButtonRelease(when, policyFlags);dispatchHoverExit(when, policyFlags);//触摸点派发dispatchTouches(when, policyFlags);dispatchHoverEnterAndMove(when, policyFlags);dispatchButtonPress(when, policyFlags);}if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {mCurrentMotionAborted = false;}}// Synthesize key up from raw buttons if needed.synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState);// Clear some transient state.mCurrentRawState.rawVScroll = 0;mCurrentRawState.rawHScroll = 0;// Copy current touch to last touch in preparation for the next cycle.mLastRawState.copyFrom(mCurrentRawState);mLastCookedState.copyFrom(mCurrentCookedState);
}void TouchInputMapper::cookPointerData() {//获取有多少个触点uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount;mCurrentCookedState.cookedPointerData.clear();mCurrentCookedState.deviceTimestamp =mCurrentRawState.deviceTimestamp;//按下点的个数mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount;mCurrentCookedState.cookedPointerData.hoveringIdBits =mCurrentRawState.rawPointerData.hoveringIdBits;//按下id的集合mCurrentCookedState.cookedPointerData.touchingIdBits =mCurrentRawState.rawPointerData.touchingIdBits;//判断按下点的个数是否为0,正常不会为0if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {mCurrentCookedState.buttonState = 0;} else {mCurrentCookedState.buttonState = mCurrentRawState.buttonState;}// Walk through the the active pointers and map device coordinates onto// surface coordinates and adjust for display orientation.//遍历触点for (uint32_t i = 0; i < currentPointerCount; i++) {//取出触点数据const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i];// Sizefloat touchMajor, touchMinor, toolMajor, toolMinor, size;//size的校准  长轴短轴的校准switch (mCalibration.sizeCalibration) {case Calibration::SIZE_CALIBRATION_GEOMETRIC:case Calibration::SIZE_CALIBRATION_DIAMETER:case Calibration::SIZE_CALIBRATION_BOX:case Calibration::SIZE_CALIBRATION_AREA:if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.toolMajor.valid) {touchMajor = in.touchMajor;touchMinor = mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor;toolMajor = in.toolMajor;toolMinor = mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor;size = mRawPointerAxes.touchMinor.valid? avg(in.touchMajor, in.touchMinor) : in.touchMajor;} else if (mRawPointerAxes.touchMajor.valid) {toolMajor = touchMajor = in.touchMajor;toolMinor = touchMinor = mRawPointerAxes.touchMinor.valid? in.touchMinor : in.touchMajor;size = mRawPointerAxes.touchMinor.valid? avg(in.touchMajor, in.touchMinor) : in.touchMajor;} else if (mRawPointerAxes.toolMajor.valid) {touchMajor = toolMajor = in.toolMajor;touchMinor = toolMinor = mRawPointerAxes.toolMinor.valid? in.toolMinor : in.toolMajor;size = mRawPointerAxes.toolMinor.valid? avg(in.toolMajor, in.toolMinor) : in.toolMajor;} else {ALOG_ASSERT(false, "No touch or tool axes.  ""Size calibration should have been resolved to NONE.");touchMajor = 0;touchMinor = 0;toolMajor = 0;toolMinor = 0;size = 0;}if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) {uint32_t touchingCount =mCurrentRawState.rawPointerData.touchingIdBits.count();if (touchingCount > 1) {touchMajor /= touchingCount;touchMinor /= touchingCount;toolMajor /= touchingCount;toolMinor /= touchingCount;size /= touchingCount;}}if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_GEOMETRIC) {touchMajor *= mGeometricScale;touchMinor *= mGeometricScale;toolMajor *= mGeometricScale;toolMinor *= mGeometricScale;} else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_AREA) {touchMajor = touchMajor > 0 ? sqrtf(touchMajor) : 0;touchMinor = touchMajor;toolMajor = toolMajor > 0 ? sqrtf(toolMajor) : 0;toolMinor = toolMajor;} else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DIAMETER) {touchMinor = touchMajor;toolMinor = toolMajor;}mCalibration.applySizeScaleAndBias(&touchMajor);mCalibration.applySizeScaleAndBias(&touchMinor);mCalibration.applySizeScaleAndBias(&toolMajor);mCalibration.applySizeScaleAndBias(&toolMinor);size *= mSizeScale;break;default:touchMajor = 0;touchMinor = 0;toolMajor = 0;toolMinor = 0;size = 0;break;}// Pressurefloat pressure;switch (mCalibration.pressureCalibration) {case Calibration::PRESSURE_CALIBRATION_PHYSICAL:case Calibration::PRESSURE_CALIBRATION_AMPLITUDE:pressure = in.pressure * mPressureScale;break;default:pressure = in.isHovering ? 0 : 1;break;}//方向校准// Tilt and Orientationfloat tilt;float orientation;if (mHaveTilt) {float tiltXAngle = (in.tiltX - mTiltXCenter) * mTiltXScale;float tiltYAngle = (in.tiltY - mTiltYCenter) * mTiltYScale;orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle));tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle));} else {tilt = 0;switch (mCalibration.orientationCalibration) {case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED:orientation = in.orientation * mOrientationScale;break;case Calibration::ORIENTATION_CALIBRATION_VECTOR: {int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4);int32_t c2 = signExtendNybble(in.orientation & 0x0f);if (c1 != 0 || c2 != 0) {orientation = atan2f(c1, c2) * 0.5f;float confidence = hypotf(c1, c2);float scale = 1.0f + confidence / 16.0f;touchMajor *= scale;touchMinor /= scale;toolMajor *= scale;toolMinor /= scale;} else {orientation = 0;}break;}default:orientation = 0;}}// Distance  距离校准float distance;switch (mCalibration.distanceCalibration) {case Calibration::DISTANCE_CALIBRATION_SCALED:distance = in.distance * mDistanceScale;break;default:distance = 0;}// Coverage   覆盖面校准int32_t rawLeft, rawTop, rawRight, rawBottom;switch (mCalibration.coverageCalibration) {case Calibration::COVERAGE_CALIBRATION_BOX:rawLeft = (in.toolMinor & 0xffff0000) >> 16;rawRight = in.toolMinor & 0x0000ffff;rawBottom = in.toolMajor & 0x0000ffff;rawTop = (in.toolMajor & 0xffff0000) >> 16;break;default:rawLeft = rawTop = rawRight = rawBottom = 0;break;}//x y 坐标校准// Adjust X,Y coords for device calibration// TODO: Adjust coverage coords?float xTransformed = in.x, yTransformed = in.y;mAffineTransform.applyTo(xTransformed, yTransformed);// Adjust X, Y, and coverage coords for surface orientation.float x, y;float left, top, right, bottom;switch (mSurfaceOrientation) {case DISPLAY_ORIENTATION_90:x = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;y = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale + mXTranslate;left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;right = float(rawBottom- mRawPointerAxes.y.minValue) * mYScale + mYTranslate;bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate;orientation -= M_PI_2;if (mOrientedRanges.haveOrientation && orientation < mOrientedRanges.orientation.min) {orientation += (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);}break;case DISPLAY_ORIENTATION_180:x = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale + mXTranslate;y = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate;left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate;right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate;orientation -= M_PI;if (mOrientedRanges.haveOrientation && orientation < mOrientedRanges.orientation.min) {orientation += (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);}break;case DISPLAY_ORIENTATION_270:x = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate;y = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate;right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;orientation += M_PI_2;if (mOrientedRanges.haveOrientation && orientation > mOrientedRanges.orientation.max) {orientation -= (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);}break;default:x = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;y = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;break;}// Write output coords.PointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i];out.clear();out.setAxisValue(AMOTION_EVENT_AXIS_X, x);out.setAxisValue(AMOTION_EVENT_AXIS_Y, y);out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size);out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor);out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor);out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation);out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt);out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance);if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) {out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_1, left);out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_2, top);out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_3, right);out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_4, bottom);} else {out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor);out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor);}// Write output properties.PointerProperties& properties =mCurrentCookedState.cookedPointerData.pointerProperties[i];uint32_t id = in.id;properties.clear();properties.id = id;properties.toolType = in.toolType;// Write id index.mCurrentCookedState.cookedPointerData.idToIndex[id] = i;}
}void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {//触点的个数BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;//上一次触点BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits;int32_t metaState = getContext()->getGlobalMetaState();int32_t buttonState = mCurrentCookedState.buttonState;//本次触点和上一次触点是相等的   没有手指的变化if (currentIdBits == lastIdBits) {if (!currentIdBits.isEmpty()) { // 当前这次不为空// No pointer id changes so this is a move event.// The listener takes care of batching moves so we don't have to deal with that here.//没有触点的变化并且不为null,还有事件的变化,所以判定为触点的移动dispatchMotion(when, policyFlags, mSource,AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,AMOTION_EVENT_EDGE_FLAG_NONE,mCurrentCookedState.deviceTimestamp,mCurrentCookedState.cookedPointerData.pointerProperties,mCurrentCookedState.cookedPointerData.pointerCoords,mCurrentCookedState.cookedPointerData.idToIndex,currentIdBits, -1,mOrientedXPrecision, mOrientedYPrecision, mDownTime);}} else {// There may be pointers going up and pointers going down and pointers moving// all at the same time.//如果有触点的变化,那么判定是否有触点的按下或抬起或者同时有触点的移动BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value);BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value);BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value);BitSet32 dispatchedIdBits(lastIdBits.value);// Update last coordinates of pointers that have moved so that we observe the new// pointer positions at the same time as other pointers that have just gone up.//比较last触点坐标的变化来判定是否有触点的移动bool moveNeeded = updateMovedPointers(mCurrentCookedState.cookedPointerData.pointerProperties,mCurrentCookedState.cookedPointerData.pointerCoords,mCurrentCookedState.cookedPointerData.idToIndex,mLastCookedState.cookedPointerData.pointerProperties,mLastCookedState.cookedPointerData.pointerCoords,mLastCookedState.cookedPointerData.idToIndex,moveIdBits);if (buttonState != mLastCookedState.buttonState) {moveNeeded = true;}//是否有up事件// Dispatch pointer up events.while (!upIdBits.isEmpty()) {uint32_t upId = upIdBits.clearFirstMarkedBit();dispatchMotion(when, policyFlags, mSource,AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, 0,mCurrentCookedState.deviceTimestamp,mLastCookedState.cookedPointerData.pointerProperties,mLastCookedState.cookedPointerData.pointerCoords,mLastCookedState.cookedPointerData.idToIndex,dispatchedIdBits, upId, mOrientedXPrecision, mOrientedYPrecision, mDownTime);dispatchedIdBits.clearBit(upId);}// Dispatch move events if any of the remaining pointers moved from their old locations.// Although applications receive new locations as part of individual pointer up// events, they do not generally handle them except when presented in a move event.//是否有move事件if (moveNeeded && !moveIdBits.isEmpty()) {ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);dispatchMotion(when, policyFlags, mSource,AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, 0,mCurrentCookedState.deviceTimestamp,mCurrentCookedState.cookedPointerData.pointerProperties,mCurrentCookedState.cookedPointerData.pointerCoords,mCurrentCookedState.cookedPointerData.idToIndex,dispatchedIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime);}// Dispatch pointer down events using the new pointer locations.//是否有按下事件while (!downIdBits.isEmpty()) {uint32_t downId = downIdBits.clearFirstMarkedBit();dispatchedIdBits.markBit(downId);if (dispatchedIdBits.count() == 1) {// First pointer is going down.  Set down time.mDownTime = when;}dispatchMotion(when, policyFlags, mSource,AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0,mCurrentCookedState.deviceTimestamp,mCurrentCookedState.cookedPointerData.pointerProperties,mCurrentCookedState.cookedPointerData.pointerCoords,mCurrentCookedState.cookedPointerData.idToIndex,dispatchedIdBits, downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime);}}
}


http://www.ppmy.cn/ops/124191.html

相关文章

如何删除不需要的右键菜单

比如要删除以下右键菜单&#xff1a; 1. 打开“命令提示符”&#xff0c;并输入“regedit”以打开注册表编辑器。或使用快捷键“WinR”打开“运行”窗口&#xff0c;输入“regedit”以打开注册表编辑器。 2. 在注册表编辑器中&#xff0c;找到路径“计算机HKEY_CLASSES_ROOT/Di…

【深度学习】自动微分——Autodiff or Autograd?

论文 [1].CSC321 Lecture 10: Automatic Differentiation [2].Automatic Differentiation in Machine Learning:a Survey 关键点总结&#xff1a; 雅可比矩阵&#xff1a;对于多变量函数 y ⃗ f ( x ⃗ ) \vec{y} f(\vec{x}) y ​f(x )&#xff0c;其梯度矩阵&#xff08;…

Llama-3.2-3B-Instruct PyTorch模型微调最佳实践

1 引言 Meta Llama 3.2多语言大型语言模型集合&#xff08;LM&#xff09;是一个1B和3B大小&#xff08;文本输入/文本输出&#xff09;的预训练和指令微调模型集合。Llama 3.2指令调整的纯文本模型针对多语言对话用例进行了优化&#xff0c;包括智能检索和总结任务。它们在常…

如何将uniapp项目首次提交到指定git仓库

在移动应用开发领域&#xff0c;uniapp凭借其跨平台的优势&#xff0c;已经成为许多开发者的首选框架。创建一个uniapp项目后&#xff0c;将代码提交到版本控制仓库是项目管理的第一步。本文将详细介绍如何将uniapp项目首次提交到指定的Git仓库。 准备工作 在开始之前&#x…

从数据到洞察:ChatGPT如何革新Python数据分析流程

导读&#xff1a;通过ChatGPT与Python的结合&#xff0c;数据分析流程得到了极大的优化和提升&#xff0c;从数据获取、清洗、代码生成到智能分析和可视化展示&#xff0c;每一步都变得更加高效和智能化。这不仅提高了分析的准确性和效率&#xff0c;还降低了技术门槛&#xff…

PigGo的安装配置

TyporaPigGo的使用 1、下载PigGo 1.1、先打开Typora的偏好设置 1.2 下载PigGo app 1.3 下载Setup-xxx.exe版本 1.4安装成功后打开PigGo 2、配置PigGo 1、安装gitee-uploader插件 2、 PicGo设置 ​ ​ 3、图床设置 3.1配置SM.MS 3.1.1 登录sm,生成秘钥 如果没有注册&…

nacos多数据源插件介绍以及使用

概述 在微服务架构中&#xff0c;服务配置的集中管理和动态调整是至关重要的。Nacos 提供了配置管理和服务发现的功能&#xff0c;其中配置管理支持动态数据源的切换&#xff0c;增强了其在复杂环境中的适用性。默认情况下&#xff0c;Nacos 支持 MySQL 和Derby&#xff0c;但…

openpnp - juki吸嘴尺寸

文章目录 openpnp - juki吸嘴尺寸概述笔记吸嘴可以对应的最小元件尺寸END openpnp - juki吸嘴尺寸 概述 在网上买的juki吸嘴的商品页面&#xff0c;并没有具体的吸嘴尺寸。 现在贴片时&#xff0c;要根据吸嘴外径大小来决定具体元件要用哪种吸嘴&#xff0c;先自己量一下。 …