当前位置: 移动技术网 > IT编程>移动开发>Android > Android编程输入事件流程详解

Android编程输入事件流程详解

2019年07月24日  | 移动技术网IT编程  | 我要评论

3366小游戏打豆豆,cad 64位下载,玻璃釉电位器

本文实例讲述了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 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调用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.getevent
dispatchkey/dispatchpointer/dispatchtrackball

更多关于android相关内容感兴趣的读者可查看本站专题:《android开发入门与进阶教程》、《android调试技巧与常见问题解决方法汇总》、《android多媒体操作技巧汇总(音频,视频,录音等)》、《android基本组件用法总结》、《android视图view技巧总结》、《android布局layout技巧总结》及《android控件用法总结

希望本文所述对大家android程序设计有所帮助。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网