input模块的主要功能 :
从多个输入设备获得输入事件
input模块包含三个文件,input_manager.c,touchscreen.c和stdin.c,其中touchscreen.ch和stdin.c为支持的输入方式,input_manager.c通过链表管理可支持的设备。
input_manager.c
| |
touchscreen.c stdin.c
底层的touchscreen.c和stdin.c,向上注册InputOpr结构体,提供该设备的操作函数。
typedef struct InputOpr {
char *name; /* 输入模块的名字 */
pthread_t tTreadID; /* 子线程ID */
int (*DeviceInit)(void); /* 设备初始化函数 */
int (*DeviceExit)(void); /* 设备退出函数 */
int (*GetInputEvent)(PT_InputEvent ptInputEvent); /* 获得输入数据 */
struct InputOpr *ptNext;
}T_InputOpr, *PT_InputOpr;
typedef struct InputEvent {
struct timeval tTime; /* 发生这个输入事件时的时间 */
int iType; /* 类别: stdin, touchsceen */
int iX; /* X/Y座标 */
int iY;
int iKey; /* 按键值 */
int iPressure; /* 压力值 */
}T_InputEvent, *PT_InputEvent;
touchscreen.c
static T_InputOpr g_tTouchScreenOpr = {
.name = "touchscreen",
.DeviceInit = TouchScreenDevInit, //触摸屏输入模块的设备初始化函数
.DeviceExit = TouchScreenDevExit, //触摸屏输入模块的设备退出函数
.GetInputEvent = TouchScreenGetInputEvent, //触摸屏输入模块的读取数据函数,它在触摸屏输入模块的子线程中被调用
};
static int TouchScreenDevInit(void){
char *pcTSName = NULL;
int iBpp;
if ((pcTSName = getenv("TSLIB_TSDEVICE")) != NULL ) {
g_tTSDev = ts_open(pcTSName, 0); /* 以阻塞方式打开 */
}
else{
g_tTSDev = ts_open("/dev/event0", 1);
}
ts_config(g_tTSDev)
GetDispResolution(&giXres, &giYres, &iBpp)
return 0;
}
static int TouchScreenDevExit(void){
return 0;
}
static int TouchScreenGetInputEvent(PT_InputEvent ptInputEvent){
struct ts_sample tSamp;
while (1){
iRet = ts_read(g_tTSDev, &tSamp, 1); /* 如果无数据则休眠 */
if (iRet == 1){ //返回原始事件
ptInputEvent->tTime = tSamp.tv;
ptInputEvent->iType = INPUT_TYPE_TOUCHSCREEN;
ptInputEvent->iX = tSamp.x;
ptInputEvent->iY = tSamp.y;
ptInputEvent->iPressure = tSamp.pressure;
return 0;
}
else{
return -1;
}
}
return 0;
}
其中
触摸屏read得到的数据,参考ts_print和tslib.h
struct ts_sample {
int x;
int y;
unsigned int pressure;
struct timeval tv;
};
stdin.c
static T_InputOpr g_tStdinOpr = {
.name = "stdin",
.DeviceInit = StdinDevInit, //标准输入模块的设备初始化函数,用于设置标准输入的属性,比如默认的标准输入是接收到回车换行符时才返回数据,在本程序里把它改为"接收到任意一个字符即返回数据"
.DeviceExit = StdinDevExit, //标准输入模块的设备退出函数,恢复标准输入的原来属性
.GetInputEvent = StdinGetInputEvent, //标准输入模块的读取数据函数,它在标准输入模块的子线程中被调用
};
static int StdinDevInit(void){
struct termios tTTYState;
tcgetattr(STDIN_FILENO, &tTTYState); //get the terminal state
tTTYState.c_lflag &= ~ICANON; //turn off canonical mode
tTTYState.c_cc[VMIN] = 1; /* 有一个数据时就立刻返回 */ //minimum of number input read.
tcsetattr(STDIN_FILENO, TCSANOW, &tTTYState); //set the terminal attributes.
return 0;
}
static int StdinDevExit(void){
struct termios tTTYState;
tcgetattr(STDIN_FILENO, &tTTYState); //get the terminal state
tTTYState.c_lflag |= ICANON; //turn on canonical mode
tcsetattr(STDIN_FILENO, TCSANOW, &tTTYState); //set the terminal attributes.
return 0;
}
static int StdinGetInputEvent(PT_InputEvent ptInputEvent){
/* 如果有数据就读取、处理、返回
* 如果没有数据, 立刻返回, 不等待*/
/* select, poll 可以参数 UNIX环境高级编程 */
char c;
ptInputEvent->iType = INPUT_TYPE_STDIN; /* 处理数据 */
c = fgetc(stdin); /* 会休眠直到有输入 */
gettimeofday(&ptInputEvent->tTime, NULL);
return 0;
}
input_manager.c
input_manager.c通过链表管理底层支持的显示设备向上注册的InputOpr结构体,并向外部提供对底层的操作函数。其中头文件Input_manager.h包含InputOpr和InputEvent结构体。
int RegisterInputOpr(PT_InputOpr ptInputOpr) //注册"输入模块"
int AllInputDevicesInit(void) //调用所有"输入模块"的设备相关的初始化函数并创建用于读取输入数据的子线程
static void *InputEventThreadFunction(void *pVoid) //"输入模块"的线程函数,每个输入模块都是通过创建子线程来读取输入数据,读到数据后它会唤醒等得数据的其他线程
int GetInputEvent(PT_InputEvent ptInputEvent) //获得输入数据,它会使得当前线程休眠,当各输入模块的子线程读到数据后会把它唤醒
上层先调用AllInputDevicesInit函数初始化相关设备并创建用于读取输入数据的子线程。在子线程函数中以阻塞方式读取事件进入休眠,在上层函数中调用GetInputEvent获取事件进入休眠。当有输入事件时,子线程函数将上层函数唤醒,则上层函数就得到了输入事件InputEvent结构体。具体实现参考多输入。