Android遥控器事件集成及用户输入系统_第1页
Android遥控器事件集成及用户输入系统_第2页
Android遥控器事件集成及用户输入系统_第3页
Android遥控器事件集成及用户输入系统_第4页
Android遥控器事件集成及用户输入系统_第5页
已阅读5页,还剩3页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Android遥控器事件集成及用户输入系统分析一、用户输入系统结构Android中,用户输入系统的结构相对简单,主要的输入硬件设备是键盘、触摸屏、轨迹球等。在Android的上层中,可以通过获得这些设备产生的事件,并对设备的事件做出响应。在Java框架和应用程序层,通常使用运动事件获得触摸屏、轨迹球等设备的信息,用按键事件获得各种键盘的信息。Android用户输入系统的基本层次结构如图1所示。图1 Android用户输入系统的基本层次结构具体而言,Android用户输入系统自下而上包含了驱动程序、本地库处理部分、Java类对输入事件的处理、对Java程序的接口。Android用户输入系统的结构

2、如图2所示:图2 用户输入系统的结构如图2所示,自下而上,Android的用户输入系统分成几个部分:驱动程序:在/dev/input目录中,通常是Event类型的驱动程序;EventHub:本地框架层的EventHub是libui中的一部分,它实现了对驱动程序的控制,并从中获得信息;KeyLayout(按键布局)和KeyCharacterMap(按键字符映射)文件。同时,libui中有相应的代码对其操作。定义按键布局和按键字符映射需要运行时配置文件的支持,它们的后缀名分别为kl和kcm;Java框架层的处理:在Java框架层具有KeyInputDevice等类用于处理由EventHub传送上来

3、的信息,通常信息由数据结构RawInputEvent和KeyEvent来表示。通常情况下,对于按键事件,则直接使用KeyEvent来传送给应用程序层,对于触摸屏和轨迹球等事件,则由RawInputEvent经过转换后,形成MotionEvent时间传送给应用程序层;在Android的应用程序层中,通过重新实现onTouchEvent和onTrackballEvent等函数来接收运动事件(MotionEvent),通过重新实现onKeyDown和onKeyUp等函数来接收按键事件(KeyEvent)。这些类包含在android.view包中。二、Hi3716C中遥控器事件的传递流程Hi3716C

4、中输入事件的流程如图3所示:图3 Hi3716C中输入事件的基本流程图下面按照事件传递流程依次对遥控器按键事件传递各个环节进行讲述:1、 输入设备的打开EventHub类对输入设备进行了封装。输入设备驱动程序对用户空间应用程序提供一些设备文件,这些设备文件放在/dev/input里面。在系统启动后,android 会使用 EventHub.cpp中以下函数:static const char *device_path = "/dev/input"  bool EventHub:openPlatformInput(void)res = scan_

5、dir(device_path); 通过调用scan_dir()搜索/dev/input下所有Input驱动的设备节点,最终调用下面的函数打开搜索到的所有输入设备:int EventHub:open_device(const char *deviceName)      .     fd = open(deviceName, O_RDWR);     . &

6、#160;    mFDsmFDCount.fd = fd;     mFDsmFDCount.events = POLLIN;     .     ioctl(mFDsmFDCount.fd, EVIOCGNAME(sizeof(devname)-1),devname);     .  

