Android输入之EvemtHub

       EventHub中主要被调用的是getEvent:

bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
        int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
        int32_t* outValue, nsecs_t* outWhen)
{
....

    if (!mOpened) {
        mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
        mOpened = true;
    }
.....

}

在该函数中首先判断/dev/input下的文件是否扫描打开过,如果没有进入openPlatformInput():

/*
 * Open the platform-specific input device.
 */
bool EventHub::openPlatformInput(void)
{
    /*
     * Open platform-specific input device(s).
     */
    int res;

    mFDCount = 1;
    mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));
    mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));
    mFDs[0].events = POLLIN;
    mDevices[0] = NULL;
#ifdef HAVE_INOTIFY
    mFDs[0].fd = inotify_init();
    res = inotify_add_watch(mFDs[0].fd, device_path, IN_DELETE | IN_CREATE);
    if(res < 0) {
        LOGE("could not add watch for %s, %s/n", device_path, strerror(errno));
    }
#else
    /*
     * The code in EventHub::getEvent assumes that mFDs[0] is an inotify fd.
     * We allocate space for it and set it to something invalid.
     */
    mFDs[0].fd = -1;
#endif

    res = scan_dir(device_path);
    if(res < 0) {
        LOGE("scan dir failed for %s/n", device_path);
        //open_device("/dev/input/event0");
    }

    return true;
}
mFDCount 用来存储要poll的文件个数,使用 inotify机制来检测该目录,这样在该目录临时加入的文件也能及时打开,特别实用于以模块方式加载的驱动。然后就会扫描整个目录并打开文件。

int EventHub::scan_dir(const char *dirname)                                                                   
{                                                                                                             
    char devname[PATH_MAX];                                                                                   
    char *filename;                                                                                           
    DIR *dir;                                                                                                 
    struct dirent *de;                                                                                        
    dir = opendir(dirname);                                                                                   
    if(dir == NULL)                                                                                           
        return -1;                                                                                            
    strcpy(devname, dirname);                                                                                 
    filename = devname + strlen(devname);                                                                     
    *filename++ = '/';                                                                                        
    while((de = readdir(dir))) {                                                                              
        if(de->d_name[0] == '.' &&                                                                            
           (de->d_name[1] == '/0' ||                                                                          
            (de->d_name[1] == '.' && de->d_name[2] == '/0')))                                                 
            continue;                                                                                         
        strcpy(filename, de->d_name);                                                                         
        open_device(devname);                                                                                 
    }                                                                                                         
    closedir(dir);                                                                                            
    return 0;                                                                                                 
}                                                                                                             
在扫描以后就调用 open_device打开文件:

int EventHub::open_device(const char *deviceName)
{
....

 fd = open(deviceName, O_RDWR);//打开文件

...

 if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) {
        //LOGI("MAP/n");
        //for (int i=0; i<((KEY_MAX+7)/8); i++) {
        //    LOGI("%d: 0x%02x/n", i, key_bitmask[i]);
        //}
        for (int i=0; i<((BTN_MISC+7)/8); i++) {
            if (key_bitmask[i] != 0) {
                device->classes |= CLASS_KEYBOARD;
                break;
            }
        }
        if ((device->classes & CLASS_KEYBOARD) != 0) {
            device->keyBitmask = new uint8_t[sizeof(key_bitmask)];
            if (device->keyBitmask != NULL) {
                memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
            } else {
                delete device;
                LOGE("out of memory allocating key bitmask");
                return -1;
            }
        }
    }
判断改设备是不是键盘,如果是设置device属性;

以同样的方式判断是否是轨迹球,多点触摸,单点触摸,并设置属性;

 if ((device->classes&CLASS_KEYBOARD) != 0) {

如果是键盘要做如下处理:

/ find the .kl file we need for this device
        const char* root = getenv("ANDROID_ROOT");
        snprintf(keylayoutFilename, sizeof(keylayoutFilename),
                 "%s/usr/keylayout/%s.kl", root, tmpfn);
        bool defaultKeymap = false;
        if (access(keylayoutFilename, R_OK)) {
            snprintf(keylayoutFilename, sizeof(keylayoutFilename),
                     "%s/usr/keylayout/%s", root, "qwerty.kl");
            defaultKeymap = true;
        }
        device->layoutMap->load(keylayoutFilename);
加载要使用的映射文件,这里默认使用的是qwerty.kl,这里是可以更改的,很多公司都会更改以使用自家的映射。

这样所有的文件都打开了,也设置了属性,我们再回到getEvent接着向下分析:

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

查看是否完全打开,如果没有完全打开就返回;

pollres = poll(mFDs, mFDCount, -1);对打开的所有文件进行poll,

// mFDs[0] is used for inotify, so process regular events starting at mFDs[1]
        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);
如果可读,就判断是否是按键类型,如果是就调用映射文件,改变code,如果不是就直接上报该值。

 // read_notify() will modify mFDs and mFDCount, so this must be done after
        // processing all other events.
        if(mFDs[0].revents & POLLIN) {
            read_notify(mFDs[0].fd);
        }
    }
}
这个用来时时监测notify机制。这样数据就完全读出来了。其他的方法等用到时再仔细看吧。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值