欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android編程輸入事件流程詳解

 更新時(shí)間:2016年10月26日 10:11:39   作者:Wallace  
這篇文章主要介紹了Android編程輸入事件流程,較為詳細(xì)的分析了Android輸入事件原理、相關(guān)概念與具體操作流程,需要的朋友可以參考下

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

EventHub對(duì)輸入設(shè)備進(jìn)行了封裝。輸入設(shè)備驅(qū)動(dòng)程序?qū)τ脩艨臻g應(yīng)用程序提供一些設(shè)備文件,這些設(shè)備文件放在/dev/input里面。

EventHub掃描/dev/input下所有設(shè)備文件,并打開(kāi)它們。

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對(duì)外提供了一個(gè)函數(shù)用于從輸入設(shè)備文件中讀取數(shù)據(jù)。

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;
          }
        }
      }
    }
 ...
}

對(duì)于按鍵事件,調(diào)用mDevices[i]->layoutMap->map進(jìn)行映射。映射實(shí)際是由 KeyLayoutMap::map完成的,KeyLayoutMap類里讀取配置文件qwerty.kl,由配置文件qwerty.kl決定鍵值的映射關(guān)系。你可以通過(guò)修改./development/emulator/keymaps/qwerty.kl來(lái)改變鍵值的映射關(guān)系。

JNI函數(shù)

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

static jboolean
android_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調(diào)用hub->getEvent讀了取事件,然后轉(zhuǎn)換成JAVA的結(jié)構(gòu)。

事件中轉(zhuǎn)線程

在frameworks/base/services/java/com/android/server/KeyInputQueue.java里創(chuàng)建了一個(gè)線程,它循環(huán)的讀取事件,然后把事件放入事件隊(duì)列里。

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);
        }
    }
  };
}

輸入事件分發(fā)線程

在frameworks/base/services/java/com/android/server/WindowManagerService.java里創(chuàng)建了一個(gè)輸入事件分發(fā)線程,它負(fù)責(zé)把事件分發(fā)到相應(yīng)的窗口上去。

mQueue.getEvent
dispatchKey/dispatchPointer/dispatchTrackball

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

希望本文所述對(duì)大家Android程序設(shè)計(jì)有所幫助。

相關(guān)文章

  • Android SurfaceView預(yù)覽變形完美解決方法

    Android SurfaceView預(yù)覽變形完美解決方法

    本篇文章主要介紹了Android SurfaceView預(yù)覽變形完美解決方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-04-04
  • Android 調(diào)用發(fā)送短信的方法

    Android 調(diào)用發(fā)送短信的方法

    這篇文章主要介紹了Android 調(diào)用發(fā)送短信的方法的相關(guān)資料,主要實(shí)現(xiàn)Android 調(diào)用短信的使用,希望通過(guò)本文能幫助到大家,需要的朋友可以參考下
    2017-09-09
  • Android集成百度地圖開(kāi)發(fā)流程和注意事項(xiàng)

    Android集成百度地圖開(kāi)發(fā)流程和注意事項(xiàng)

    現(xiàn)在很多項(xiàng)目都需要集成百度地圖,所以就把自己做過(guò)一個(gè)項(xiàng)目的經(jīng)驗(yàn)寫(xiě)出來(lái)和大家分享,方便自己和大家使用的時(shí)候參考借鑒,下面就來(lái)一起看看Android集成百度地圖開(kāi)發(fā)流程和注意事項(xiàng)吧。
    2016-09-09
  • Flutter實(shí)現(xiàn)切換應(yīng)用時(shí)隱藏應(yīng)用預(yù)覽

    Flutter實(shí)現(xiàn)切換應(yīng)用時(shí)隱藏應(yīng)用預(yù)覽

    如果您要顯示敏感數(shù)據(jù),例如錢包金額,或者只是當(dāng)?shù)卿洷韱物@示插入的密碼清晰時(shí),當(dāng)您不在應(yīng)用程序中時(shí),您必須隱藏敏感數(shù)據(jù)。本文將利用Flutter實(shí)現(xiàn)切換應(yīng)用時(shí)隱藏應(yīng)用預(yù)覽,需要的可以參考一下
    2022-06-06
  • Android自定義單例AlertDialog詳解

    Android自定義單例AlertDialog詳解

    這篇文章主要為大家詳細(xì)介紹了Android自定義單例AlertDialog的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • Android 實(shí)現(xiàn)控件懸浮效果實(shí)例代碼

    Android 實(shí)現(xiàn)控件懸浮效果實(shí)例代碼

    本篇文章主要介紹了Android 實(shí)現(xiàn)控件懸浮效果實(shí)例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-01-01
  • 一文詳解Jetpack?Android新一代導(dǎo)航管理Navigation

    一文詳解Jetpack?Android新一代導(dǎo)航管理Navigation

    這篇文章主要為大家介紹了Jetpack?Android新一代導(dǎo)航管理Navigation詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • 一文吃透Hilt自定義與跨壁壘

    一文吃透Hilt自定義與跨壁壘

    這篇文章主要介紹了Hilt自定義與跨壁壘的實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • 解析Android Jetpack簡(jiǎn)介

    解析Android Jetpack簡(jiǎn)介

    Jetpack是一套庫(kù)、工具和指南的集合,幫助開(kāi)發(fā)者更輕松地編寫(xiě)優(yōu)質(zhì)應(yīng)用,這篇文章主要介紹了Android Jetpack簡(jiǎn)介,需要的朋友可以參考下
    2022-09-09
  • Android仿京東、天貓商品詳情頁(yè)

    Android仿京東、天貓商品詳情頁(yè)

    這篇文章主要為大家詳細(xì)介紹了Android仿京東、天貓商品詳情頁(yè)的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-01-01

最新評(píng)論