读书人

Android 模拟系统事件(2)

发布时间: 2013-09-06 10:17:17 作者: rapoo

Android 模拟系统事件(二)
简介

JNI(Java Native Interface)是本地编程接口,它允许Java代码和其他语言写的代码进行交互,它可以在 Java 虚拟机 (VM) 内部运行的 Java 代码与用其它编程语言(如 C、C++ 和汇编语言)编写的应用程序和库进行交互操作。

功能

通过jni实现向Android系统注入事件,从而实现模拟按键、模拟触屏等操作!用它直接跳过上面的Android平台权限的问题!

原理是在jni中通过Linux内核的ioctl函数和c语言函数(memset、write)来实现对设备的I/O通道进行管理的。所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等。它的调用个数如下:

int EVT_open(struct NATIVE_INFO *info){    struct input_absinfo absinfo;     if(initEVT)        return 0;     if(info == NULL)    {        LOGE("info null point.");        goto fail;    }     if(info->FB_width == 0 || info->FB_height == 0)    {        LOGE("error width %d and height %d.", info->FB_width, info->FB_height);        goto fail;    }     memset(&ei, 0, sizeof(ei));    ei.screen_width = info->FB_width;    ei.screen_height = info->FB_height;     scan_dir(DEV_DIR);     if(ioctl(ei.fd_touch, EVIOCGABS(ABS_X), &absinfo)) {        LOGI("Error reading absolute controller ABS_X[%d]: %s", errno, strerror(errno));        return;    }    ei.abs_x_min = absinfo.minimum;    ei.abs_x_max = absinfo.maximum;     if(ioctl(ei.fd_touch, EVIOCGABS(ABS_Y), &absinfo)) {        LOGI("Error reading absolute controller ABS_Y[%d]: %s", errno, strerror(errno));        return;    }    ei.abs_y_min = absinfo.minimum;    ei.abs_y_max = absinfo.maximum;     initEVT = 1;    return 0; fail:    EVT_close();    return -1;} int EVT_close(){    if(ei.fd_key > 0)        close(ei.fd_key);    if(ei.fd_touch > 0)        close(ei.fd_touch);     initEVT = 0;    return 0;} int EVT_touch(int action, float x, float y){    int abs_x, abs_y;     if(initEVT == 0)    {        LOGE("event not inital");        return -1;    }     switch(action)    {    case ACTION_DOWN:        calculateXY(x, y, &abs_x, &abs_y);        write_event(ei.fd_touch, 3, 0, abs_x);        write_event(ei.fd_touch, 3, 1, abs_y);        write_event(ei.fd_touch, 1, 330, 1);        write_event(ei.fd_touch, 0, 0, 0);        break;    case ACTION_UP:        write_event(ei.fd_touch, 1, 330, 0);        write_event(ei.fd_touch, 0, 0, 0);        break;    case ACTION_MOVE:        calculateXY(x, y, &abs_x, &abs_y);        write_event(ei.fd_touch, 3, 0, abs_x);        write_event(ei.fd_touch, 3, 1, abs_y);        write_event(ei.fd_touch, 0, 0, 0);        break;    }    return 0;} int EVT_key(int action, int key){    if(initEVT == 0)    {        LOGE("event not inital");        return -1;    }     switch(action)    {    case ACTION_DOWN:        write_event(ei.fd_key, 1, key, 1);        break;    case ACTION_UP:        write_event(ei.fd_key, 1, key, 0);        break;    }    return 0;}  int 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_dev(devname);    }    closedir(dir);    return 0;} int open_dev(const char *deviceName){    int fd;    int version;    uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];    uint8_t abs_bitmask[sizeof_bit_array(ABS_MAX + 1)];     fd = open(deviceName, O_RDWR);    if(fd < 0) {        LOGI("could not open device[%d]: %s", errno, strerror(errno));        return -1;    }     if(ioctl(fd, EVIOCGVERSION, &version)) {        return -1;    }     memset(key_bitmask, 0, sizeof(key_bitmask));    if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) {        if (containsNonZeroByte(key_bitmask, 0, sizeof_bit_array(BTN_MISC))                || containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_GAMEPAD),                        sizeof_bit_array(BTN_DIGI))                || containsNonZeroByte(key_bitmask, sizeof_bit_array(KEY_OK),                        sizeof_bit_array(KEY_MAX + 1))) {            ei.fd_key = fd;            LOGI("get key input device: %s", deviceName);        }    }     memset(abs_bitmask, 0, sizeof(abs_bitmask));    if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0) {        // Is this a new modern multi-touch driver?        if (test_bit(ABS_MT_POSITION_X, abs_bitmask)                && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) {            ei.fd_touch = fd;            LOGI("get multi-touch input device: %s", deviceName);         // Is this an old style single-touch driver?        } else if (test_bit(BTN_TOUCH, key_bitmask)                && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {            ei.fd_touch = fd;            LOGI("get single-touch input device: %s", deviceName);        }    }} int write_event(int fd, int type, int code, int value){    struct input_event event;     memset(&event, 0, sizeof(event));    event.type = type;    event.code = code;    event.value = value;    if(write(fd, &event, sizeof(event)) < sizeof(event)) {        LOGI("write event failed[%d]: %s", errno, strerror(errno));        return -1;    }    return 0;} void calculateXY(float x, float y, int *abs_x, int *abs_y){    *abs_x = ei.abs_x_min +            (int)((x * (float)(ei.abs_x_max - ei.abs_x_min)) / ei.screen_width + 0.5);    *abs_y = ei.abs_y_min +            (int)((y * (float)(ei.abs_y_max - ei.abs_y_min)) / ei.screen_height + 0.5);} int containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint32_t endIndex){    const uint8_t* end = array + endIndex;    array += startIndex;    while (array != end) {        if (*(array++) != 0) {            return 1;        }    }    return 0;}

结论

以上是使用ioctl来实现对设备i/o控制,如果不用ioctl的话,也可以实现对设备I/O通道的控制。例如,我们可以在驱动程序中实现write的时候检查一下是否有特殊约定的数据流通过,如果有的话,那么后面就跟着控制命令。但是如果这样做的话,会导致代码分工不明,程序结构混乱,程序员自己也会头昏眼花的。所以,我们就使用ioctl来实现控制的功能。


下载

项目下载

读书人网 >Android

热点推荐