zoukankan      html  css  js  c++  java
  • 10.5 android输入系统_Reader线程_使用EventHub读取事件和核心类及配置文件_实验_分析

    4. Reader线程_使用EventHub读取事件

    使用inotify监测/dev/input下文件的创建和删除

    使用epoll监测有无数据上报

    细节:

    a、fd1 = inotify_init("/dev/input")

    b、假设input下已经有了event0和event1

      fd2 = open("/dev/input/event0")

      fd3= open("/dev/input/event1")

    c、使用epoll_wait监测fd1、fd2、fd3

    d、如果epoll_wait返回的数据中有fd1,表示有设备节点创建或者删除了,如果是创建,getEvent就会创建一个EawEvent结构体来表示创建事件,如果是fd2或者fd2,getEvent会去读取驱动上报的input_event事件,并用其构造EawEvent返回

    Reader线程:获取事件、简单处理、传给Dispatcher线程

    threadLoop//InputReader.cpp中

      mReader->loopOnce()

        count = mEventHub->getEvent();//获得事件

    获得事件分析:

    应用程序获得的输入事件的数据

    struct EawEvent{nsecs_t when;

            int32_t deviceID;

            int32_t type;//插入/拔出/按键类/相对位移类/绝对位移类等

            int32_t code;

            int32_t value;        

    }

    驱动程序上报的输入事件的数据

    struct input_event{

      struct timeval;

      __u16 type;

      __u16 code;

      __s32 value;

    }

    因此应用程序对驱动输出的数据做了扩展

    (mEventHub对应在构造的时候会创建epoll和inotify来监测)

    count = mEventHub->getEvent(int timeoutMillis,EawEvent* buffer,size_tbufferSIze)//inputReader.cpp中

      scanDevicesLocked()//扫描目录

        scanDirLocked(DEVICE_PATH)//扫描“/dev/input”

          openDeviceLocked(devname)

            loadConfigurationLocked(device)

            loadKeyMapLocked(device)

              device->keyMap.load

            addDeviceLocked(device)

        CreateVirtualKeyboardLocked

      event->type = DEVICE_REMOVED;

      event->type = DEVICE_ADDED;

      eventltem = mPendingEventltems[mPendingEventIndex++]

      deviceIndex = mDevices.indexOfKey(eventItem.data.u32)

      Device* device = mDevice.valueAt(deviceIndex)

      read(device->fd,readBuffer.....)

      set theRawEvent form input_event

      epoll_wait(mEpollFd,mPendingEventItems,....)

    5. Reader线程_核心类及配置文件_实验

    Reader线程核心类:

    mEventHub对象

      mDevices对象里存放的是各个输入设备,存放的是KeyedVector<编号,Device*>

        Device结构信息:设备fd(open(/dev/input/event)返回)和信息(name/bus/VID/PID,根据这些信息会打开3个配置文件(IDC:input device config/keylayout:键盘布局/KCM:key character map))、映射信息

    android输入系统中应用层按键1用AKEYCODE_1 = 8来表示,而在linux内核中按键1用KEY_1=2来表示,因此两者直接存在一个转换,利用keylayout即kl文件来实现,利用那个kl文件是根据PID、VID、DEVICE_NAME等信息来查找某个适合的XXXX.kl文件

    实验:

    kl文件格式:
    key    17                                 W
             内核中的code值           android中的值AKEYCODE_W

    创建:
    su
    mkdir -p /data/system/devices/keylayout/

    根据DEVICE_NAME设备名字查找kl文件,利用的是前面写的那个应用程序,在程序设设置了name=InputEmulatorFrom100ask.net,其中的.号会被改为_
    cp /system/usr/keylayout/Generic.kl /data/system/devices/keylayout/InputEmulatorFrom100ask_net.kl 
    修改 /data/system/devices/keylayout/InputEmulatorFrom100ask_net.kl
    添加这2行:
    key 227 STAR      STAR在android表示*
    key 228 POUND  POUND 在android表示#

    修改权限:
    busybox chmod 777 /data/system/devices -R

    重启

    su
    busybox mount -t nfs -o nolock,vers=2 192.168.1.123:/work/nfs_root /data/mnt(挂载到/mnt下会导致系统很卡)

    insmod InputEmulator.ko

    发送*键
    sendevent /dev/input/event5 1 227 1
    sendevent /dev/input/event5 1 227 0
    sendevent /dev/input/event5 0 0 0

    发送#键
    sendevent /dev/input/event5 1 228 1
    sendevent /dev/input/event5 1 228 0
    sendevent /dev/input/event5 0 0 0

    scancode ===> android keycode 只是表示按下了某个键,比如linux227对应android应用下的STAR,而决定STAR表示的是“*”字符,是由KCM:key character map决定的,这个kcm文件是根据PID、VID、DEVICE_NAME等信息来查找某个适合的XXXX.kcm文件
    kcm文件格式:
    key B {
    label: 'B' # 印在按键上的文字
    base: 'b' # 如果没有其他按键(shift, ctrl等)同时按下,此按键对应的字符是'b'
    shift, capslock: 'B'
    }

    B 表示 AKEYCODE_B

    实验:
    mkdir -p /data/system/devices/keychars
    cp /system/usr/keychars/Generic.kcm /data/system/devices/keychars/InputEmulatorFrom100ask_net.kcm
    修改:
    key STAR {
    label: '*'
    # base: '*'
    base: '1'
    }

    key POUND {
    label: '#'
    # base: '#'
    base: '2'
    }

    busybox chmod 777 /data/system/devices -R

    重启

    insmod InputEmulator.ko

    发送*键, 得到1
    sendevent /dev/input/event5 1 227 1
    sendevent /dev/input/event5 1 227 0
    sendevent /dev/input/event5 0 0 0

    发送#键, 得到2
    sendevent /dev/input/event5 1 228 1
    sendevent /dev/input/event5 1 228 0
    sendevent /dev/input/event5 0 0 0

    keylayout: 只是用来表示驱动上报的scancode对应哪一个android按键(AKEYCODE_x)
         只是表示按键被按下
         它对应哪一个字符,由kcm文件决定
    kcm: 用来表示android按键(AKEYCODE_x)对应哪一个字符
       表示同时按下其他按键后,对应哪个字符


    也可以用组合键
    sendevent /dev/input/event5 1 42 1     (shift+KEY_8)
    sendevent /dev/input/event5 1 9 1
    sendevent /dev/input/event5 1 9 0
    sendevent /dev/input/event5 1 42 0
    sendevent /dev/input/event5 0 0 0

    sendevent /dev/input/event5 1 42 1      (shift+KEY_3)
    sendevent /dev/input/event5 1 4 1
    sendevent /dev/input/event5 1 4 0
    sendevent /dev/input/event5 1 42 0
    sendevent /dev/input/event5 0 0 0

    6. Reader线程_核心类及配置文件_分析

    当EventHub检测到/dev/input下面有设备节点被创建时,其就会去打开这个设备节点,创建Device结构并把其加载到EventHub结构体的mDevices上

    EventHub结构体成员:

    {

    mNextDeviceld:int32_t

    mDevices:KeyedVector<int32_t,Device*>

    mOpeningDevice:Device*

    mClosingDevice:Device*

    }

    EventHub.cpp里面的OpenDeviceLocked函数:

    (1)open

    (2)ioctl得到信息:名字、VID、PID等

    (3)new Device()

    (4)加载idc文件

    (5)加载kl和kcm文件

    Device结构体成员:

    {

    fd:int  //=open("/dev/input/event*")

    identifier:const InputDeviceIdentifier//属性:名字、总线、PID、VID等

    keyBitmask[]:uint8_t

    configurationFile:String8   //IDC文件名(XXX.idc)

    configuration:PropertyMap*   //idc属性,从idc文件中得到的值

    keyMap:KeyMap //保存有keylayout和KCM文件信息

    }

    KeyMap结构体:

    {

    keyLayoutFile:String8   //XXX.kl文件名

    keyLayoutMap:sp<KeyLayoutMap>   //XXX.kl文件内容

    keyCharacterMapFile:String8  //XXX.kl文件名

    keyCharacterMap;sp<KeyCharacterMap>  //XXX.kl文件内容

    }

    KeyLayoutMap结构体:

    {

    mKeysByScanCode:KeyedVector<int32_t,Key> //int32_t是内核上报的scancode,Key是结构体{KeyCode(android里面对应的值);flags}eg:<1,KEY{AKEYCODE_ESCAPE,flag}>/<2,KEY{AKEYCODE_1,flag}>等,flag主要用于虚拟按键,比如在键盘上滑动是忽略上报事件

    mKeysByUsageCode:KeyedVector<int32_t,Key>

    }

    KeyCharacterMap结构体:

    {

    mKeys:KeyedVector<int32_t,Key*>//

    //int32_t是android下对应的值,Key是结构体{label(标签,没啥作用);number;firstBehavior()},firstBehavior是Behavior结构体指针,对于KCM中每一项里面的base、shift、capslock(除了label外都会构造)都会构造一个Behavior结构体

    {metaState(按下的其他键);character(android下的值对于的字符);fallbackKeyCode};eg:base的Behavior{0,‘a’,null},shift的Behavior{shift,“A”,null},capslock的Behavior{capslock,“A”,null}

    mKeysByScanCode:KeyedVector<int32_t,int32_t>//功能同KeyLayoutMap里的mKeysByScanCode:KeyedVector,没有flag,不能处理虚拟按键,很少使用这一项

    mKeysByUsageCode:KeyedVector<int32_t,int32_t>

    }

    说明:对于kcm文件里面的每一项,里面的如果值是eg:ctrl  fallback SEARCH,则对于其Behavior的fallbackKeyCode = AKEYCODE_SEARCH,fallbackKeyCode 的作用是当上报ctrl+按键character后如不不能处理,再次上报一个值fallbackKeyCode 

    7. Reader线程_简单处理

    根据获得的EawEvent的type进行处理

    (1)Add Device

    (2)Remove Device

    (3)真正的输入事件

    processEventLocked(mEventBuffer,count)

      addDeviceLocked(rawEvent->when,rawEvent->deviceld)

        InputDevice *device = createDeviceLocked(deviceld,...)

          lnputDevice* device = new InputDevice(&mContext,...)

          device->addMapper(new KeyboardInputMapper(device,keyboardSource,keyboardType))

        mDevices.add(deviceId,device)//发现新的输入设备的时候,device不仅添加到EventHub的mDevices中,也会添加到InputReader结构体的mDevices中,在InputReader的mDevices中记录的是Input_Device结构体,数据成员有mID(通过这个mID可以从EventHub里的mDevices找到对应的Device)、mMappers(对上报的事件用其来处理)

      removeDeviceLocked(rawEvent->when,rawEvent->deviceld)

      processEventsForDeviceLocked(deviceId,rawEvent,batchSize)

        device->process(rawEvents,count)//device就是在addDevice时构造的Input_Device

          InputMapper* mapper = mMappers[i]//找到对应事件的mapper,代用它process来处理数据

          mapper->process(rawEvent)

            getEventHub()->mapKey(getDeviceId(),scanCode,...)//把驱动上报的linux内核层code转换为android下对应的code

            processKey

              NotifyKeyArgs args(......)//使用多个数据来构造args,接着上报args数据

              getListener()->notifyKey(&args)//通知一个listener来处理args,这里的listener肯定是dispatcher线程

                mArgsQueue.push(.....)

    说明:InputReader中的mDevices下的input_device结构体用来处理数据

         EventHub中的mDevices下的device结构体用来读取事件获得数据

    总结:

    NativeInputManager结构体

      InputReader mReader

      mReaderThread//线程,仅提供循环,具体的工作由mReader负责

      InputDispatcher mDispatcher

      mDispatcherThread//线程,仅提供循环,具体的工作由mDispatcher负责

    InputReader结构体

      EventHub mEventHub//管理多个输入设备,设备保存在mDevice中

      mPolicy

      InputDevice mDevices//里面也保存设备,其和EventHub中的mDevice不同之处是其提供mMapper输入数据处理函数

  • 相关阅读:
    【poj2828】Buy Tickets
    【hdu2795】Billboard
    【hdu1394】Minimum Inversion Number
    【BZOJ1012】 【JSOI2008】最大数maxnumber
    【hdu】p1754I Hate It
    【线段树模板】
    Day1
    synchronized底层原理
    Java之浅拷贝和深拷贝
    图解算法——恢复一棵二叉搜索树(BST)
  • 原文地址:https://www.cnblogs.com/liusiluandzhangkun/p/9163968.html
Copyright © 2011-2022 走看看