7、   const char* root = getenv("ANDROID_ROOT");     snprintf(keylayoutFilename, sizeof(keylayoutFilename),                  "%s/usr/

8、keylayout/%s.kl", root, tmpfn);     .     device->layoutMap->load(keylayoutFilename);     .  打开设备的时候,如果 device->classes&CLASS_KEYBOARD 不等于 0 表明是键盘。 在此过程中,通过device->layoutMap->l

9、oad(keylayoutFilename),KeyLayoutMap类device->layoutMap会尝试载入并解析按键映射文件/system/usr/keylayout/ Hi3716_keypad.kl (若不存在则载入默认的/system/usr/keylayout/ qwerty.kl)。Hi3716_keypad.kl文件的片断如下所示:key 8 7key 9 8key 10 9key 11 0key 158 BACK WAKE_DROPPEDkey 230 SOFT_RIGHT WAKEkey 107 ENDCALL WAKE_DROPPEDkey 61 C

10、ALL WAKE_DROPPEDkey 232 DPAD_CENTER WAKE_DROPPEDkey 108 DPAD_DOWN WAKE_DROPPEDkey 103 DPAD_UP WAKE_DROPPEDkey 102 HOME WAKEkey 105 DPAD_LEFT WAKE_DROPPEDkey 106 DPAD_RIGHT WAKE_DROPPEDkey 115 VOLUME_UPkey 114 VOLUME_DOWNkey 16 Qkey 17 Wkey 18 Ekey 19 Rkey 20 T文件第1列为按键的整数扫描码(ScanCode),第2列为按键的字符串标签(Ke

11、ycodeLabel),第3列表示按键的Flag,带有WAKE字符,表示这个按键可以唤醒系统。在KeyLayoutMap:load()中解析kl 文件时,会首先使用第1列扫描码所对应的按键标签,在KeycodeLabels.h (froyoframeworksbaseincludeui)中的KeycodeLabel KEYCODES中查找同名字符串标签,并将找到的标签对应的键值(KeycodeLabels.value)存入Key. Keycode。同样地,kl文件第3列Flag字符串与KeycodeLabels.h中KeycodeLabel FLAGS的同名字符串所对应的整数值(Ke

12、ycodeLabels.value),也会被存入Key.flags。最终,把按键的映射关系保存在 KeyedVector<int32_t,Key> m_keys中,int32_t即为kl文件中的扫描码。需要指出的是,KeycodeLabel KEYCODES中的KeycodeLabels.value与android.view. KeyEvent.java中定义的键值是完全一致的,因此m_keys中的Key. Keycode值是可以被Android识别的。2、 驱动程序捕捉并上报按键事件目录patch_froyodevicehisihi3716cdriversdkmspandroid

13、_driver hi_keypad下Ir_keyboad.c和Ir_keyboad.h是Hi3716C遥控器的驱动程序。它是Hi3716C的设备1(/dev/input/event0)的驱动程序,设备名称为Hi3716_keypad。在IR_Keypad_Events_Probe()中此设备节点的中断响应函数被设置为IR_Keypad_IntIsr()。当遥控器按键按下时,更底层的中断响应代码会获取按键的遥控器编码(Ir_keyboad.h中ScanCode)并传递给IR_Keypad_IntIsr(),IR_Keypad_IntIsr将遥控器编码转换为扫描码,通过input_key上报按键事

14、件。如下所示:if(IR_KEY_DOWN = keyval) /*key down*/ input_event(edev->input, EV_KEY, KEY_DOWN, KPC_EV_KEY_PRESS); input_event(edev->input, EV_KEY, KEY_DOWN, KPC_EV_KEY_RELEASE); printk("+ key down pressn");3、 InputDeviceReader线程读取按键事件EventHub对外提供了一个函数用于从输入设备文件中读取数据:bool EventHub:getEvent(in

15、t32_t* outDeviceId, int32_t* outType, int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags, int32_t* outValue, nsecs_t* outWhen). while(1) . release_wake_lock(WAKE_LOCK_ID); pollres = poll(mFDs, mFDCount, -1); acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); for(i = 1; i < mFDCount; i

16、+) if(mFDsi.revents) if(mFDsi.revents & POLLIN) res = read(mFDsi.fd, &iev, sizeof(iev); if (res = sizeof(iev) if (iev.type = EV_KEY) err = mDevicesi->layoutMap->map(iev.code, outKeycode, outFlags); else *outKeycode = iev.code; return true; .函数使用阻塞函数poll()等侍驱动层事件的发生,然后通过read()读取Input设备的

17、数据,调用mDevicesi->layoutMap->map进行映射。KeyLayoutMap:map ()会使用KeyLayoutMap:load()所生成的KeyedVector<int32_t,Key> m_keys,将按键的扫描码转换为Android可以识别的键值。通过前面对KeyLayoutMap:load()的分析可知,KeyLayoutMap:map ()过程中,实际进行了2次按键信息转换:按键的扫描码首先被转换为了kl文件中相应的字符串标签KeycodeLabel,接着字符串标签又根据KeycodeLabels.h中的KeycodeLabel KEYCO

18、DES被转换为了与android.view. KeyEvent.java键值相一致的整数键值。frameworks/base/services/jni/com_android_server_KeyInputQueue.cpp中,向JAVA提供了jni函数android_server_KeyInputQueue_readEvent,用于读取输入设备事件:static jboolean android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz, jobject

19、60;event)     sp hub = gHub;     if (hub = NULL)          hub = new EventHub;         gHub = hub;

20、60;         .    bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,             &flags, &value,

21、 &when);     env->SetIntField(event, gInputOffsets.mDeviceId, (jint)deviceId);    env->SetIntField(event, gInputOffsets.mScancode, (jint)scancode); env->SetIntField(event, gInputOffsets.mKeycode, (jint)

22、keycode);     .    return res; readEvent调用hub->getEvent读了取事件,然后将扫描码和键码等转换成JAVA的结构。在frameworks/base/services/java/com/android/server/KeyInputQueue.java里创建了一个线程,它循环地读取事件,然后把事件放入事件队列里。在KeyInputQueue的构造函数中,这个线程被启动。Thread mThread = new Thread("Inp

23、utDeviceReader") 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); ;4、 按键事件分

24、发在frameworks/base/services/java/com/android/server/WindowManagerService.java里创建了一个输入事件分发线程,它负责把事件分发到相应的窗口上去。在WindowManagerService的构造函数中有:private WindowManagerService(Context context, PowerManagerService pm,boolean haveInputMethods) mQueue = new KeyQ();mInputThread = new InputDispatcherThread(); 

25、;          .         mInputThread.start(); KeyQ 是抽象类 KeyInputQueue 的实现,所以 new KeyQ类的时候实际上在 KeyInputQueue 类中创建了一个线程 InputDeviceReader 专门用来从设备读取按键事件。之后调用mInputThread.start()启动一个线程 InputDispatcherThread 。Inpu

26、tDispatcherThread 线程从 KeyQ 的事件队列中读取按键事件,在process() 方法中进行事件处理:QueuedEvent ev = mQueue.getEvent(int)(!configChanged && curTime < nextKeyTime) ? (nextKeyTime-curTime) : 0);switch (ev.classType)     case RawInputEvent.CLASS_KEYBOARD:       

27、60; .         dispatchKey(KeyEvent)ev.event, 0, 0);         mQueue.recycleEvent(ev);         break;     case RawInputEvent.CLASS_TOUCHSCREEN:      

28、60;  /Log.i(TAG, "Read next event " + ev);         dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);         break; case RawInputEvent.CLASS_TRACKBALL:        dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0);        break;在process() 方法中,首先从事件队列中读取发生的事件,并根据读取到事件类型的不同分成三类(KEYBOARD、TOU

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论