前言
官方关于android input介绍http://source.android.com/devices/tech/input/overview.html ,安卓input子系统是通过事件管道通过系统的各个层的。在最低层,物理输入设备产生了描述的状态变化的信号,如按键和触摸接触点。然后进行编码,并以某种方式发送这些信号,例如通过USB HID报告或I2C总线。这些信号
被linux Kernel的驱动解码。驱动会把这些信号翻译成标准的事件类型和代码。Linux内核在linux/input.h中定义了一套标准的事件类型和代码。android的 EventHub 组件通过打开dev中的设备文件的方式从linux kernel读取这些输入事件,然后android的 InputReader 组件会把这些linux输入事件翻译成一个android输入事件流。在翻译过程中涉及到device configuration, keyboard layout files, and various mapping tables.三个配置文件。最后InputReader 会把这些翻译好的事件发送给合适的应用程序窗口。class ServerThread extends Thread {
private static final String TAG = "SystemServer";
private static final String ENCRYPTING_STATE = "trigger_restart_min_framework";
private static final String ENCRYPTED_STATE = "1";
ContentResolver mContentResolver;
void reportWtf(String msg, Throwable e) {
Slog.w(TAG, "***********************************************");
Log.wtf(TAG, "BOOT FAILURE " + msg, e);
}
@Override
public void run() {
。。。。。。
。。。。。。
Slog.i(TAG, "Window Manager");
wm = WindowManagerService.main(context, power,
factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
!firstBoot);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ActivityManagerService.self().setWindowManager(wm);
。。。。。
。。。。。。
}
public static WindowManagerService main(Context context,
PowerManagerService pm, boolean haveInputMethods, boolean allowBootMsgs) {
WMThread thr = new WMThread(context, pm, haveInputMethods, allowBootMsgs);
thr.start();
synchronized (thr) {
while (thr.mService == null) {
try {
thr.wait();
} catch (InterruptedException e) {
}
}
return thr.mService;
}
}
static class WMThread extends Thread {
WindowManagerService mService;
private final Context mContext;
private final PowerManagerService mPM;
private final boolean mHaveInputMethods;
private final boolean mAllowBootMessages;
public WMThread(Context context, PowerManagerService pm,
boolean haveInputMethods, boolean allowBootMsgs) {
。。。。。。。。
。。。。。。。。
WindowManagerService s = new WindowManagerService(mContext, mPM,
mHaveInputMethods, mAllowBootMessages);
。。。。
。。。。。。
}
private WindowManagerService(Context context, PowerManagerService pm,
boolean haveInputMethods, boolean showBootMsgs) {
。。。。。。。。。。。
。。。。。。。。。。。
mInputManager = new InputManager(context, this);
PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
thr.start();
synchronized (thr) {
while (!thr.mRunning) {
try {
thr.wait();
} catch (InterruptedException e) {
}
}
}
mInputManager.start();
}
public InputManager(Context context, WindowManagerService windowManagerService) {
this.mContext = context;
this.mWindowManagerService = windowManagerService;
this.mCallbacks = new Callbacks();
Looper looper = windowManagerService.mH.getLooper();
Slog.i(TAG, "Initializing input manager");
nativeInit(mContext, mCallbacks, looper.getQueue());
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
}
注意看这里的nativeInit(mContext, mCallbacks, looper.getQueue());这句,这个函数定义
private static native void nativeInit(Context context, Callbacks callbacks,
MessageQueue messageQueue);static JNINativeMethod gInputManagerMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit", "(Landroid/content/Context;"
"Lcom/android/server/wm/InputManager$Callbacks;Landroid/os/MessageQueue;)V",
(void*) android_server_InputManager_nativeInit },
。。。。。。。。。
}//定义一个 JNINativeMethod然后在下面函数中注册
int register_android_server_InputManager(JNIEnv* env) {
int res = jniRegisterNativeMethods(env, "com/android/server/wm/InputManager",
gInputManagerMethods, NELEM(gInputManagerMethods));
LOG_FATAL_IF(res < 0, "Unable to register native methods.");
//Android的native层与java层都是这么调用的。我们继续看看
static void android_server_InputManager_nativeInit(JNIEnv* env, jclass clazz,
jobject contextObj, jobject callbacksObj, jobject messageQueueObj) {
if (gNativeInputManager == NULL) {
sp looper = android_os_MessageQueue_getLooper(env, messageQueueObj);
gNativeInputManager = new NativeInputManager(contextObj, callbacksObj, looper);
} else {
LOGE("Input manager already initialized.");
jniThrowRuntimeException(env, "Input manager already initialized.");
}
}
NativeInputManager::NativeInputManager(jobject contextObj,
jobject callbacksObj, const sp& looper) :
mLooper(looper) {
。。。。。。。。。
sp eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
}
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
namespace android {
InputManager::InputManager(
const sp& eventHub,
const sp& readerPolicy,
const sp& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
InputReaderThread::InputReaderThread(const sp& reader) :
Thread(/*canCallJava*/ true), mReader(reader) {
}
InputDispatcherThread::InputDispatcherThread(const sp& dispatcher) :
Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
}
private WindowManagerService(Context context, PowerManagerService pm,
boolean haveInputMethods, boolean showBootMsgs) {
。。。。。。。。。。。
。。。。。。。。。。。
mInputManager = new InputManager(context, this);
PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
thr.start();
synchronized (thr) {
while (!thr.mRunning) {
try {
thr.wait();
} catch (InterruptedException e) {
}
}
}
mInputManager.start();
}
public void start() {
Slog.i(TAG, "Starting input manager");
nativeStart();
registerPointerSpeedSettingObserver();
registerShowTouchesSettingObserver();
updatePointerSpeedFromSettings();
updateShowTouchesFromSettings();
}
static JNINativeMethod gInputManagerMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit", "(Landroid/content/Context;"
"Lcom/android/server/wm/InputManager$Callbacks;Landroid/os/MessageQueue;)V",
(void*) android_server_InputManager_nativeInit },
{ "nativeStart", "()V",
(void*) android_server_InputManager_nativeStart },
。。。。。。。。。。。。。。。。。。。。。
然后本文件下
static void android_server_InputManager_nativeStart(JNIEnv* env, jclass clazz) {
if (checkInputManagerUnitialized(env)) {
return;
}
status_t result = gNativeInputManager->getInputManager()->start();
if (result) {
jniThrowRuntimeException(env, "Input manager could not be started.");
}
}
status_t InputManager::start() {
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
if (result) {
LOGE("Could not start InputDispatcher thread due to error %d.", result);
return result;
}
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
if (result) {
LOGE("Could not start InputReader thread due to error %d.", result);
mDispatcherThread->requestExit();
return result;
}
return OK;
}
终于找到了status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
然后仔细看这两个类并没有实现这个函数,因此他们会调用他们的父类public Thread里的 Run 方法我们来看这个代码\android40\frameworks\base\libs\utils\ Threads.cppstatus_t Thread::run(const char* name, int32_t priority, size_t stack)
{
Mutex::Autolock _l(mLock);
if (mRunning) {
// thread already started
return INVALID_OPERATION;
}
// reset status and exitPending to their default value, so we can
// try again after an error happened (either below, or in readyToRun())
mStatus = NO_ERROR;
mExitPending = false;
mThread = thread_id_t(-1);
// hold a strong reference on ourself
mHoldSelf = this;
mRunning = true;
bool res;
if (mCanCallJava) {
res = createThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
} else {
res = androidCreateRawThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
}
if (res == false) {
mStatus = UNKNOWN_ERROR; // something happened!
mRunning = false;
mThread = thread_id_t(-1);
mHoldSelf.clear(); // "this" may have gone away after this.
return UNKNOWN_ERROR;
}
// Do not refer to mStatus here: The thread is already running (may, in fact
// already have exited with a valid mStatus result). The NO_ERROR indication
// here merely indicates successfully starting the thread and does not
// imply successful termination/execution.
return NO_ERROR;
// Exiting scope of mLock is a memory barrier and allows new thread to run
}
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}
void InputReader::loopOnce() {
。。。。。。。。。。。
。。。。。。
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
。。。。。。。。。
。。。。。。。。。。。
}
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize){
LOG_ASSERT(bufferSize >= 1); //buffsize必须>=1
AutoMutex _l(mLock);
struct input_event readBuffer[bufferSize]; //定义数据缓存 注解1
RawEvent* event = buffer; //保存缓存基地址
size_t capacity = bufferSize;
bool awoken = false;
for (;;) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); //获取系统当前时间
//如果需要就重新打开设备
// Reopen input devices if needed.
if (mNeedToReopenDevices) {
mNeedToReopenDevices = false;
LOGI("Reopening all input devices due to a configuration change.");
closeAllDevicesLocked(); //关闭所有设备
mNeedToScanDevices = true; //下次运行需要重新扫描所有设备
break; // return to the caller before we actually rescan
}
//报告最近的被添加删除的设备
// Report any devices that had last been added/removed.
while (mClosingDevices) { //如果队列有数据
Device* device = mClosingDevices;
LOGV("Reporting device closed: id=%d, name=%s\n",
device->id, device->path.string());
mClosingDevices = device->next;
event->when = now;
event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
event->type = DEVICE_REMOVED; //报告类型DEVICE_REMOVED
event += 1;
delete device;
mNeedToSendFinishedDeviceScan = true;
if (--capacity == 0) {
break; //凑够bufferSize个就退出
}
}
if (mNeedToScanDevices) {
mNeedToScanDevices = false;
scanDevicesLocked(); //打开所有设备 注解2
mNeedToSendFinishedDeviceScan = true;
}
while (mOpeningDevices != NULL) { //报告被添加的最新设备
Device* device = mOpeningDevices;
LOGV("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;
}
}
if (mNeedToSendFinishedDeviceScan) { //如果设备扫描并报告完成
mNeedToSendFinishedDeviceScan = false;
event->when = now;
event->type = FINISHED_DEVICE_SCAN; //发送一个FINISHED_DEVICE_SCAN事件
event += 1;
if (--capacity == 0) {
break;
}
}
// Grab the next input event.
bool deviceChanged = false;
while (mPendingEventIndex < mPendingEventCount) {
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
//从mPendingEventItems中读取事件
if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {//判定事件类型EPOLL_ID_INOTIFY /dev/input下
//文件有变化时才会发送这个事件 注解3
if (eventItem.events & EPOLLIN) {
mPendingINotify = true; //有了设备变化
} else {
LOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
}
continue;
}
if (eventItem.data.u32 == EPOLL_ID_WAKE) { //看事件类型是否为EPOLL_ID_WAKE 注解4
if (eventItem.events & EPOLLIN) {
LOGV("awoken after wake()");
awoken = true; //唤醒整个input系统
char buffer[16];
ssize_t nRead;
do {
nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));//把管道里的数据读出来
} while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
} else {
LOGW("Received unexpected epoll event 0x%08x for wake read pipe.",
eventItem.events);
}
continue;
}
ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
//如果不是EPOLL_ID_INOTIFY和EPOLL_ID_WAKE 那么得到发送事件的设备的索引
if (deviceIndex < 0) {
LOGW("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, //读取这个设备的event数据
sizeof(struct input_event) * capacity);
if (readSize == 0 || (readSize < 0 && errno == ENODEV)) { //看是不是读取成功了
// Device was removed before INotify noticed.
LOGW("could not get event, removed? (fd: %d size: %d bufferSize: %d capacity: %d errno: %d)\n",
device->fd, readSize, bufferSize, capacity, errno);
deviceChanged = true;
closeDeviceLocked(device);
} else if (readSize < 0) {
if (errno != EAGAIN && errno != EINTR) {
LOGW("could not get event (errno=%d)", errno);
}
} else if ((readSize % sizeof(struct input_event)) != 0) {
LOGE("could not get event (wrong size: %d)", readSize);
} else {
int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
size_t count = size_t(readSize) / sizeof(struct input_event);
//计算这次读取的input_event的个数
for (size_t i = 0; i < count; i++) {
const struct input_event& iev = readBuffer[i];
LOGV("%s got: t0=%d, t1=%d, 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);
#ifdef HAVE_POSIX_CLOCKS
// 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;
LOGV("event time %lld, now %lld", event->when, now);
#else
event->when = now;
#endif
event->deviceId = deviceId; //将input_event转换成android的RawEvent类型
event->type = iev.type;
event->scanCode = iev.code;
event->value = iev.value;
event->keyCode = AKEYCODE_UNKNOWN;
event->flags = 0;
if (iev.type == EV_KEY && device->keyMap.haveKeyLayout()) {
status_t err = device->keyMap.keyLayoutMap->mapKey(iev.code,
&event->keyCode, &event->flags);
LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
iev.code, event->keyCode, event->flags, err);
}
event += 1;
}
capacity -= count;
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; //凑够256就退出
break;
}
}
} else {
LOGW("Received unexpected epoll event 0x%08x for device %s.",
eventItem.events, device->identifier.name.string());
}
}
// readNotify() will modify the list of devices so this must be done after
// processing all other events to ensure that we read all remaining events
// before closing the devices.
if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {//如果有/dev/input下的设
//备有变化 并且还读取到了设备变化的事件
mPendingINotify = false;
readNotifyLocked(); //那么就打开这个设备 这个函数代码都在本目录下
//很简单能看懂 这里就不做说明了
deviceChanged = true;
}
// Report added or removed devices immediately.
if (deviceChanged) { //如果有设备变化了 就跳过这次循环
continue;
}
//我们读取到了 事件,或者 需要唤醒input模块 那么就立即报告所有事件给android上层
// Return now if we have collected any events or if we were explicitly awoken.
if (event != buffer || awoken) {
break;
}
// Poll for events. Mind the wake lock dance!
// We hold a wake lock at all times except during epoll_wait(). This works due to some
// subtle choreography. When a device driver has pending (unread) events, it acquires
// a kernel wake lock. However, once the last pending event has been read, the device
// driver will release the kernel wake lock. To prevent the system from going to sleep
// when this happens, the EventHub holds onto its own user wake lock while the client
// is processing events. Thus the system can only sleep if there are no events
// pending or currently being processed.
//
// The timeout is advisory only. If the device is asleep, it will not wake just to
// service the timeout.
mPendingEventIndex = 0;
mLock.unlock(); // release lock before poll, must be before release_wake_lock
release_wake_lock(WAKE_LOCK_ID);
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
//读取mEpollFd的事件到mPendingEventItems 注解3 注解4
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
mLock.lock(); // reacquire lock after poll, must be after acquire_wake_lock
if (pollResult == 0) {
// Timed out.
mPendingEventCount = 0;
break;
}
if (pollResult < 0) {
// An error occurred.
mPendingEventCount = 0;
// Sleep after errors to avoid locking up the system.
// Hopefully the error is transient.
if (errno != EINTR) {
LOGW("poll failed (errno=%d)\n", errno);
usleep(100000);
}
} else {
// Some events occurred.
mPendingEventCount = size_t(pollResult);
// On an SMP system, it is possible for the framework to read input events
// faster than the kernel input device driver can produce a complete packet.
// Because poll() wakes up as soon as the first input event becomes available,
// the framework will often end up reading one event at a time until the
// packet is complete. Instead of one call to read() returning 71 events,
// it could take 71 calls to read() each returning 1 event.
//
// Sleep for a short period of time after waking up from the poll() to give
// the kernel time to finish writing the entire packet of input events.
if (mNumCpus > 1) {
usleep(250);
}
}
}
// All done, return the number of events we read.
return event - buffer; //返回读取到事件个数
//到这里就把所读取到的事件送给InputReader::loopOnce()来处理了
}
struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
static const char *DEVICE_PATH = "/dev/input"; //定义input设备的目录
void EventHub::scanDevicesLocked() {
status_t res = scanDirLocked(DEVICE_PATH); //扫描这个目录
if(res < 0) {
LOGE("scan dir failed for %s\n", DEVICE_PATH);
}
}
status_t EventHub::scanDirLocked(const char *dirname)
{
char devname[PATH_MAX];
char *filename;
DIR *dir;
struct dirent *de;
dir = opendir(dirname); //打开这个目录 这个函数实现在\android40\bionic\libc\unistd\opendir.c
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;
}
status_t EventHub::openDeviceLocked(const char *devicePath) {
char buffer[80];
LOGV("Opening device: %s", devicePath);
int fd = open(devicePath, O_RDWR);打开这个目录
if(fd < 0) {
LOGE("could not open %s, %s\n", devicePath, strerror(errno));
return -1;
}
InputDeviceIdentifier identifier;
// Get device name.名称
if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
//fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.name.setTo(buffer);
}
// Check to see if the device is on our excluded list 检查这个设备是否在我们的链表上
for (size_t i = 0; i < mExcludedDevices.size(); i++) {
const String8& item = mExcludedDevices.itemAt(i);
if (identifier.name == item) {
LOGI("ignoring event id %s driver %s\n", devicePath, item.string());
close(fd);
return -1;
}
}
// Get device driver version. 驱动版本
int driverVersion;
if(ioctl(fd, EVIOCGVERSION, &driverVersion)) {
LOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno));
close(fd);
return -1;
}
// Get device identifier. 设备ID
struct input_id inputId;
if(ioctl(fd, EVIOCGID, &inputId)) {
LOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno));
close(fd);
return -1;
}
identifier.bus = inputId.bustype;
identifier.product = inputId.product;
identifier.vendor = inputId.vendor;
identifier.version = inputId.version;
// Get device physical location.//物理地址
if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) {
//fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.location.setTo(buffer);
}
// Get device unique id.
if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) {
//fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.uniqueId.setTo(buffer);
}
// Make file descriptor non-blocking for use with poll().
if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
LOGE("Error %d making device file descriptor non-blocking.", 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);
#if 0
LOGI("add device %d: %s\n", deviceId, devicePath);
LOGI(" bus: %04x\n"
" vendor %04x\n"
" product %04x\n"
" version %04x\n",
identifier.bus, identifier.vendor, identifier.product, identifier.version);
LOGI(" name: \"%s\"\n", identifier.name.string());
LOGI(" location: \"%s\"\n", identifier.location.string());
LOGI(" unique id: \"%s\"\n", identifier.uniqueId.string());
LOGI(" driver: v%d.%d.%d\n",
driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff);
#endif
// Load the configuration file for the device.加载设备的配置文件
loadConfigurationLocked(device);
// Figure out the kinds of events the device reports.读取设备 数据的类型
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask);
ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask);
ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask);
ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask);
ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask);
ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask);
//这个设备如果是键盘 那么是否含有 游戏手柄的特殊键 有的话做特殊处理
// See if this is a keyboard. Ignore everything in the button range except for
// joystick and gamepad buttons which are handled like keyboards for the most part.
bool haveKeyboardKeys = containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC))
|| containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK),
sizeof_bit_array(KEY_MAX + 1));
bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC),
sizeof_bit_array(BTN_MOUSE))
|| containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK),
sizeof_bit_array(BTN_DIGI));
if (haveKeyboardKeys || haveGamepadButtons) {
device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
}
// See if this is a cursor device such as a trackball or mouse. 莫非是鼠标?
if (test_bit(BTN_MOUSE, device->keyBitmask)
&& test_bit(REL_X, device->relBitmask)
&& test_bit(REL_Y, device->relBitmask)) {
device->classes |= INPUT_DEVICE_CLASS_CURSOR;
}
// See if this is a touch pad.还是触摸板
// Is this a new modern multi-touch driver?竟然多点触控?
if (test_bit(ABS_MT_POSITION_X, device->absBitmask) //靠x y坐标来判定
&& 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) { //也就是这个BTN_TOUCH,
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;
}
/********************************************************************************
从上面的分析来看要确定这个设备
多点触控需要报三个bit位
ABS_MT_POSITION_X ABS_MT_POSITION_Y BTN_TOUCH
单点触控也是三个bit位
ABS_X ABS_Y BTN_TOUCH
鼠标三个bit位
REL_X REL_Y BTN_MOUSE
********************************************************************************/
// See if this device is a joystick.游戏杆
// Assumes that joysticks always have gamepad buttons in order to distinguish them
// from other devices such as accelerometers that also have absolute axes.
if (haveGamepadButtons) {
uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK;
for (int i = 0; i <= ABS_MAX; i++) {
if (test_bit(i, device->absBitmask)
&& (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) {
device->classes = assumedClasses;
break;
}
}
}
// Check whether this device has switches.
for (int i = 0; i <= SW_MAX; i++) {
if (test_bit(i, device->swBitmask)) {
device->classes |= INPUT_DEVICE_CLASS_SWITCH;
break;
}
}
// Configure virtual keys. 虚拟按键处理这个也很重要现在一般触摸屏上带的按键都是这么处理的
//下面会单独讲 注解5
if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) {
// Load the virtual keys for the touch screen, if any.
// We do this now so that we can make sure to load the keymap if necessary.
status_t status = loadVirtualKeyMapLocked(device);
LOGE("Get virtualkeys\n");
if (!status) {
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);//获取设备的keymap文件 这个对于按键设备来讲比较
} //重要也比较复杂 可以百度 android keymap
// Configure the keyboard, gamepad or virtual keyboard.配置键盘类的设备
if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) {
// Register the keyboard as a built-in keyboard if it is eligible.
if (!keyMapStatus
&& mBuiltInKeyboardId == -1
&& isEligibleBuiltInKeyboard(device->identifier,
device->configuration, &device->keyMap)) {
mBuiltInKeyboardId = device->id;
}
// 'Q' key support = cheap test of whether this is an alpha-capable kbd
if (hasKeycodeLocked(device, AKEYCODE_Q)) {
device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;
}
// See if this device has a DPAD.
if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) &&
hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) &&
hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) &&
hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) &&
hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) {
device->classes |= INPUT_DEVICE_CLASS_DPAD;
}
// See if this device has a gamepad.
for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) {
if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) {
device->classes |= INPUT_DEVICE_CLASS_GAMEPAD;
break;
}
}
}
/********************************************************************************
注意上面device->classes的赋值方式都是除了joystick其他都是 “|=” 也就是说一个设备其实可以
识别出多个类这也是为什么一个触摸屏可以发送按键指令的原因
********************************************************************************/
//有些设备不支持 比如有些传感器走的也是input设备但是他们由单独的传感器模块处理
//而不是有eventhub,因此这里他们会被排除掉。
// If the device isn't recognized as something we handle, don't monitor it.
if (device->classes == 0) {
LOGV("Dropping device: id=%d, path='%s', name='%s'",
deviceId, devicePath, device->identifier.name.string());
delete device;
return -1;
}
//判断是内部设备还是外部设备看代码判定是外部设备有两个条件一是配置文件中有
//"device.internal"这个配置项就是内部设备其他为外部设备,一是总线类型是usb或者蓝牙就是外部设备。
// Determine whether the device is external or internal.
if (isExternalDeviceLocked(device)) {
device->classes |= INPUT_DEVICE_CLASS_EXTERNAL;
}
//注册一个epoll来监听这个设备的事件。
//epoll是内核提供的一个监听设备的一个方法跟select类似不过比select更高效而且没有个数的限制
// Register with epoll.
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
eventItem.data.u32 = deviceId;
if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
LOGE("Could not add device fd to epoll instance. errno=%d", errno);
delete device;
return -1;
}
LOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
"configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s",
deviceId, fd, devicePath, device->identifier.name.string(),
device->classes,
device->configurationFile.string(),
device->keyMap.keyLayoutFile.string(),
device->keyMap.keyCharacterMapFile.string(),
toString(mBuiltInKeyboardId == deviceId));
mDevices.add(deviceId, device);//将设备加入到已打开设备链表中
device->next = mOpeningDevices;
mOpeningDevices = device;
return 0;
}
void EventHub::loadConfigurationLocked(Device* device) {
device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(
device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);
if (device->configurationFile.isEmpty()) {
LOGD("No input device configuration file found for device '%s'.",
device->identifier.name.string());
} else {
status_t status = PropertyMap::load(device->configurationFile,
&device->configuration);
if (status) {
LOGE("Error loading input device configuration file for device '%s'. "
"Using default configuration.",
device->identifier.name.string());
}
}
}
String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
const InputDeviceIdentifier& deviceIdentifier,
InputDeviceConfigurationFileType type) {
if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
if (deviceIdentifier.version != 0) {
// Try vendor product version.
//首先从厂商编号、设备编号和设备驱动版本号去获取设备文件
String8 versionPath(getInputDeviceConfigurationFilePathByName(
String8::format("Vendor_%04x_Product_%04x_Version_%04x",
deviceIdentifier.vendor, deviceIdentifier.product,
deviceIdentifier.version),
type));
if (!versionPath.isEmpty()) {
return versionPath;
}
}
// Try vendor product.
String8 productPath(getInputDeviceConfigurationFilePathByName(
String8::format("Vendor_%04x_Product_%04x",
deviceIdentifier.vendor,deviceIdentifier.product),//如果没有成功就从厂商编号
type)); //和设备编号去获取
if (!productPath.isEmpty()) {
return productPath;
}
}
// Try device name.
return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type);//如果还没有的话就
//从设备名去获取
}
status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier,
const PropertyMap* deviceConfiguration) {
// Use the configured key layout if available.
if (deviceConfiguration) {
String8 keyLayoutName;
if(deviceConfiguration->tryGetProperty(String8("keyboard.layout"),//查找配置文件中keyboard.layout
keyLayoutName)) { //项 来加载layout文件
status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName);
if (status == NAME_NOT_FOUND) {
LOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
"it was not found.",
deviceIdenfifier.name.string(), keyLayoutName.string());
}
}
String8 keyCharacterMapName;
if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"), //查找配置文件中
keyCharacterMapName)) { //keyboard.characterMap项 来加载characterMap文件
status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName);
if (status == NAME_NOT_FOUND) {
LOGE("Configuration for keyboard device '%s' requested keyboard character "
"map '%s' but it was not found.",
deviceIdenfifier.name.string(), keyLayoutName.string());
}
}
if (isComplete()) {
return OK;
}
}
// Try searching by device identifier.
if (probeKeyMap(deviceIdenfifier, String8::empty())) {
return OK; //如果没有成功就靠 厂商id 设备id 驱动版本 等来查找
}
// Fall back on the Generic key map.
// TODO Apply some additional heuristics here to figure out what kind of
// generic key map to use (US English, etc.) for typical external keyboards.
if (probeKeyMap(deviceIdenfifier, String8("Generic"))) { //如果还没有成功就打开"Generic"
return OK;
}
// Try the Virtual key map as a last resort.
if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) { //还没有就打开 "Virtual"
return OK;
}
// Give up!
LOGE("Could not determine key map for device '%s' and no default key maps were found!",
deviceIdenfifier.name.string());
return NAME_NOT_FOUND;
}
mEpollFd = epoll_create(EPOLL_SIZE_HINT); //创建一个 epoll文件
mINotifyFd = inotify_init(); // 用来监控/dev/input/目录下的文件改动
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
eventItem.data.u32 = EPOLL_ID_INOTIFY;//添加的监控设备所要发送的事件类型
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
//取出mEpollFd的事件放在数组mPendingEventItems中
int wakeFds[2];
result = pipe(wakeFds); //创建管道
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);//注册这个管道
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
eventItem.data.u32 = EPOLL_ID_WAKE;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
//将read管道添加到mEpollFd的监控中
status_t EventHub::loadVirtualKeyMapLocked(Device* device) {
// The virtual key map is supplied by the kernel as a system board property file.
String8 path;
path.append("/sys/board_properties/virtualkeys.");
path.append(device->identifier.name);//虚拟按键配置文件在/sys/board_properties/virtualkeys.name中
if (access(path.string(), R_OK)) {
return NAME_NOT_FOUND;
}
return VirtualKeyMap::load(path, &device->virtualKeyMap);
}
status_t VirtualKeyMap::load(const String8& filename, VirtualKeyMap** outMap){
*outMap = NULL;
Tokenizer* tokenizer;
status_t status = Tokenizer::open(filename, &tokenizer);//打开文件获得tokenizer
if (status) {
LOGE("Error %d opening virtual key map file %s.", status, filename.string());
} else {
VirtualKeyMap* map = new VirtualKeyMap();
if (!map) {
LOGE("Error allocating virtual key map.");
status = NO_MEMORY;
} else {
#if DEBUG_PARSER_PERFORMANCE
nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
#endif
Parser parser(map, tokenizer);
status = parser.parse();
#if DEBUG_PARSER_PERFORMANCE
nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
LOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
tokenizer->getFilename().string(), tokenizer->getLineNumber(),
elapsedTime / 1000000.0);
#endif
if (status) {
delete map;
} else {
*outMap = map; //返回 map的指针
}
}
delete tokenizer;
}
return status;
}
void InputReader::loopOnce() {
int32_t timeoutMillis;
{
。。。。。。。。
。。。。。。。。。。
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
if (count) {
processEventsLocked(mEventBuffer, count);
}
。。。。。。。。。。。。。。
}
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
for (const RawEvent* rawEvent = rawEvents; count;) { //循环处理所有事件
int32_t type = rawEvent->type;
size_t batchSize = 1;
//如果事件的类型比FIRST_SYNTHETIC_EVENT 说明这是个kernel传来的input事件
if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
int32_t deviceId = rawEvent->deviceId;
while (batchSize < count) {
//找到属于同一个设备所有事件 或者 同一设备 但类型为FIRST_SYNTHETIC_EVENT之
//前的所有事件 ,从这里可以看出如果要系统处理一次的操作,那么驱动层必须发送
//FIRST_SYNTHETIC_EVENT事件,或者造成设备切换,设备切换不是我们能控制的因此我
//们必须发送FIRST_SYNTHETIC_EVENT事件来告诉系统这次操作完成了。
if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
|| rawEvent[batchSize].deviceId != deviceId) {
break;
}
batchSize += 1;
}
#if DEBUG_RAW_EVENTS
LOGD("BatchSize: %d Count: %d", batchSize, count);
#endif
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);//处理这些事件 注解7
} else { //这个是设备变化的事件
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED: //增加设备
addDeviceLocked(rawEvent->when, rawEvent->deviceId); //注解6
break;
case EventHubInterface::DEVICE_REMOVED:
//删除设备这个不多做说明了,就是把当前设备 从设备链表里删除
removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::FINISHED_DEVICE_SCAN: //扫描设备完成
handleConfigurationChangedLocked(rawEvent->when);注
break;
default:
LOG_ASSERT(false); // can't happen
break;
}
}
count -= batchSize;
rawEvent += batchSize;
}
}
void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
String8 name = mEventHub->getDeviceName(deviceId); //得到设备名字
uint32_t classes = mEventHub->getDeviceClasses(deviceId);//得到设备类型
InputDevice* device = createDeviceLocked(deviceId, name, classes);//创建一个inputreader层的设备
device->configure(when, &mConfig, 0); //配置一些东西 ----------------------------+-
device->reset(when); //复位 ||
||
if (device->isIgnored()) {//看mapper是否添加成功了 ||
LOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId, name.string());||
} else { ||
LOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId, name.string(), ||
device->getSources()); ||
} ||
||
ssize_t deviceIndex = mDevices.indexOfKey(deviceId); ||
if (deviceIndex < 0) { ||
mDevices.add(deviceId, device); //添加新建的设备 ||
} else { ||
LOGW("Ignoring spurious device added event for deviceId %d.", deviceId); ||
delete device; ||
return; ||
} ||
||
这个函数里调用了createDeviceLocked() 和 configure()我们一一来看 ||
createDeviceLocked()在当前文件中代码 <---------------------------------- |
InputDevice* InputReader::createDeviceLocked(int32_t deviceId, |
const String8& name, uint32_t classes) { |
InputDevice* device = new InputDevice(&mContext, deviceId, name, classes);//创建一个新设备 |
|
// External devices. |
if (classes & INPUT_DEVICE_CLASS_EXTERNAL) { //为外部设备 设置专门属性 |
device->setExternal(true); |
} |
//为switch设备添加mapper文件inputmapper文件是事件的映射文件,负责把事件处理后输送给相应的上层app|
//这个设备很少用到我们就暂时不分析了代码在InputReader.cpp中 需要的自己看一下 |
// Switch-like devices. |
if (classes & INPUT_DEVICE_CLASS_SWITCH) { |
device->addMapper(new SwitchInputMapper(device)); |
} |
|
// Keyboard-like devices. |
uint32_t keyboardSource = 0; |
int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC; |
if (classes & INPUT_DEVICE_CLASS_KEYBOARD) { |
//设置按键类设备的mapper属性这里添加的mapper文件只有基本属性,并没有具体的内容具体配置是 |
//在config中进行的 |
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) { //为按键类设备添加mapper文件 |
device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType)); |
} |
|
// Cursor-like devices. |
if (classes & INPUT_DEVICE_CLASS_CURSOR) { //为鼠标类设备添加mapper 文件 |
device->addMapper(new CursorInputMapper(device)); |
} |
|
// Touchscreens and touchpad devices. |
if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) { //触控类添加mapper文件 |
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) { //游戏杆类添加mapper文件 |
device->addMapper(new JoystickInputMapper(device)); |
} |
|
return device; |
} |
|
对于上面的addMapper这个函数 |
void InputDevice::addMapper(InputMapper* mapper) { |
mMappers.add(mapper); |
} |
|
这里调用了mMappers.add(mapper);我没找到这add方法的实现代码在哪?哪位大神可以提示一下最好。在此先谢过|
不过createDeviceLocked这个函数还是很简单的,就是一些新建设备和mapper文件,具体的操作都没有涉及到 |
|
下面看InputDevice::configure 也在这个文件中 <-------------------------
void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes){
mSources = 0;
if (!isIgnored()) { //mapper文件不为空
if (!changes) { // first time only
mContext->getEventHub()->getConfiguration(mId, &mConfiguration); //找到相应的idc文件
}
size_t numMappers = mMappers.size();
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];
mapper->configure(when, config, changes);
mSources |= mapper->getSources();
}
}
}
上面调用的getConfiguration()在 EventHub.cpp中
先看getConfiguration()这个函数的作用是,返回设备的配置文件(即idc文件)指针。
void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device && device->configuration) {
*outConfiguration = *device->configuration;
} else {
outConfiguration->clear();
}
}
void TouchInputMapper::configure(nsecs_t when,
const InputReaderConfiguration* config, uint32_t changes) {
InputMapper::configure(when, config, changes);
mConfig = *config;
if (!changes) { // first time only
// Configure basic parameters.
configureParameters(); //见下面 |
V
/************************************************************************************************
上面调用的configureParameters()函数
void TouchInputMapper::configureParameters() {
// Use the pointer presentation mode for devices that do not supportdistinct
//基于指针的配置并不明显的支持多点触控,这里的配置能够准确的配置两点或以上设备
// multitouch. The spot-based presentation relies on being able to accurately
// locate two or more fingers on the touch pad.
mParameters.gestureMode = getEventHub()->hasInputProperty(getDeviceId(),INPUT_PROP_SEMI_MT)
//从驱动里确定device 是多点触控 还是指针,还是点设备
? Parameters::GESTURE_MODE_POINTER : Parameters::GESTURE_MODE_SPOTS;
String8 gestureModeString;
//配置文件中找touch.gestureMode这个条目 来确定设备的类型
if(getDevice()->getConfiguration().tryGetProperty(String8("touch.gestureMode"),
gestureModeString)) {
if (gestureModeString == "pointer") { //如果指针
mParameters.gestureMode = Parameters::GESTURE_MODE_POINTER;
} else if (gestureModeString == "spots") { //点设备
mParameters.gestureMode = Parameters::GESTURE_MODE_SPOTS;
} else if (gestureModeString != "default") { //默认
LOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string());
}
}
//从驱动文件里确定 触控设备的类型
if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_DIRECT)) {
// The device is a touch screen.
mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; //触摸屏
} else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_POINTER)) {
// The device is a pointing device like a track pad.
mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; //指针设备(多指鼠标)
} else if (getEventHub()->hasRelativeAxis(getDeviceId(), REL_X) //传送的坐标是相对坐标
|| getEventHub()->hasRelativeAxis(getDeviceId(), REL_Y)) { //y也是相对坐标
// The device is a cursor device with a touch pad attached.
// By default don't use the touch pad to move the pointer.
mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; //那就是触摸板
} else {
// The device is a touch pad of unknown purpose.
mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; //指针设备
}
String8 deviceTypeString;
if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"),
deviceTypeString)) {
//从配置文件中确定设备类型
if (deviceTypeString == "touchScreen") {
mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; //触摸屏
} else if (deviceTypeString == "touchPad") {
mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; //触摸板
} else if (deviceTypeString == "pointer") {
mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; //指针设备
} else if (deviceTypeString != "default") {
LOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string());
}
}
mParameters.orientationAware = mParameters.deviceType ==Parameters::DEVICE_TYPE_TOUCH_SCREEN;
getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"),
mParameters.orientationAware);
//idc文件中找"touch.orientationAware"这个条目来确定屏幕的方向
mParameters.associatedDisplayId = -1;
mParameters.associatedDisplayIsExternal = false;
if (mParameters.orientationAware
|| mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
|| mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
mParameters.associatedDisplayIsExternal =
mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
&& getDevice()->isExternal();
mParameters.associatedDisplayId = 0;
}
}
*******************************************************************************************/
// Configure common accumulators.配置光标和按键加速,都是根据驱动文件或者idc文件
mCursorScrollAccumulator.configure(getDevice());
mTouchButtonAccumulator.configure(getDevice());
// Configure absolute axis information.将所有坐标相关初始值清除
代码在本文件中的void RawPointerAxes::clear()
configureRawPointerAxes();
//然后调用voidMultiTouchInputMapper::configureRawPointerAxes()也在本文件中,它是从
//驱动文件里面找到一些配置然后读取出来 这些代码就不贴出来了太多了 而且意义不大
// Prepare input device calibration. 准备 输入设备标准把硬件信息 加入到 建立的虚拟设备中例如
parseCalibration();
//分辨率 屏幕方向 显示区域等信息 代码很长不贴了
resolveCalibration();
}
if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) {
// Update pointer speed. //校准 指针速度
mPointerVelocityControl.setParameters(mConfig.pointerVelocityControlParameters);
mWheelXVelocityControl.setParameters(mConfig.wheelVelocityControlParameters);
mWheelYVelocityControl.setParameters(mConfig.wheelVelocityControlParameters);
//简单的校准参数赋值 代码很简单都在本文件中 这里就不贴了
}
bool resetNeeded = false;
if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO
| InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT
| InputReaderConfiguration::CHANGE_SHOW_TOUCHES))) {
// Configure device sources, surface dimensions, orientation and
// scaling factors.
configureSurface(when,&resetNeeded);----------------------------------------------------------
} |
|
if (changes && resetNeeded) { |
//Send reset, unless this is the first time the device has beenconfigured,除非这个设备是第一次配置, |
//in which case the reader will call reset itself after all mappers areready否则在这里它将被reset一次|
getDevice()->notifyReset(when); |
} |
} |
|
/********************************************************************************************** <-----
下面看 configureSurface(when, &resetNeeded); 在InputReader.cpp中
void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
int32_t oldDeviceMode = mDeviceMode;
// Determine device mode. 通过设备的类型来确定mSource和mDeviceMode。
if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER
&& mConfig.pointerGesturesEnabled) {
mSource = AINPUT_SOURCE_MOUSE;
mDeviceMode = DEVICE_MODE_POINTER;
} else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
&& mParameters.associatedDisplayId >= 0) {
mSource = AINPUT_SOURCE_TOUCHSCREEN;
mDeviceMode = DEVICE_MODE_DIRECT;
} else {
mSource = AINPUT_SOURCE_TOUCHPAD;
mDeviceMode = DEVICE_MODE_UNSCALED;
}
// Ensure we have valid X and Y axes.从驱动中读出来的配置中 x和y的值 是有效的
if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) {
LOGW(INDENT "Touch device '%s' did not report support for X or Y axis! "
"The device will be inoperable.", getDeviceName().string());
mDeviceMode = DEVICE_MODE_DISABLED;
return;
}
// Get associated display dimensions.
if (mParameters.associatedDisplayId >= 0) {
if (!mConfig.getDisplayInfo(mParameters.associatedDisplayId //得到显示屏的分辨率 代码在本文件中
mParameters.associatedDisplayIsExternal, |
&mAssociatedDisplayWidth, &mAssociatedDisplayHeight, |
&mAssociatedDisplayOrientation)) { |
LOGI(INDENT "Touch device '%s' could not query the properties of its associated " |
"display %d. The device will be inoperable until the display size " |
"becomes available.", |
getDeviceName().string(), mParameters.associatedDisplayId); |
mDeviceMode = DEVICE_MODE_DISABLED; |
return; |
} |
} V
/***********************************************************************************************
bool InputReaderConfiguration::getDisplayInfo(int32_t displayId, bool external,
int32_t* width, int32_t* height, int32_t* orientation) const {
if (displayId == 0) {
const DisplayInfo& info = external ? mExternalDisplay : mInternalDisplay;
//这里的关键是 mExternalDisplay和mInternalDisplay在哪里初始化的值
if (info.width > 0 && info.height > 0) { //其实这是在另外一个进程里设置的 过程比较复杂
if (width) {
//参考http://wenku.baidu.com/view/1c25e14a2e3f5727a5e9621f.html
*width = info.width;
}
if (height) {
*height = info.height;
}
if (orientation) {
*orientation = info.orientation;
}
return true;
}
}
return false;
}
************************************************************************************************/
// Configure dimensions. 根据上面确定的mDeviceMode 来确定 实际可用的分辨率,
int32_t width, height, orientation;
if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) {
width = mAssociatedDisplayWidth; //真实的分辨率
height = mAssociatedDisplayHeight;
orientation = mParameters.orientationAware ?
mAssociatedDisplayOrientation : DISPLAY_ORIENTATION_0;
} else {
//驱动中读出来的分辨率经过计算得到的
width = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1;
height = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1;
orientation = DISPLAY_ORIENTATION_0;
}
// If moving between pointer modes, need to reset some state.
//设备类型发生了改变这说明前面的配置可能发生某种意外 清除一些状态 下面重新来配置
bool deviceModeChanged;
if (mDeviceMode != oldDeviceMode) {
deviceModeChanged = true;
mOrientedRanges.clear();
}
// Create pointer controller if needed.
if (mDeviceMode == DEVICE_MODE_POINTER ||
(mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) {
if (mPointerController == NULL) {
mPointerController = getPolicy()->obtainPointerController(getDeviceId());
//建立一个pointer controller
//pointercontroller 是神马东西呢我们可以找到他们的代码
//android\frameworks\base\services\input\PointerController.cpp中,这里就不分析代码了,实在太多了,仅
//对它的作用说明一下:当我们触摸屏幕或者移动鼠标时,我们有时候需要在屏幕上
触摸点或者鼠标光标的位置,
//pointer controller 就是同步坐标和显示位置用的
}
} else {
mPointerController.clear();
}
char hwrotBuf[PROPERTY_VALUE_MAX];
int32_t hwrotation;
property_get("ro.sf.hwrotation", hwrotBuf, "0");
hwrotation = atoi(hwrotBuf) / 90;
orientation = (orientation + hwrotation ) % 4;
if (hwrotation == DISPLAY_ORIENTATION_90 ||
hwrotation == DISPLAY_ORIENTATION_270) {
int tmp = width;
width = height;
height = tmp;
}
bool orientationChanged = mSurfaceOrientation != orientation;
if (orientationChanged) {
mSurfaceOrientation = orientation;
}
bool sizeChanged = mSurfaceWidth != width || mSurfaceHeight != height;
if (sizeChanged || deviceModeChanged) {
LOGI("Device reconfigured: id=%d, name='%s', surface size is now %dx%d, mode is %d",
getDeviceId(), getDeviceName().string(), width, height, mDeviceMode);
mSurfaceWidth = width;
mSurfaceHeight = height;
// Configure X and Y factors.
mXScale = float(width) / (mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1);
mYScale = float(height) / (mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1);
mXPrecision = 1.0f / mXScale;
mYPrecision = 1.0f / mYScale;
mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X;//如果分辨率有了改变就需要重新配置一些参数
mOrientedRanges.x.source = mSource;
mOrientedRanges.y.axis = AMOTION_EVENT_AXIS_Y;
mOrientedRanges.y.source = mSource;
configureVirtualKeys(); //配置虚拟按键 代码在本文件中 |
V
/*****************************************************************************************
void TouchInputMapper::configureVirtualKeys() {
Vector virtualKeyDefinitions;
getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions);
//这里有个新数据类型Vector,他的作用我们做个说明
//vector是C++标准模板库中的部分内容,中文偶尔译作“容器”,但并不准确。它是一个多功能的,
//能够操作多种数据结构和算法的模板类和函数库。vector之所以被认为是一个容器,是因为它能够
//像容器一样存放各种类型的对象,简单地说,vector是一个能够存放任意类型的动态数组,能够增
//加和压缩数据。
mVirtualKeys.clear();
if (virtualKeyDefinitions.size() == 0) {
return;
}
mVirtualKeys.setCapacity(virtualKeyDefinitions.size());
int32_t touchScreenLeft = mRawPointerAxes.x.minValue; //确定按键的 坐标和大小
int32_t touchScreenTop = mRawPointerAxes.y.minValue;
int32_t touchScreenWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1;
int32_t touchScreenHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1;
for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
const VirtualKeyDefinition& virtualKeyDefinition =
virtualKeyDefinitions[i];
//得到按键的定义(虚拟按键配置文件中读出来的)
mVirtualKeys.add(); //添加这个按键
VirtualKey& virtualKey = mVirtualKeys.editTop();
virtualKey.scanCode = virtualKeyDefinition.scanCode;
int32_t keyCode;
uint32_t flags;
if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode,
& keyCode, & flags)) {
LOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring",
virtualKey.scanCode);
mVirtualKeys.pop(); // drop the key 失败了。。。
continue;
}
virtualKey.keyCode = keyCode;
virtualKey.flags = flags;
// convert the key definition's display coordinates into touch coordinates for a hitbox
int32_t halfWidth = virtualKeyDefinition.width / 2;
int32_t halfHeight = virtualKeyDefinition.height / 2;
//按键的上下左右坐标
virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth)
* touchScreenWidth / mSurfaceWidth + touchScreenLeft;
virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth)
* touchScreenWidth / mSurfaceWidth + touchScreenLeft;
virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight)
* touchScreenHeight / mSurfaceHeight + touchScreenTop;
virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight)
* touchScreenHeight / mSurfaceHeight + touchScreenTop;
}
}
********************************************************************************************/
剩下的就 不多说了 全是参数的配置
。。。。。。。。。
。。。。。。。。。
。。。。。。。。。
}
*************************************************************************************************/
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
// Process all of the events in order for each mapper. 让每个设备的 mapper处理相应的input事件
// 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--; rawEvent++) {
。。。。。
if (mDropUntilNextSync) {
if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_REPORT) {
mDropUntilNextSync = false;
.........
} else {
.............
}
} else if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_DROPPED) {
LOGI("Detected input event buffer overrun for device %s.", mName.string());
mDropUntilNextSync = true;
reset(rawEvent->when);
} else {
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];
mapper->process(rawEvent); //通过每个设备mapper 来处理事件我们来看多点触控的
} |
} |
} |
} |
V
上面调用的 在本文件中
void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
TouchInputMapper::process(rawEvent);
mMultiTouchMotionAccumulator.process(rawEvent);
}
继续看mMultiTouchMotionAccumulator.process(rawEvent); 也在本文件中
void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
if (rawEvent->type == EV_ABS) { //只处理 EV_ABS EV_SYN 和 SYN_MT_REPORT
bool newSlot = false;
if (mUsingSlotsProtocol) {
if (rawEvent->scanCode == ABS_MT_SLOT) { //多点触控槽这个我也不知道怎么翻译好,但是具体
mCurrentSlot = rawEvent->value; //作用我知道的很清楚指的是多点触控所支持的最大点数
newSlot = true;
}
} else if (mCurrentSlot < 0) {
mCurrentSlot = 0;
}
//触摸屏所支持的最大点数设置错误 就报个错
if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) {
#if DEBUG_POINTERS
if (newSlot) {
LOGW("MultiTouch device emitted invalid slot index %d but it "
"should be between 0 and %d; ignoring this slot.",
mCurrentSlot, mSlotCount - 1);
}
#endif
} else {
Slot* slot = &mSlots[mCurrentSlot];
switch (rawEvent->scanCode) { //解析所有的合法的多点触控数据
case ABS_MT_POSITION_X: //X坐标
slot->mInUse = true;
slot->mAbsMTPositionX = rawEvent->value;
break;
case ABS_MT_POSITION_Y://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;
case ABS_MT_TRACKING_ID: //触点的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->scanCode == SYN_MT_REPORT) {
// MultiTouch Sync: The driver has returned all data for *one* of the pointers.
mCurrentSlot += 1;
}
}
void TouchInputMapper::process(const RawEvent* rawEvent) {
mCursorButtonAccumulator.process(rawEvent);
mCursorScrollAccumulator.process(rawEvent);
mTouchButtonAccumulator.process(rawEvent);
if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_REPORT) {
sync(rawEvent->when);
}
}
void TouchInputMapper::sync(nsecs_t when) {
// Sync button state.
mCurrentButtonState = mTouchButtonAccumulator.getButtonState() //同步按键状态
| mCursorButtonAccumulator.getButtonState();
// Sync scroll state.
mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); //滚动条状态
mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
mCursorScrollAccumulator.finishSync(); //清除以前信息
// Sync touch state.
bool havePointerIds = true;
mCurrentRawPointerData.clear();
syncTouch(when, &havePointerIds);--------
|
。。。。。。 |
。。。。。。 V
/*************************************************************************************
void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) {
size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();
size_t outCount = 0;
BitSet32 newPointerIdBits;
for (size_t inIndex = 0; inIndex < inCount; inIndex++) {
const MultiTouchMotionAccumulator::Slot* inSlot =
mMultiTouchMotionAccumulator.getSlot(inIndex);
if (!inSlot->isInUse()) {
continue;
}
if (outCount >= MAX_POINTERS) {
........
break; // too many fingers!
}
//把事件信息放到 mCurrentRawPointerData.pointers中 供后面使用
RawPointerData::Pointer& outPointer = mCurrentRawPointerData.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. //看看 点的ID是否有效
if (*outHavePointerIds) {
int32_t trackingId = inSlot->getTrackingId();
int32_t id = -1;
if (trackingId >= 0) {
for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) {
uint32_t n = idBits.clearFirstMarkedBit();
if (mPointerTrackingIdMap[n] == trackingId) {
id = n;
}
}
if (id < 0 && !mPointerIdBits.isFull()) {
id = mPointerIdBits.markFirstUnmarkedBit();
mPointerTrackingIdMap[id] = trackingId;
}
}
if (id < 0) {
*outHavePointerIds = false;
mCurrentRawPointerData.clearIdBits();
newPointerIdBits.clear();
} else {
outPointer.id = id;
mCurrentRawPointerData.idToIndex[id] = outCount;
mCurrentRawPointerData.markIdBit(id, isHovering);
newPointerIdBits.markBit(id);
}
}
outCount += 1;
}
mCurrentRawPointerData.pointerCount = outCount;
mPointerIdBits = newPointerIdBits;
mMultiTouchMotionAccumulator.finishSync();
}
************************************************************************************/
// Reset state that we will compute below.
mCurrentFingerIdBits.clear(); //先清除一些数据
mCurrentStylusIdBits.clear();
mCurrentMouseIdBits.clear();
mCurrentCookedPointerData.clear();
if (mDeviceMode == DEVICE_MODE_DISABLED) {
// Drop all input if the device is disabled. //设备无效就把数据清除
mCurrentRawPointerData.clear();
mCurrentButtonState = 0;
} else {
// Preprocess pointer data. //否则就处理他们
if (!havePointerIds) {
assignPointerIds();
}
// Handle policy on initial down or hover events.
uint32_t policyFlags = 0;
bool initialDown = mLastRawPointerData.pointerCount == 0
&& mCurrentRawPointerData.pointerCount != 0;
bool buttonsPressed = mCurrentButtonState & ~mLastButtonState;
if (initialDown || buttonsPressed) { //如果第一次摁下
// If this is a touch screen, hide the pointer on an initialdown.如果是个触摸屏,隐藏这个点
if (mDeviceMode == DEVICE_MODE_DIRECT) {
getContext()->fadePointer();
}
// Initial downs on external touch devices should wake thedevice.如果是外部设备就唤醒整个系统
// We don't do this for internal touch screens to prevent them from waking
// up in your pocket.//内部设备不用唤醒,因为有时候你仅仅是把设备放进口袋里
// TODO: Use the input device configuration to control this behavior more finely.
if (getDevice()->isExternal()) {
policyFlags |= POLICY_FLAG_WAKE_DROPPED;
}
}
。。。。。。。。。
// Cook pointer data. This call populates the mCurrentCookedPointerData 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();//根据当前屏幕显示状态进行坐标转换关于这个官网有个很详细的介绍这里就不做说
//明了给出网址http://source.android.com/devices/tech/input/touch-devices.html
// Dispatch the touches either directly or by translation through a pointer on screen.
if (mDeviceMode == DEVICE_MODE_POINTER) { //如果是鼠标
。。。。。。。。。。。。。。
// Stylus takes precedence over all tools, then mouse, then finger.优先级 笔《鼠标《手指
PointerUsage pointerUsage = mPointerUsage;
if (!mCurrentStylusIdBits.isEmpty()) {
mCurrentMouseIdBits.clear();
mCurrentFingerIdBits.clear();
pointerUsage = POINTER_USAGE_STYLUS;
} else if (!mCurrentMouseIdBits.isEmpty()) {
mCurrentFingerIdBits.clear();
pointerUsage = POINTER_USAGE_MOUSE;
} else if (!mCurrentFingerIdBits.isEmpty() || isPointerDown(mCurrentButtonState)) {
pointerUsage = POINTER_USAGE_GESTURES;
}
dispatchPointerUsage(when, policyFlags, pointerUsage);//分发这个事件 这里不做说明我们从下
//面touch设备看起最终他俩是一个作用就是把事件放入到 待处理的队列中
} else {
if (mDeviceMode == DEVICE_MODE_DIRECT
&& mConfig.showTouches && mPointerController != NULL) {
mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
mPointerController->setButtonState(mCurrentButtonState);
mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords,
mCurrentCookedPointerData.idToIndex,
mCurrentCookedPointerData.touchingIdBits);
}
dispatchHoverExit(when, policyFlags);
dispatchTouches(when, policyFlags); ---------------------
dispatchHoverEnterAndMove(when, policyFlags); |
} V
/**********************************************************************************************
void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
。。。。。。。。。。。。。。。。。。。。。。
if (currentIdBits == lastIdBits) {
if (!currentIdBits.isEmpty()) {
// No pointer id changes so this is a move event.点ID没有变化 那么这是一个MOVE 事件
// The listener takes care of batching moves so we don't have to deal with that here.
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState,
AMOTION_EVENT_EDGE_FLAG_NONE,
mCurrentCookedPointerData.pointerProperties,
mCurrentCookedPointerData.pointerCoords,
mCurrentCookedPointerData.idToIndex,
currentIdBits, -1,
mOrientedXPrecision, mOrientedYPrecision, mDownTime);
}
} else { //有可能是 up down move 等事件
。。。。。。。。。。。。。。。
// Dispatch pointer up events. //up事件处理
while (!upIdBits.isEmpty()) {
uint32_t upId = upIdBits.clearFirstMarkedBit();
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, buttonState, 0,
mLastCookedPointerData.pointerProperties,
mLastCookedPointerData.pointerCoords,
mLastCookedPointerData.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.
if (moveNeeded) { //move事件处理
LOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, 0,
mCurrentCookedPointerData.pointerProperties,
mCurrentCookedPointerData.pointerCoords,
mCurrentCookedPointerData.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, //down事件处理
AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0,
mCurrentCookedPointerData.pointerProperties,
mCurrentCookedPointerData.pointerCoords,
mCurrentCookedPointerData.idToIndex,
dispatchedIdBits, downId,
mOrientedXPrecision, mOrientedYPrecision, mDownTime);
}
}
}
void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
const PointerProperties* properties, const PointerCoords* coords,
const uint32_t* idToIndex, BitSet32 idBits,
int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) {
。。。。。。。。。。。
。。。。。。。。。。。。。
NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
action, flags, metaState, buttonState, edgeFlags,
pointerCount, pointerProperties, pointerCoords, xPrecision, yPrecision, downTime);
getListener()->notifyMotion(&args);
这里调用TouchInputMapper::getListener()->notifyMotion(&args)TouchInputMapper::getListener()调用
mContext->getListener(),
此mContext为InputReader::mContext,所以其getListener()返回的则为
InputReader::mQueuedListener,则最后调用QueuedInputListener::notifyMotion
最后我们找到实现代码在android\frameworks\base\services\input\InputListener.cpp中
void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
mArgsQueue.push(new NotifyMotionArgs(*args));
}
这个函数是把 整理好的事件 放入到队列里。
。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。。。。。。。
}
void InputReader::loopOnce() {
int32_t timeoutMillis;
{ // acquire lock
。。。。。。。。。。。。。。
processEventsLocked(mEventBuffer, count);
。。。。。。。。。。。。。。。。。。。。
// Flush queued events out to the listener.将队列里的事件发送到给各个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();
}
void QueuedInputListener::flush() {
size_t count = mArgsQueue.size();
for (size_t i = 0; i < count; i++) {
NotifyArgs* args = mArgsQueue[i];
args->notify(mInnerListener);
delete args;
}
mArgsQueue.clear();
}
QueuedInputListener::QueuedInputListener(const sp& innerListener) :
mInnerListener(innerListener) {
}
InputReader::InputReader(const sp& eventHub,
const sp& policy,
const sp& listener) :
mContext(this), mEventHub(eventHub), mPolicy(policy),
mGlobalMetaState(0), mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
mQueuedListener = new QueuedInputListener(listener);
InputManager::InputManager(
const sp& eventHub,
const sp& readerPolicy,
const sp& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
void NotifyMotionArgs::notify(const sp& listener) const {
listener->notifyMotion(this);
}
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
。。。。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。.
if (!motionEntry->canAppendSamples(args->action, //将事件复制到mInboundQueue中
args->pointerCount, args->pointerProperties)) {
// Last motion event in the queue for this device and source is
// not compatible for appending new samples. Stop here.
goto NoBatchingOrStreaming;
}
。。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。。
if (needWake) {
mLooper->wake();
}
}
这里调用mLooper->wake(); 终于可以执行InputDispatcher的线程了,在这之前的所有动作都是在InputReader中执行的。下面可以看
mDispatcher->dispatchOnce();这个函数了在android\frameworks\base\services\input\InputDispatcher.cpp中
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
AutoMutex _l(mLock);
dispatchOnceInnerLocked(&nextWakeupTime); //事件处理----------------------------------
|
if (runCommandsLockedInterruptible()) { |
nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately |
} |
} // release lock |
|
// Wait for callback or timeout or wake. (make sure we round up, not down) |
nsecs_t currentTime = now(); |
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime); |
mLooper->pollOnce(timeoutMillis); | |
} V |
|
这里调用的mLooper->pollOnce(timeoutMillis); 在android\frameworks\base\libs\utils\Looper.cpp中 |
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) { |
int result = 0; |
for (;;) { |
while (mResponseIndex < mResponses.size()) { |
const Response& response = mResponses.itemAt(mResponseIndex++); |
ALooper_callbackFunc callback = response.request.callback; |
if (!callback) { |
int ident = response.request.ident; |
int fd = response.request.fd; |
int events = response.events; |
void* data = response.request.data; |
。。。。。 |
if (outFd != NULL) *outFd = fd; |
if (outEvents != NULL) *outEvents = events; |
if (outData != NULL) *outData = data; |
return ident; |
} |
} |
|
if (result != 0) { |
。。。。 |
if (outFd != NULL) *outFd = 0; |
if (outEvents != NULL) *outEvents = NULL; |
if (outData != NULL) *outData = NULL; |
return result; |
} |
|
result = pollInner(timeoutMillis);注意这里 这个函数会导致线程阻塞 一是超时 一是 epoll |
} | |
} | |
V |
|
int Looper::pollInner(int timeoutMillis) { |
|
。。。。。。。。。。。。。。。。。。。。。 |
int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime);//超时阻塞 |
。。。。。。。。。。。。。。。。 |
。。。。。。。。。。。 |
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);//epoll阻塞 |
。。。。。。。。。. |
。。。。。。。。 |
} |
|
|
|
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { <------------------------
nsecs_t currentTime = now();
。。。。。。。。。。。。。。
mInboundQueue.dequeue(entry);//从事件队列里面取出事件
mPendingEvent = entry;
}
// Poke user activity for this event.
if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
pokeUserActivityLocked(mPendingEvent);
}
}
// Now we have an event to dispatch.我们取得了 分发的事件
// All events are eventually dequeued and processed this way, even if we intend to drop them.
//所有从队列 里取出的事件都必须用这种方法处理,甚至这是一个要被丢弃的事件
。。。。。。。。。。。。。。。。。。。。。。。
switch (mPendingEvent->type) { //根据事件的类型分别分发下去
case EventEntry::TYPE_CONFIGURATION_CHANGED: {
。。。。。。。。。
case EventEntry::TYPE_DEVICE_RESET: {
。。。。。。。。。。
case EventEntry::TYPE_KEY: {
。。。。。。。。
case EventEntry::TYPE_MOTION: {
MotionEntry* typedEntry = static_cast(mPendingEvent);
if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
dropReason = DROP_REASON_APP_SWITCH;
}
if (dropReason == DROP_REASON_NOT_DROPPED
&& isStaleEventLocked(currentTime, typedEntry)) {
dropReason = DROP_REASON_STALE;
}
if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DROP_REASON_BLOCKED;
}
done = dispatchMotionLocked(currentTime, typedEntry,
&dropReason, nextWakeupTime); //分发motion事件
break; |
} |
|
default: |
LOG_ASSERT(false); |
break; |
} |
。。。。。。。。。。。。。。。。。。。 |
} |
V
bool InputDispatcher::dispatchMotionLocked(
nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
。。。。。。。。。。。。。。。。。。。。。。。。
dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);分发事件
return true; |
} |
V
void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTime,
。。。。。。。。。。。。。。。。
prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget,
resumeWithAppendedMotionSample);
。。。。。。。。。。。。。。。。 |
} |
V
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
bool resumeWithAppendedMotionSample) {
。。。。。。。。。。。。。。。。。。。。。。。。。 //创建DispatchEntry对象并把它增加到
//Connection::outboundQueue队列中。
enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget,
resumeWithAppendedMotionSample);
} |
V
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
bool resumeWithAppendedMotionSample) {
。。。。。。。。。。。。。。。。。。。。。。。。
if (wasEmpty && !connection->outboundQueue.isEmpty()) {
activateConnectionLocked(connection.get());
//把当前Connection增加到InputDispatcher::mActiveConnections链表中
startDispatchCycleLocked(currentTime,connection);
//Connection::inputPublisher.publishMotionEvent来发布事件到ashmem buffer中,
//调用Connection::inputPublisher.sendDispatchSignal发送一个dispatch信号到InputConsumer通知它
//有了一个新的消息。
}
}