结构体&链表
结构体
typedef struct InputEvent { struct timeval tTime; /* 发生这个输入事件时的时间 */ int iType; /* 类别: stdin, touchsceen */ int iX; /* X/Y座标 */ int iY; int iKey; /* 按键值 */ int iPressure; /* 压力值 */ }T_InputEvent, *PT_InputEvent; 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;
输入事件处理的数据结构和函数接口,其中InputOpr结构体可以用于实现不同的输入模块,并且通过链表将它们连接起来。
链表操作
static PT_InputOpr g_ptInputOprHead; static T_InputEvent g_tInputEvent; static pthread_mutex_t g_tMutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t g_tConVar = PTHREAD_COND_INITIALIZER; /********************************************************************** * 函数名称: RegisterInputOpr * 功能描述: 注册"输入模块" * 输入参数: ptInputOpr - 输入模块的结构体指针 * 输出参数: 无 * 返 回 值: 0 - 成功, 其他值 - 失败 ***********************************************************************/ int RegisterInputOpr(PT_InputOpr ptInputOpr) { PT_InputOpr ptTmp; if (!g_ptInputOprHead) { g_ptInputOprHead = ptInputOpr; ptInputOpr->ptNext = NULL; } else { ptTmp = g_ptInputOprHead; while (ptTmp->ptNext) { ptTmp = ptTmp->ptNext; } ptTmp->ptNext = ptInputOpr; ptInputOpr->ptNext = NULL; } return 0; } /********************************************************************** * 函数名称: ShowInputOpr * 功能描述: 显示本程序能支持的"输入模块" * 输入参数: 无 * 输出参数: 无 * 返 回 值: 无 ***********************************************************************/ void ShowInputOpr(void) { int i = 0; PT_InputOpr ptTmp = g_ptInputOprHead; while (ptTmp) { printf("%02d %s\n", i++, ptTmp->name); ptTmp = ptTmp->ptNext; } } /********************************************************************** * 函数名称: InputEventThreadFunction * 功能描述: "输入模块"的线程函数,每个输入模块都是通过创建子线程来读取输入数据, * 读到数据后它会唤醒等得数据的其他线程 * 输入参数: pVoid - 输入模块的"读输入数据函数" * 输出参数: 无 * 返 回 值: NULL - 正常退出 ***********************************************************************/ static void *InputEventThreadFunction(void *pVoid) { T_InputEvent tInputEvent; /* 定义函数指针 */ int (*GetInputEvent)(PT_InputEvent ptInputEvent); GetInputEvent = (int (*)(PT_InputEvent))pVoid; while (1) { if(0 == GetInputEvent(&tInputEvent)) { /* 唤醒主线程, 把tInputEvent的值赋给一个全局变量 */ /* 访问临界资源前,先获得互斥量 */ pthread_mutex_lock(&g_tMutex); g_tInputEvent = tInputEvent; /* 唤醒主线程 */ pthread_cond_signal(&g_tConVar); /* 释放互斥量 */ pthread_mutex_unlock(&g_tMutex); } } return NULL; } /********************************************************************** * 函数名称: AllInputDevicesInit * 功能描述: 调用所有"输入模块"的设备相关的初始化函数 * 并创建用于读取输入数据的子线程 * 输入参数: 无 * 输出参数: 无 * 返 回 值: 0 - 成功, 其他值 - 失败 ***********************************************************************/ int AllInputDevicesInit(void) { PT_InputOpr ptTmp = g_ptInputOprHead; int iError = -1; while (ptTmp) { if (0 == ptTmp->DeviceInit()) { /* 创建子线程 */ pthread_create(&ptTmp->tTreadID, NULL, InputEventThreadFunction, ptTmp->GetInputEvent); iError = 0; } ptTmp = ptTmp->ptNext; } return iError; } /********************************************************************** * 函数名称: GetInputEvent * 功能描述: 获得输入数据,它会使得当前线程休眠, * 当各输入模块的子线程读到数据后会把它唤醒 * 输入参数: 无 * 输出参数: ptInputEvent - 内含得到的输入数据 * 返 回 值: 0 - 成功 ***********************************************************************/ int GetInputEvent(PT_InputEvent ptInputEvent) { /* 休眠 */ pthread_mutex_lock(&g_tMutex); pthread_cond_wait(&g_tConVar, &g_tMutex); /* 被唤醒后,返回数据 */ *ptInputEvent = g_tInputEvent; pthread_mutex_unlock(&g_tMutex); return 0; } /********************************************************************** * 函数名称: InputInit * 功能描述: 调用各个输入模块的初始化函数,就是注册各个输入模块 * 输入参数: 无 * 输出参数: 无 * 返 回 值: 0 - 成功, 其他值 - 失败 ***********************************************************************/ int InputInit(void) { int iError = 0; // iError = StdinInit(); iError |= TouchScreenInit(); return iError; }
这段代码实现了一个输入管理系统,包含了注册输入模块、显示支持的输入模块、创建输入模块线程、初始化输入设备等功能。
代码中使用了全局变量和互斥量来实现线程间的同步和通信。
以下是代码中各个函数的功能描述:
RegisterInputOpr函数用于注册输入模块,将输入模块的结构体指针添加到输入模块链表中。
ShowInputOpr函数用于显示支持的输入模块,遍历输入模块链表并打印每个输入模块的名称。
InputEventThreadFunction函数是输入模块的线程函数,每个输入模块都会创建一个子线程来读取输入数据。线程循环读取数据并唤醒等待数据的其他线程。
AllInputDevicesInit函数调用所有输入模块的设备初始化函数,并创建用于读取输入数据的子线程。
GetInputEvent函数用于获取输入数据,它会使当前线程休眠,等待输入模块的子线程读取到数据后唤醒它。然后将获取到的输入数据返回给调用者。
InputInit函数用于初始化输入管理系统,调用各个输入模块的初始化函数进行注册。
这段代码的基本逻辑是,先调用InputInit进行初始化,注册各个输入模块。然后调用AllInputDevicesInit创建输入模块的子线程并启动读取输入数据。其他线程通过调用GetInputEvent函数获取输入数据,线程会在没有输入数据时进入休眠状态,直到输入模块的子线程读取到数据并唤醒它们。
这段代码实现了一个基本的输入管理系统,通过注册不同的输入模块可以支持不同的输入设备,并通过线程和同步机制实现输入数据的获取和处理。
标准输入
/********************************************************************** * 函数名称: StdinDevInit * 功能描述: 标准输入模块的设备初始化函数,用于设置标准输入的属性, * 比如默认的标准输入是接收到回车换行符时才返回数据, * 在本程序里把它改为"接收到任意一个字符即返回数据" * 输入参数: 无 * 输出参数: 无 * 返 回 值: 0 - 成功, 其他值 - 失败 ***********************************************************************/ static int StdinDevInit(void) { struct termios tTTYState; //get the terminal state tcgetattr(STDIN_FILENO, &tTTYState); //turn off canonical mode tTTYState.c_lflag &= ~ICANON; //minimum of number input read. tTTYState.c_cc[VMIN] = 1; /* 有一个数据时就立刻返回 */ //set the terminal attributes. tcsetattr(STDIN_FILENO, TCSANOW, &tTTYState); return 0; } /********************************************************************** * 函数名称: StdinDevExit * 功能描述: 标准输入模块的设备退出函数,恢复标准输入的原来属性 * 输入参数: 无 * 输出参数: 无 * 返 回 值: 0 - 成功, 其他值 - 失败 ***********************************************************************/ static int StdinDevExit(void) { struct termios tTTYState; //get the terminal state tcgetattr(STDIN_FILENO, &tTTYState); //turn on canonical mode tTTYState.c_lflag |= ICANON; //set the terminal attributes. tcsetattr(STDIN_FILENO, TCSANOW, &tTTYState); return 0; } /********************************************************************** * 函数名称: StdinGetInputEvent * 功能描述: 标准输入模块的读取数据函数,它在标准输入模块的子线程中被调用 * 输入参数: 无 * 输出参数: ptInputEvent - 内含得到的输入数据 * 返 回 值: 0 - 成功, 其他值 - 失败 ***********************************************************************/ static int StdinGetInputEvent(PT_InputEvent ptInputEvent) { /* 如果有数据就读取、处理、返回 * 如果没有数据, 立刻返回, 不等待 */ /* select, poll 可以参数 UNIX环境高级编程 */ //char c; /* 处理数据 */ ptInputEvent->iType = INPUT_TYPE_STDIN; fgetc(stdin); /* 会休眠直到有输入 */ gettimeofday(&ptInputEvent->tTime, NULL); #if 0 if (c == 'u') { ptInputEvent->iVal = INPUT_VALUE_UP; } else if (c == 'n') { ptInputEvent->iVal = INPUT_VALUE_DOWN; } else if (c == 'q') { ptInputEvent->iVal = INPUT_VALUE_EXIT; } else { ptInputEvent->iVal = INPUT_VALUE_UNKNOWN; } #endif return 0; } static T_InputOpr g_tStdinOpr = { .name = "stdin", .DeviceInit = StdinDevInit, .DeviceExit = StdinDevExit, .GetInputEvent = StdinGetInputEvent, }; /********************************************************************** * 函数名称: StdinInit * 功能描述: 注册"标准输入模块" * 输入参数: 无 * 输出参数: 无 * 返 回 值: 0 - 成功, 其他值 - 失败 ***********************************************************************/ int StdinInit(void) { return RegisterInputOpr(&g_tStdinOpr); }
这段代码实现了标准输入模块的设备初始化、设备退出和读取数据的功能。
StdinDevInit函数用于设置标准输入的属性,将其改为"接收到任意一个字符即返回数据"。它使用tcgetattr函数获取终端状态,然后通过修改终端属性的方式关闭规范模式和设置最小输入数量为1个字符,最后使用tcsetattr函数设置终端属性。
StdinDevExit函数用于恢复标准输入的原始属性,它与StdinDevInit函数相反,将终端属性设置为默认状态。
StdinGetInputEvent函数是标准输入模块的读取数据函数,它在标准输入模块的子线程中被调用。该函数会读取一个字符,并将输入事件的类型设置为标准输入类型,时间戳设置为当前时间。
g_tStdinOpr是标准输入模块的结构体实例,包含了模块的名称、设备初始化函数、设备退出函数和获取输入事件函数等信息。
StdinInit
函数用于注册标准输入模块,将g_tStdinOpr添加到输入模块链表中。
这段代码实现了标准输入模块的功能,通过修改终端属性实现了即时返回输入数据的功能。当用户在标准输入中输入任意字符时,会触发输入事件,并通过输入管理系统进行处理
标准输入模块的设备初始化
/********************************************************************** * 函数名称: StdinDevInit * 功能描述: 标准输入模块的设备初始化函数,用于设置标准输入的属性, * 比如默认的标准输入是接收到回车换行符时才返回数据, * 在本程序里把它改为"接收到任意一个字符即返回数据" * 输入参数: 无 * 输出参数: 无 * 返 回 值: 0 - 成功, 其他值 - 失败 ***********************************************************************/ static int StdinDevInit(void) { struct termios tTTYState; //get the terminal state tcgetattr(STDIN_FILENO, &tTTYState); //turn off canonical mode tTTYState.c_lflag &= ~ICANON; //minimum of number input read. tTTYState.c_cc[VMIN] = 1; /* 有一个数据时就立刻返回 */ //set the terminal attributes. tcsetattr(STDIN_FILENO, TCSANOW, &tTTYState); return 0; }
函数StdinDevInit用于初始化标准输入设备的属性,使其在输入时能够立即返回数据而不需要等待特定条件。
以下是函数中的具体步骤:
声明一个struct termios类型的变量tTTYState,用于存储终端属性信息。
调用tcgetattr函数获取当前标准输入终端的属性,并将属性信息保存在tTTYState中。
关闭规范模式(canonical mode),通过位操作将tTTYState.c_lflag中的ICANON标志位清除,即&= ~ICANON。
设置输入的最小数量为1个字符。通过修改tTTYState.c_cc[VMIN]的值为1,表示在输入中至少读取一个字符后立即返回。
使用tcsetattr函数将修改后的终端属性设置为当前标准输入终端的属性。
返回0,表示初始化成功。
这段代码的作用是修改标准输入终端的属性,以使其在接收到任意一个字符时立即返回数据。通过关闭规范模式和设置最小输入数量为1,实现了实时获取输入数据的功能。
标准输入模块的设备退出
/********************************************************************** * 函数名称: StdinDevExit * 功能描述: 标准输入模块的设备退出函数,恢复标准输入的原来属性 * 输入参数: 无 * 输出参数: 无 * 返 回 值: 0 - 成功, 其他值 - 失败 ***********************************************************************/ static int StdinDevExit(void) { struct termios tTTYState; //get the terminal state tcgetattr(STDIN_FILENO, &tTTYState); //turn on canonical mode tTTYState.c_lflag |= ICANON; //set the terminal attributes. tcsetattr(STDIN_FILENO, TCSANOW, &tTTYState); return 0; }
函数StdinDevExit用于在标准输入设备退出时恢复其原始属性,即恢复到规范模式(canonical mode)。
以下是函数中的具体步骤:
声明一个struct termios类型的变量tTTYState,用于存储终端属性信息。
调用tcgetattr函数获取当前标准输入终端的属性,并将属性信息保存在tTTYState中。
打开规范模式,通过位操作将tTTYState.c_lflag中的ICANON标志位设置,即|= ICANON。
使用tcsetattr函数将恢复后的终端属性设置为当前标准输入终端的属性。
返回0,表示退出成功。
这段代码的作用是在标准输入设备退出时恢复其原始属性,即将终端设置回规范模式。这样可以确保在程序退出时,标准输入终端的属性恢复到之前的状态。
标准输入模块的读取数据
/********************************************************************** * 函数名称: StdinGetInputEvent * 功能描述: 标准输入模块的读取数据函数,它在标准输入模块的子线程中被调用 * 输入参数: 无 * 输出参数: ptInputEvent - 内含得到的输入数据 * 返 回 值: 0 - 成功, 其他值 - 失败 ***********************************************************************/ static int StdinGetInputEvent(PT_InputEvent ptInputEvent) { /* 如果有数据就读取、处理、返回 * 如果没有数据, 立刻返回, 不等待 */ /* select, poll 可以参数 UNIX环境高级编程 */ //char c; /* 处理数据 */ ptInputEvent->iType = INPUT_TYPE_STDIN; fgetc(stdin); /* 会休眠直到有输入 */ gettimeofday(&ptInputEvent->tTime, NULL); #if 0 if (c == 'u') { ptInputEvent->iVal = INPUT_VALUE_UP; } else if (c == 'n') { ptInputEvent->iVal = INPUT_VALUE_DOWN; } else if (c == 'q') { ptInputEvent->iVal = INPUT_VALUE_EXIT; } else { ptInputEvent->iVal = INPUT_VALUE_UNKNOWN; } #endif return 0; }
函数StdinGetInputEvent用于从标准输入中读取输入数据并将其填充到ptInputEvent结构体中。
以下是函数中的具体步骤:
设置输入事件的类型为INPUT_TYPE_STDIN,即标准输入。
使用fgetc(stdin)从标准输入中读取一个字符,这个函数会阻塞并等待输入。
使用gettimeofday函数获取当前时间,并将其保存到ptInputEvent->tTime中。
注释掉的代码块是处理输入字符的逻辑,根据不同的输入字符设置ptInputEvent->iVal的值,但是该代码块被注释掉了。
返回0,表示成功获取输入数据。
总结来说,该函数的作用是从标准输入中读取一个字符,并将输入事件的类型设置为标准输入,时间戳设置为当前时间。然而,该函数并未处理具体的输入字符,因为相关的处理逻辑被注释掉了(#if 0 到 #endif 之间的代码块)。
屏幕输入
#include <config.h> #include <input_manager.h> #include <disp_manager.h> #include <stdlib.h> #include <tslib.h> //#include <draw.h> /* 参考tslib里的ts_print.c */ static struct tsdev *g_tTSDev; static int giXres; static int giYres; /********************************************************************** * 函数名称: TouchScreenDevInit * 功能描述: 触摸屏输入模块的设备初始化函数 * 注意: 由于要用到LCD的分辨率, 此函数要在SelectAndInitDisplay之后才能调用 * 输入参数: 无 * 输出参数: 无 * 返 回 值: 0 - 成功, 其他值 - 失败 ***********************************************************************/ 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); } if (!g_tTSDev) { DBG_PRINTF(APP_ERR"ts_open error!\n"); return -1; } if (ts_config(g_tTSDev)) { DBG_PRINTF("ts_config error!\n"); return -1; } if (GetDispResolution(&giXres, &giYres, &iBpp)) { return -1; } return 0; } /********************************************************************** * 函数名称: StdinDevExit * 功能描述: 触摸屏输入模块的设备退出函数 * 输入参数: 无 * 输出参数: 无 * 返 回 值: 0 - 成功, 其他值 - 失败 ***********************************************************************/ static int TouchScreenDevExit(void) { return 0; } /********************************************************************** * 函数名称: TouchScreenGetInputEvent * 功能描述: 触摸屏输入模块的读取数据函数,它在触摸屏输入模块的子线程中被调用 * 输入参数: 无 * 输出参数: ptInputEvent - 内含得到的输入数据 * 返 回 值: 0 - 成功, 其他值 - 失败 ***********************************************************************/ static int TouchScreenGetInputEvent(PT_InputEvent ptInputEvent) { struct ts_sample tSamp; int iRet; 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; } static T_InputOpr g_tTouchScreenOpr = { .name = "touchscreen", .DeviceInit = TouchScreenDevInit, .DeviceExit = TouchScreenDevExit, .GetInputEvent = TouchScreenGetInputEvent, }; /********************************************************************** * 函数名称: TouchScreenInit * 功能描述: 注册"触摸屏输入模块" * 输入参数: 无 * 输出参数: 无 * 返 回 值: 0 - 成功, 其他值 - 失败 ***********************************************************************/ int TouchScreenInit(void) { return RegisterInputOpr(&g_tTouchScreenOpr); }
这部分代码是触摸屏输入模块的实现,包括设备初始化函数、设备退出函数和获取输入数据函数。
TouchScreenDevInit:触摸屏输入模块的设备初始化函数。它通过读取环境变量 TSLIB_TSDEVICE 获取触摸屏设备的路径,如果没有设置该环境变量,则默认使用 /dev/event0。然后调用 ts_open 函数打开触摸屏设备,并进行配置。最后,通过调用 GetDispResolution 函数获取显示屏的分辨率信息。
TouchScreenDevExit:触摸屏输入模块的设备退出函数。
TouchScreenGetInputEvent:触摸屏输入模块的读取数据函数,在触摸屏输入模块的子线程中被调用。它使用 ts_read 函数读取触摸屏数据,并将数据存储在传入的输入事件结构体中。
此外,还定义了一个名为 g_tTouchScreenOpr 的触摸屏输入模块结构体,并初始化了其中的成员,包括模块名称、设备初始化函数和获取输入数据函数等。
最后,提供了一个 TouchScreenInit 函数用于注册触摸屏输入模块,将 g_tTouchScreenOpr 结构体的地址传递给 RegisterInputOpr 函数进行注册。
触摸屏输入模块的设备初始化
/********************************************************************** * 函数名称: TouchScreenDevInit * 功能描述: 触摸屏输入模块的设备初始化函数 * 注意: 由于要用到LCD的分辨率, 此函数要在SelectAndInitDisplay之后才能调用 * 输入参数: 无 * 输出参数: 无 * 返 回 值: 0 - 成功, 其他值 - 失败 ***********************************************************************/ 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); } if (!g_tTSDev) { DBG_PRINTF(APP_ERR"ts_open error!\n"); return -1; } if (ts_config(g_tTSDev)) { DBG_PRINTF("ts_config error!\n"); return -1; } if (GetDispResolution(&giXres, &giYres, &iBpp)) { return -1; } return 0; }
static int TouchScreenDevInit(void) 是触摸屏输入模块的设备初始化函数。
函数的详细分析如下:
声明了一个指针变量 pcTSName 并初始化为 NULL,以及一个整型变量 iBpp。
使用 getenv 函数获取环境变量 “TSLIB_TSDEVICE” 的值,赋给 pcTSName。如果获取成功且返回值不为 NULL,则说明环境变量存在且有值,使用获取到的值作为参数调用 ts_open 函数打开触摸屏设备,并将返回的设备指针赋给全局变量 g_tTSDev。这里的打开方式为阻塞方式(第二个参数为0)。
如果获取环境变量失败或返回值为 NULL,则说明环境变量不存在或没有值,使用 ts_open 函数以非阻塞方式打开默认触摸屏设备 “/dev/event0”,并将返回的设备指针赋给全局变量 g_tTSDev。
检查 g_tTSDev 是否为空,如果为空则打印错误信息并返回 -1。
调用 ts_config 函数对触摸屏设备进行配置,如果配置失败则打印错误信息并返回 -1。
调用 GetDispResolution 函数获取显示器的分辨率和位深度,并将结果分别赋给 giXres、giYres 和 iBpp 变量。如果获取失败,则返回 -1。
函数执行成功,返回 0。
总体来说,该函数的作用是初始化触摸屏设备,并对设备进行配置。它通过获取环境变量或使用默认设备路径来打开触摸屏设备,然后进行配置和获取显示器分辨率等信息。
触摸屏输入模块的读取数据
/********************************************************************** * 函数名称: TouchScreenGetInputEvent * 功能描述: 触摸屏输入模块的读取数据函数,它在触摸屏输入模块的子线程中被调用 * 输入参数: 无 * 输出参数: ptInputEvent - 内含得到的输入数据 * 返 回 值: 0 - 成功, 其他值 - 失败 ***********************************************************************/ static int TouchScreenGetInputEvent(PT_InputEvent ptInputEvent) { struct ts_sample tSamp; int iRet; 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; }
static int TouchScreenGetInputEvent(PT_InputEvent ptInputEvent) 是触摸屏输入模块的读取数据函数。
函数的详细分析如下:
声明了一个结构体变量 tSamp,用于存储从触摸屏读取到的样本数据。
声明了一个整型变量 iRet,用于存储 ts_read 函数的返回值。
进入一个无限循环。
在循环中调用 ts_read 函数从触摸屏设备中读取一个样本数据,并将返回值赋给 iRet。如果没有数据可读,则该函数会进入休眠状态。
如果读取成功(iRet 等于 1),则将读取到的触摸屏数据分别赋给 ptInputEvent 结构体的成员变量。其中,tSamp.tv 表示时间戳,tSamp.x 和 tSamp.y 表示触摸点的坐标,tSamp.pressure 表示触摸压力。
返回成功的标志值 0。
如果读取失败,则返回失败的标志值 -1。
函数执行过程中,只要成功读取到触摸屏数据,即会立即返回,否则会一直循环读取。
总体来说,该函数的作用是从触摸屏设备中读取触摸数据,并将读取到的数据填充到 ptInputEvent 结构体中。函数通过调用 ts_read 函数读取触摸屏数据,如果成功读取到数据,则将数据赋给 ptInputEvent 结构体,并返回成功标志;如果读取失败,则返回失败标志。该函数会在无数据可读时进入休眠状态,直到有数据可读时才会返回