国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android編程輸入事件流程詳解

2019-12-12 04:56:57
字體:
來源:轉載
供稿:網友

本文實例講述了Android編程輸入事件流程。分享給大家供大家參考,具體如下:

EventHub對輸入設備進行了封裝。輸入設備驅動程序對用戶空間應用程序提供一些設備文件,這些設備文件放在/dev/input里面。

EventHub掃描/dev/input下所有設備文件,并打開它們。

bool EventHub::openPlatformInput(void){...  mFDCount = 1;  mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));  mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));  mFDs[0].events = POLLIN;  mDevices[0] = NULL;  res = scan_dir(device_path);...  return true;}

EventHub對外提供了一個函數用于從輸入設備文件中讀取數據。

bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,    int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,    int32_t* outValue, nsecs_t* outWhen)    {     ...      while(1) {    // First, report any devices that had last been added/removed.    if (mClosingDevices != NULL) {      device_t* device = mClosingDevices;      LOGV("Reporting device closed: id=0x%x, name=%s/n",         device->id, device->path.string());      mClosingDevices = device->next;      *outDeviceId = device->id;      if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;      *outType = DEVICE_REMOVED;      delete device;      return true;    }    if (mOpeningDevices != NULL) {      device_t* device = mOpeningDevices;      LOGV("Reporting device opened: id=0x%x, name=%s/n",         device->id, device->path.string());      mOpeningDevices = device->next;      *outDeviceId = device->id;      if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;      *outType = DEVICE_ADDED;      return true;    }    release_wake_lock(WAKE_LOCK_ID);    pollres = poll(mFDs, mFDCount, -1);    acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);    if (pollres <= 0) {      if (errno != EINTR) {        LOGW("select failed (errno=%d)/n", errno);        usleep(100000);      }      continue;    }    for(i = 1; i < mFDCount; i++) {      if(mFDs[i].revents) {        LOGV("revents for %d = 0x%08x", i, mFDs[i].revents);        if(mFDs[i].revents & POLLIN) {          res = read(mFDs[i].fd, &iev, sizeof(iev));          if (res == sizeof(iev)) {            LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d",               mDevices[i]->path.string(),               (int) iev.time.tv_sec, (int) iev.time.tv_usec,               iev.type, iev.code, iev.value);            *outDeviceId = mDevices[i]->id;            if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;            *outType = iev.type;            *outScancode = iev.code;            if (iev.type == EV_KEY) {              err = mDevices[i]->layoutMap->map(iev.code, outKeycode, outFlags);              LOGV("iev.code=%d outKeycode=%d outFlags=0x%08x err=%d/n",                iev.code, *outKeycode, *outFlags, err);              if (err != 0) {                *outKeycode = 0;                *outFlags = 0;              }            } else {              *outKeycode = iev.code;            }            *outValue = iev.value;            *outWhen = s2ns(iev.time.tv_sec) + us2ns(iev.time.tv_usec);            return true;          } else {            if (res<0) {              LOGW("could not get event (errno=%d)", errno);            } else {              LOGE("could not get event (wrong size: %d)", res);            }            continue;          }        }      }    } ...}

對于按鍵事件,調用mDevices[i]->layoutMap->map進行映射。映射實際是由 KeyLayoutMap::map完成的,KeyLayoutMap類里讀取配置文件qwerty.kl,由配置文件qwerty.kl決定鍵值的映射關系。你可以通過修改./development/emulator/keymaps/qwerty.kl來改變鍵值的映射關系。

JNI函數

在frameworks/base/services/jni/com_android_server_KeyInputQueue.cpp文件中,向JAVA提供了函數android_server_KeyInputQueue_readEvent,用于讀取輸入設備事件。

static jbooleanandroid_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz, jobject event){  gLock.lock();  sp hub = gHub;  if (hub == NULL) {    hub = new EventHub;    gHub = hub;  }  gLock.unlock();  int32_t deviceId;  int32_t type;  int32_t scancode, keycode;  uint32_t flags;  int32_t value;  nsecs_t when;  bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode, &flags, &value, &when);  env->SetIntField(event, gInputOffsets.mDeviceId, (jint)deviceId);  env->SetIntField(event, gInputOffsets.mType, (jint)type);  env->SetIntField(event, gInputOffsets.mScancode, (jint)scancode);  env->SetIntField(event, gInputOffsets.mKeycode, (jint)keycode);  env->SetIntField(event, gInputOffsets.mFlags, (jint)flags);  env->SetIntField(event, gInputOffsets.mValue, value);  env->SetLongField(event, gInputOffsets.mWhen, (jlong)(nanoseconds_to_milliseconds(when)));  return res;}

readEvent調用hub->getEvent讀了取事件,然后轉換成JAVA的結構。

事件中轉線程

在frameworks/base/services/java/com/android/server/KeyInputQueue.java里創建了一個線程,它循環的讀取事件,然后把事件放入事件隊列里。

Thread mThread = new Thread("InputDeviceReader") {  public void run() {      android.os.Process.setThreadPriority(          android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);        try {        RawInputEvent ev = new RawInputEvent();        while (true) {          InputDevice di;        readEvent(ev);        send = preprocessEvent(di, ev);          addLocked(di, curTime, ev.flags, ..., me);        }    }  };}

輸入事件分發線程

在frameworks/base/services/java/com/android/server/WindowManagerService.java里創建了一個輸入事件分發線程,它負責把事件分發到相應的窗口上去。

mQueue.getEventdispatchKey/dispatchPointer/dispatchTrackball

更多關于Android相關內容感興趣的讀者可查看本站專題:《Android開發入門與進階教程》、《Android調試技巧與常見問題解決方法匯總》、《Android多媒體操作技巧匯總(音頻,視頻,錄音等)》、《Android基本組件用法總結》、《Android視圖View技巧總結》、《Android布局layout技巧總結》及《Android控件用法總結

希望本文所述對大家Android程序設計有所幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 吉水县| 赤水市| 那坡县| 团风县| 株洲县| 朝阳市| 河南省| 深圳市| 温州市| 修文县| 工布江达县| 沈丘县| 长海县| 科技| 邛崃市| 竹溪县| 那坡县| 南昌市| 彰化市| 青铜峡市| 广饶县| 怀安县| 威远县| 嘉荫县| 克山县| 卢氏县| 临猗县| 琼中| 宁化县| 明星| 兴化市| 德阳市| 成安县| 孟村| 龙游县| 长阳| 耒阳市| 潮安县| 利辛县| 通许县| 高州市|