【Android休眠】引申之uinput: 用户空间的输入子系统
来源:互联网 发布:足球数据分析大师系统 编辑:程序博客网 时间:2024/05/17 23:06
http://blog.csdn.net/u013686019/article/details/53910121
uinput is a linux kernel module that allows to handle the input subsystem from user land. It can be used to create and to handle input devices from an application. It creates a character device in /dev/input directory. The device is a virtual interface, it doesn't belong to a physical device.
In this document, we will see how to create a such input device and how it can be used.
1. Creating an input device
Once the uinput module is installed (via modprobe or insmod), a character device is created, named as/dev/input/uinput (or/dev/uinput on some systems). This device represents the interface between the application and the kernel input subsystem.
To use uinput, we need to open the character device in write-only and non-blocking mode:
#include <linux/input.h>#include <linux/uinput.h>...int fd;fd = open("/dev/input/uinput", O_WRONLY | O_NONBLOCK);if(fd < 0) { ... exit(EXIT_FAILURE);}
Now the device is opened, we will configure our input device. First, we need to inform the input subsystem which types of input event we want to use. Types of events are defined in/usr/include/linux/input.h:
...#define EV_KEY 0x01#define EV_REL 0x02#define EV_ABS 0x03...
- EV_KEY type represents key press and release events,
- EV_REL type represents relative axis events (such as mouse movements),
- EV_ABS type represents absolute axis events (such as touchscreen movements),
- …
The ioctl request UI_SET_EVBIT applied on theuinput file descriptor is used to enable a type of event. The two following lines enable key press/release and synchronization events.
ret = ioctl(fd, UI_SET_EVBIT, EV_KEY);...ret = ioctl(fd, UI_SET_EVBIT, EV_SYN);When enabling EV_KEY events, we need to describe which keycodes are allowed to be sent via the input subsystem.
As linux/input.h defines the 'd' key as KEY_D, we can enable the keycode representing the 'd' key by using:
ret = ioctl(fd, UI_SET_KEYBIT, KEY_D);...
Now some basic features have been enabled, we need to finish the configuration by using thestruct uinput_user_dev fromlinux/uinput.h. This structure is defined as:
#define UINPUT_MAX_NAME_SIZE 80struct uinput_user_dev { char name[UINPUT_MAX_NAME_SIZE]; struct input_id id; int ff_effects_max; int absmax[ABS_MAX + 1]; int absmin[ABS_MAX + 1]; int absfuzz[ABS_MAX + 1]; int absflat[ABS_MAX + 1];};
The most important fields are:
- name is the given name to the input device we will create,
- id is a linux internal structure that describes the device bustype, vendor id, product id and version,
- absmin and absmax are integer array that defines mininal and maximal values for an absolute axis (i.e absmin[ABS_X] = 0, absmax[ABS_X] = 1024 for the X axis on a touchscreen device).
Now, we can fill this structure with appropriate values:
struct uinput_user_dev uidev;memset(&uidev, 0, sizeof(uidev));snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-sample");uidev.id.bustype = BUS_USB;uidev.id.vendor = 0x1234;uidev.id.product = 0xfedc;uidev.id.version = 1;
Then, we write this structure in the uinput file descriptor.
ret = write(fd, &uidev, sizeof(uidev));
Last step is to request the creation of the device via the UI_DEV_CREATE ioctl request on the file descriptor:
ret = ioctl(fd, UI_DEV_CREATE);Now, the file descriptor fd represents the end-point file descriptor of the new input device.
2. Injecting events in the input subsystem
The following block code injects a key press event in the input subsystem. The input_event structure contains 3 important fields:
type: is an event type (EV_KEY,EV_ABS,EV_REL, ...),
code: could be either a key code when usingEV_KEY, or an axis forEV_ABS andEV_REL,
value: may be 1 (press) or 0 (release) forEV_KEY, or any values for others (positive integer forEV_ABS, signed integer forEV_REL, etc…).
To inject a press event on the 'd' key:
struct input_event ev;memset(&ev, 0, sizeof(ev));ev.type = EV_KEY;ev.code = KEY_D;ev.value = 1;ret = write(fd, &ev, sizeof(ev));
3. Destroying an input device
ret = ioctl(fd, UI_DEV_DESTROY);
4. Handling absolute axis events
If we want to inject absolute events, we first need to activate EV_ABS event and the desired axes support with ioctl requests. The following ioctl requests enable X and Y absolute axes:
ret = ioctl(fd, UI_SET_EVBIT, EV_ABS);...ret = ioctl(fd, UI_SET_ABSBIT, ABS_X);...ret = ioctl(fd, UI_SET_ABSBIT, ABS_Y);
Then we need to defined a range of values for each axis with absmin and absmax fields from the uinput_user_dev structure:
uidev.absmin[ABS_X] = 0;uidev.absmax[ABS_X] = 1023;
Event injection follows the same method as for any other events.
struct input_event ev[2];memset(ev, 0, sizeof(ev));ev[0].type = EV_ABS;ev[0].code = ABS_X;ev[0].value = 1023;ev[1].type = EV_ABS;ev[1].code = ABS_Y;ev[1].value = 767;ret = write(fd, ev, sizeof(ev));
5. Sample code
以下是模拟键盘的一个示例及其使用测试,在Android平台测试:
First compile code under Android source,
Then push your bin file to Android system,
Third, open an App that contains an EditText, such as Google browser and run your bin file.
#ifndef _GNU_SOURCE#define _GNU_SOURCE#endif#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <fcntl.h>#include <paths.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <errno.h>#include <linux/input.h>#include <linux/uinput.h>#include <signal.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <sys/stat.h>#include <sys/time.h>#include <sys/types.h>#include <sys/wait.h>#include <sys/time.h>#include <sys/ioctl.h>#include <sys/types.h>#include <linux/types.h>#include <termios.h>#include <time.h>#include <pthread.h>#include <hardware_legacy/power.h>#define LOG_TAG "UINPUT"#include <utils/Log.h> //all Android LOG macros are defined here.#define DEBUG 1#ifdef DEBUG#define LOG(lvl, f,...) do{ \ LOG_PRI(ANDROID_LOG_ERROR,LOG_TAG,"%d:%s(): " f, __LINE__, __FUNCTION__, ##__VA_ARGS__);\ }while(0)#else#define LOG(lvl,f,...)do{}while(0)#endif#define SHIFT (1 << 16)/* * Convert from character to KEY_CODE */static int keyboard_map(const char key){ int event = -1; switch (key) { case '1': event = KEY_1; break; case '2': event = KEY_2; break; case '3': event = KEY_3; break; case '4': event = KEY_4; break; case '5': event = KEY_5; break; case '6': event = KEY_6; break; case '7': event = KEY_7; break; case '8': event = KEY_8; break; case '9': event = KEY_9; break; case '0': event = KEY_0; break; case 'a': event = KEY_A; break; case 'b': event = KEY_B; break; case 'c': event = KEY_C; break; case 'd': event = KEY_D; break; case 'e': event = KEY_E; break; case 'f': event = KEY_F; break; case 'g': event = KEY_G; break; case 'h': event = KEY_H; break; case 'i': event = KEY_I; break; case 'j': event = KEY_J; break; case 'k': event = KEY_K; break; case 'l': event = KEY_L; break; case 'm': event = KEY_M; break; case 'n': event = KEY_N; break; case 'o': event = KEY_O; break; case 'p': event = KEY_P; break; case 'q': event = KEY_Q; break; case 'r': event = KEY_R; break; case 's': event = KEY_S; break; case 't': event = KEY_T; break; case 'u': event = KEY_U; break; case 'v': event = KEY_V; break; case 'w': event = KEY_W; break; case 'x': event = KEY_X; break; case 'y': event = KEY_Y; break; case 'z': event = KEY_Z; break; case 'A': event = KEY_A; event |= SHIFT; break; case 'B': event = KEY_B; event |= SHIFT; break; case 'C': event = KEY_C; event |= SHIFT; break; case 'D': event = KEY_D; event |= SHIFT; break; case 'E': event = KEY_E; event |= SHIFT; break; case 'F': event = KEY_F; event |= SHIFT; break; case 'G': event = KEY_G; event |= SHIFT; break; case 'H': event = KEY_H; event |= SHIFT; break; case 'I': event = KEY_I; event |= SHIFT; break; case 'J': event = KEY_J; event |= SHIFT; break; case 'K': event = KEY_K; event |= SHIFT; break; case 'L': event = KEY_L; event |= SHIFT; break; case 'M': event = KEY_M; event |= SHIFT; break; case 'N': event = KEY_N; event |= SHIFT; break; case 'O': event = KEY_O; event |= SHIFT; break; case 'P': event = KEY_P; event |= SHIFT; break; case 'Q': event = KEY_Q; event |= SHIFT; break; case 'R': event = KEY_R; event |= SHIFT; break; case 'S': event = KEY_S; event |= SHIFT; break; case 'T': event = KEY_T; event |= SHIFT; break; case 'U': event = KEY_U; event |= SHIFT; break; case 'V': event = KEY_V; event |= SHIFT; break; case 'W': event = KEY_W; event |= SHIFT; break; case 'X': event = KEY_X; event |= SHIFT; break; case 'Y': event = KEY_Y; event |= SHIFT; break; case 'Z': event = KEY_Z; event |= SHIFT; break; case '!': event = KEY_1; event |= SHIFT; break; case '@': event = KEY_2; event |= SHIFT; break; case '#': event = KEY_3; event |= SHIFT; break; case '$': event = KEY_4; event |= SHIFT; break; case '%': event = KEY_5; event |= SHIFT; break; case '^': event = KEY_6; event |= SHIFT; break; case '&': event = KEY_7; event |= SHIFT; break; case '*': event = KEY_8; event |= SHIFT; break; case '(': event = KEY_9; event |= SHIFT; break; case ')': event = KEY_0; event |= SHIFT; break; case '-': event = KEY_MINUS; break; case '_': event = KEY_MINUS; event |= SHIFT; break; case '=': event = KEY_EQUAL; break; case '+': event = KEY_EQUAL; event |= SHIFT; break; case ';': event = KEY_SEMICOLON; break; case ':': event = KEY_SEMICOLON; event |= SHIFT; break; case ',': event = KEY_COMMA; break; case '<': event = KEY_COMMA; event |= SHIFT; break; case '.': event = KEY_DOT; break; case '>': event = KEY_DOT; event |= SHIFT; break; case '/': event = KEY_SLASH; break; case '?': event = KEY_SLASH; event |= SHIFT; break; case '[': event = KEY_LEFTBRACE; break; case '{': event = KEY_LEFTBRACE; event |= SHIFT; break; case ']': event = KEY_RIGHTBRACE; break; case '}': event = KEY_RIGHTBRACE; event |= SHIFT; break; case '\\': event = KEY_BACKSLASH; break; case '|': event = KEY_BACKSLASH; event |= SHIFT; break; case '\'': event = KEY_APOSTROPHE; break; case '"': event = KEY_APOSTROPHE; event |= SHIFT; break; case '`': event = KEY_GRAVE; break; case '~': event = KEY_BACKSLASH; event |= SHIFT; break; default: event = -1; break; } return event;}int keyboard_init(void){ int fd; struct uinput_user_dev uidev; //struct input_event ev; int i; fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); if(fd <= 0) { LOG(0, "error: open"); return -1; } else { LOG(0, "open /dev/uinput fd = %d\n", fd); } memset(&uidev, 0, sizeof(uidev)); snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "HID Fake Device"); uidev.id.bustype = BUS_USB; uidev.id.vendor = 0x1; uidev.id.product = 0x1; uidev.id.version = 1; // config uinput device Keyboard ioctl(fd, UI_SET_EVBIT, EV_KEY); for (i = 0; i < 128; i++) { ioctl(fd, UI_SET_KEYBIT, i); usleep(10000); } if(write(fd, &uidev, sizeof(uidev)) < 0) { LOG(0, "error: write"); return -1; } if(ioctl(fd, UI_DEV_CREATE) < 0) { LOG(0, "error: ioctl"); return -1; } return fd;}int keyboard_release(int fd){ if (fd <= 0) return -1; if(ioctl(fd, UI_DEV_DESTROY) < 0) LOG(0, "error: ioctl"); close(fd); return 0;}int keyboard_write(int fd, const char key){ struct input_event event; const int kval = keyboard_map(key); const unsigned short key_code = (unsigned short) kval; if (fd <= 0) { LOG(0, "open fd <= 0 error!\n"); return -1; } if (kval <= 0) { LOG(0, "keyboard_write error!\n"); return -1; } // shift down if ((kval & SHIFT) == SHIFT) { memset(&event, 0, sizeof(event)); gettimeofday(&event.time, 0); event.type = EV_KEY; event.value = 1; event.code = KEY_LEFTSHIFT; if (write(fd, &event, sizeof(event)) < 0) return -1; } // key down memset(&event, 0, sizeof(event)); gettimeofday(&event.time, 0); event.type = EV_KEY; event.value = 1; event.code = key_code; if (write(fd, &event, sizeof(event)) < 0) return -1; // key up memset(&event, 0, sizeof(event)); gettimeofday(&event.time, 0); event.type = EV_KEY; event.value = 0; event.code = key_code; if (write(fd, &event, sizeof(event)) < 0) return -1; // shift down if ((kval & SHIFT) == SHIFT) { memset(&event, 0, sizeof(event)); gettimeofday(&event.time, 0); event.type = EV_KEY; event.value = 0; event.code = KEY_LEFTSHIFT; if (write(fd, &event, sizeof(event)) < 0) return -1; } // sync event.type = EV_SYN; event.value = 0; event.code = SYN_REPORT; if (write(fd, &event, sizeof(event)) < 0) return -1; return 0;}int main(int argc, char **argv){int fd = -1;int i = -1;const char *buf = "!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~";fd = keyboard_init();if (fd <= 0) {LOG(0, "error: keyboard_init()");return -1;}for (i = 0; i < strlen(buf); i++) { keyboard_write(fd, buf[i]); usleep(10000); } keyboard_release(fd); return 0;}
原文:uinput: the user level input subsystem
- 【Android休眠】引申之uinput: 用户空间的输入子系统
- 【Android休眠】引申之关于系统PM的思考
- Android 4.0 用户输入子系统
- Android 4.0 用户输入子系统
- Android 4.0 用户输入子系统
- Android 4.0 用户输入子系统
- Android底层开发之Linux输入子系统要不要判断系统休眠状态上报键值
- android 使用uinput模拟输入设备
- 我的uinput模拟输入设备
- android底层驱动学习之linux输入子系统的理解
- [android] 调试linux input子系统驱动的用户空间命令 getevent/sendevent
- Android输入子系统之启动过程分析
- Linux驱动子系统之I2C用户空间调用
- Linux时间子系统之(三):用户空间接口函数
- Linux时间子系统之(三):用户空间接口函数
- Android Camera子系统之用户View
- Android系统利用uinput设备驱动实现虚拟输入设备
- Android系统利用uinput设备驱动实现虚拟输入设备
- android 判断一串数字是否为正确手机号和身份证号的校验工具类
- 各种浏览器的Hack写法(chrome firefox ie等)
- rman进行归档日志指定备份几次以上的不备份
- Android:ubuntu下编译MuPDF源码
- 9. 使用JdbcTemplate【从零开始学Spring Boot】
- 【Android休眠】引申之uinput: 用户空间的输入子系统
- DrawerLayout侧拉中途无法滑动,侧拉一定距离无法移动,卡主,停止
- android studio发布版和测试版证书SHA1获取
- JAVA校招技能图谱
- Vue + Webpack + Vue-loader 功能介绍
- 魅蓝手机ROOT权限获取
- maven项目中子模块中相互引用问题解决方案
- android应用中去掉标题栏的方法
- 用js写倒计时