Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1490389
  • 博文数量: 267
  • 博客积分: 3010
  • 博客等级: 少校
  • 技术积分: 3089
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-05 17:09
个人简介

尊天命,尽人事

文章分类

全部博文(267)

文章存档

2017年(6)

2015年(4)

2014年(27)

2013年(52)

2012年(59)

2011年(120)

分类: 嵌入式

2012-02-02 19:38:08

Android输入设备处理流程
2011-05-18 17:29
Android输入设备处理流程
2010-11-19 14:50

Android系统硬件的访问是通过HAL(Hardware Abstract Layer)来进行的,HAL就起到来Hardware adapter的作用。对于输入设备,如KeyPad、TouchPanel等,Android用EventHub具体的对其进行了封装。

输入设备驱动程序对用户空间应用程序提供一些设备文件,这些设备文件放在/dev/input里面。

1. EventHub扫描/dev/input下所有设备文件,并打开它们。

  1. bool EventHub::openPlatformInput(void)
  2. {
  3. ...
  4. mFDCount = 1;
  5. mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));
  6. mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));
  7. mFDs[0].events = POLLIN;
  8. mDevices[0] = NULL;

  9. res = scan_dir(device_path);
  10. ...
  11. return true;
  12. }

  13. int EventHub::scan_dir(const char *dirname)
  14. {
  15. char devname[PATH_MAX];
  16. char *filename;
  17. DIR *dir;
  18. struct dirent *de;
  19. dir = opendir(dirname);
  20. if(dir == NULL)
  21. return -1;
  22. strcpy(devname, dirname);
  23. filename = devname + strlen(devname);
  24. *filename++ = '/';
  25. while((de = readdir(dir)))
  26. {
  27. if(de->d_name[0] == '.' &&
  28. (de->d_name[1] == '\0' ||
  29. (de->d_name[1] == '.' && de->d_name[2] == '\0')))
  30. continue;
  31. strcpy(filename, de->d_name);
  32. open_device(devname);
  33. }
  34. closedir(dir);
  35. return 0;
  36. }

  37. open_device(devname)
  38. {
  39. open(...)
  40.     ioctl(...)
  41. }
  42. EventHub对外提供了一个函数用于从输入设备文件中读取数据。

  43. bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
  44. int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
  45. int32_t* outValue, nsecs_t* outWhen)
  46. {
  47. ...
  48. while(1)
  49. {

  50. // First, report any devices that had last been added/removed.
  51. if (mClosingDevices != NULL)
  52. {
  53. device_t* device = mClosingDevices;
  54. LOGV("Reporting device closed: id=0x%x, name=%s\n",
  55. device->id, device->path.string());
  56. mClosingDevices = device->next;
  57. *outDeviceId = device->id;
  58. if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
  59. *outType = DEVICE_REMOVED;
  60. delete device;
  61. return true;
  62. }

  63. if (mOpeningDevices != NULL)
  64. {
  65. device_t* device = mOpeningDevices;
  66. LOGV("Reporting device opened: id=0x%x, name=%s\n",
  67. device->id, device->path.string());
  68. mOpeningDevices = device->next;
  69. *outDeviceId = device->id;
  70. if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
  71. *outType = DEVICE_ADDED;
  72. return true;
  73. }

  74. release_wake_lock(WAKE_LOCK_ID);

  75. pollres = poll(mFDs, mFDCount, -1);

  76. acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);

  77. if (pollres <= 0)
  78. {
  79. if (errno != EINTR)
  80. {
  81. LOGW("select failed (errno=%d)\n", errno);
  82. usleep(100000);
  83. }
  84. continue;
  85. }

  86. for(i = 1; i < mFDCount; i++)
  87. {
  88. if(mFDs[i].revents)
  89. {
  90. LOGV("revents for %d = 0x%08x", i, mFDs[i].revents);
  91. if(mFDs[i].revents & POLLIN)
  92. {
  93. res = read(mFDs[i].fd, &iev, sizeof(iev));
  94. if (res == sizeof(iev))
  95. {
  96. LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d",
  97. mDevices[i]->path.string(),
  98. (int) iev.time.tv_sec, (int) iev.time.tv_usec,
  99. iev.type, iev.code, iev.value);
  100. *outDeviceId = mDevices[i]->id;
  101. if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
  102. *outType = iev.type;
  103. *outScancode = iev.code;
  104. if (iev.type == EV_KEY)
  105. {
  106. err = mDevices[i]->layoutMap->map(iev.code, outKeycode, outFlags);
  107. LOGV("iev.code=%d outKeycode=%d outFlags=0x%08x err=%d\n",
  108. iev.code, *outKeycode, *outFlags, err);
  109. if (err != 0)
  110. {
  111. *outKeycode = 0;
  112. *outFlags = 0;
  113. }
  114. }
  115. else
  116. {
  117. *outKeycode = iev.code;
  118. }
  119. *outValue = iev.value;
  120. *outWhen = s2ns(iev.time.tv_sec) + us2ns(iev.time.tv_usec);
  121. return true;
  122. }
  123. else
  124. {
  125. if (res<0)
  126. {
  127. LOGW("could not get event (errno=%d)", errno);
  128. }
  129. else
  130. {
  131. LOGE("could not get event (wrong size: %d)", res);
  132. }
  133. continue;
  134. }
  135. }
  136. }
  137. }
  138. ...
  139. }

对于按键事件,调用mDevices[i]->layoutMap->map进行映射。映射实际是由 KeyLayoutMap::map完成的,KeyLayoutMap类里读取配置文件qwerty.kl,由配置文件qwerty.kl决定键值的映射 关系。你可以通过修改./development/emulator/keymaps/qwerty.kl来改变键值的映射关系。

2. JNI函数

在frameworks/base/services/jni/com_android_server_KeyInputQueue.cpp文件 中,向JAVA提供了函数android_server_KeyInputQueue_readEvent,用于读取输入设备事件。

  1. static jboolean
  2. android_server_KeyInputQueue_readEvent(JNIEnv* env,
  3. jobject clazz,
  4. jobject event)
  5. {
  6. gLock.lock();
  7. sp<EventHub> hub = gHub;
  8. if (hub == NULL)
  9. {
  10. hub = new EventHub;
  11. gHub = hub;
  12. }
  13. gLock.unlock();

  14. int32_t deviceId;
  15. int32_t type;
  16. int32_t scancode, keycode;
  17. uint32_t flags;
  18. int32_t value;
  19. nsecs_t when;
  20. bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,
  21. &flags, &value, &when);

  22. env->SetIntField(event, gInputOffsets.mDeviceId, (jint)deviceId);
  23. env->SetIntField(event, gInputOffsets.mType, (jint)type);
  24. env->SetIntField(event, gInputOffsets.mScancode, (jint)scancode);
  25. env->SetIntField(event, gInputOffsets.mKeycode, (jint)keycode);
  26. env->SetIntField(event, gInputOffsets.mFlags, (jint)flags);
  27. env->SetIntField(event, gInputOffsets.mValue, value);
  28. env->SetLongField(event, gInputOffsets.mWhen,
  29. (jlong)(nanoseconds_to_milliseconds(when)));

  30. return res;
  31. }
readEvent调用hub->getEvent读了取事件,然后转换成JAVA的结构。


3. 事件中转线程

在frameworks/base/services/java/com/android/server/KeyInputQueue.java里创建了一个线程,它循环的读取事件,然后把事件放入事件队列里。

  1. Thread mThread = new Thread("InputDeviceReader")
  2. {
  3. public void run()
  4. {
  5. android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
  6. try
  7. {
  8. RawInputEvent ev = new RawInputEvent();
  9. while (true)
  10. {
  11. InputDevice di;
  12. readEvent(ev);
  13. send = preprocessEvent(di, ev);
  14. addLocked(di, curTime, ev.flags, ..., me);
  15. }
  16. }
  17. }
  18. };
注:readEvent就是调用了JNI的android_server_KeyInputQueue_readEven函数

4. 输入事件分发线程

在frameworks/base/services/java/com/android/server/WindowManagerService.java里创建了一个输入事件分发线程,它负责把事件分发到相应的窗口上去。

在WindowManagerService构造函数中调用

  1. mInputThread = new InputDispatcherThread();
  2. mInputThread.start();

  3. InputDispatcherThread的实现代码如下:

  4. private final class InputDispatcherThread extends Thread
  5. {
  6. // Time to wait when there is nothing to do: 9999 seconds.
  7. static final int LONG_WAIT=9999*1000;
  8. public InputDispatcherThread()
  9. {
  10. super("InputDispatcher");
  11. }

  12. @Override
  13. public void run()
  14. {
  15. while (true) process();
  16. }

  17. private void process()
  18. {
  19. android.os.Process.setThreadPriority(
  20. android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
  21. ... ...
  22. while (true)
  23. {
  24. long curTime = SystemClock.uptimeMillis();
  25. // Retrieve next event, waiting only as long as the next
  26. // repeat timeout. If the configuration has changed, then
  27. // don't wait at all -- we'll report the change as soon as
  28. // we have processed all events.
  29. QueuedEvent ev = mQueue.getEvent(
  30. (int)((!configChanged && curTime < nextKeyTime)
  31. ? (nextKeyTime-curTime) : 0));
  32. ... ...
  33. try
  34. {
  35. if (ev != null)
  36. {
  37. switch (ev.classType)
  38. {
  39. case RawInputEvent.CLASS_KEYBOARD:
  40. ...
  41. dispatchKey((KeyEvent)ev.event, 0, 0);
  42. mQueue.recycleEvent(ev);
  43. break;
  44. case RawInputEvent.CLASS_TOUCHSCREEN:
  45. //Slog.i(TAG, "Read next event " + ev);
  46. dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);
  47. break;
  48. case RawInputEvent.CLASS_TRACKBALL:
  49. dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0);
  50. break;
  51. case RawInputEvent.CLASS_CONFIGURATION_CHANGED:
  52. configChanged = true;
  53. break;
  54. default:
  55. mQueue.recycleEvent(ev);
  56. break;
  57. }

  58. } else if (configChanged)
  59. {
  60. configChanged = false;
  61. sendNewConfiguration();

  62. }
  63. else if (lastKey != null)
  64. {
  65. curTime = SystemClock.uptimeMillis();
  66. ... ...
  67. dispatchKey(newEvent, 0, 0);

  68. }
  69. else
  70. {
  71. curTime = SystemClock.uptimeMillis();
  72. lastKeyTime = curTime;
  73. nextKeyTime = curTime + LONG_WAIT;
  74. }
  75. }
  76. catch (Exception e)
  77. {
  78. ... ...
  79. }
  80. }
  81. }
  82. }

阅读(3124) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~