数码相框-主界面MainPage输入功能
定义输入管理的头文件
#ifndef _INPUT_MANAGER_H
#define _INPUT_MANAGER_H
#include <sys/time.h>
#include <pthread.h>
/* 输入类型定义 */
#define INPUT_TYPE_STDIN 0 /* 标准输入 */
#define INPUT_TYPE_TOUCHSCREEN 1 /* 触摸屏 */
/* 输入事件值定义 */
#define INPUT_VALUE_UP 0 /* 上 */
#define INPUT_VALUE_DOWN 1 /* 下 */
#define INPUT_VALUE_EXIT 2 /* 退出 */
#define INPUT_VALUE_UNKNOWN -1 /* 未知 */
/* 输入事件结构体定义,包含事件的时间、类型、坐标、键值和压力等信息 */
typedef struct InputEvent {
struct timeval tTime;
int iType; /* 输入设备类型 */
int iX;
int iY;
int iKey;
int iPressure;
}T_InputEvent, *PT_InputEvent;
/* 输入操作结构体定义,包含设备名称、线程ID、设备初始化与退出函数指针、获取输入事件函数指针和下一个输入操作结构体指针 */
typedef struct InputOpr {
char *name;
pthread_t tTreadID;
int (*DeviceInit)(void); /* 设备初始化函数 */
int (*DeviceExit)(void); /* 设备退出函数 */
int (*GetInputEvent)(PT_InputEvent ptInputEvent); /* 获取输入事件函数 */
struct InputOpr *ptNext; /* 下一个输入操作结构体指针 */
}T_InputOpr, *PT_InputOpr;
/* 输入系统初始化 */
int InputInit(void);
/* 注册输入操作 */
int RegisterInputOpr(PT_InputOpr ptInputOpr);
/* 展示已注册的输入操作 */
void ShowInputOpr(void);
/* 初始化所有输入设备 */
int AllInputDevicesInit(void);
/* 获取输入事件 */
int GetInputEvent(PT_InputEvent ptInputEvent);
/* 标准输入设备初始化 */
int StdinInit(void);
/* 触摸屏设备初始化 */
int TouchScreenInit(void);
#endif /* _INPUT_MANAGER_H */
修改touchscreen.c
/*
* TouchScreenDevInit - 初始化触摸屏设备
*
* 此函数用于初始化触摸屏设备,它会尝试从环境变量获取触摸屏设备节点,
* 如果未设置,则使用默认设备节点。需要在SelectAndInitDisplay函数调用之后调用此函数,
* 因为它依赖于LCD的分辨率。
*
* 返回值:
* 0 - 初始化成功
* -1 - 初始化失败
*/
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;
}
/*
* TouchScreenDevExit - 退出触摸屏设备
*
* 此函数用于清理触摸屏设备初始化过程中的资源。
*
* 返回值:
* 0 - 退出成功
*/
static int TouchScreenDevExit(void)
{
return 0;
}
/*
* TouchScreenGetInputEvent - 获取触摸屏输入事件
*
* 从触摸屏设备读取一个输入事件,并将其填充到提供的输入事件结构体中。
*
* 参数:
* ptInputEvent - 指向接收输入事件的结构体的指针。
*
* 返回值:
* 0 - 读取事件成功
* -1 - 读取事件失败
*/
static int TouchScreenGetInputEvent(PT_InputEvent ptInputEvent)
{
struct ts_sample tSamp;
struct ts_sample tSampPressed;
struct ts_sample tSampReleased;
int iRet;
int bStart = 0;
int iDelta;
static struct timeval tPreTime;
// 循环读取触摸屏事件
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;
}
/*
* g_tTouchScreenOpr - 触摸屏操作结构体
*
* 定义了触摸屏操作的相关函数指针和设备名称。
*/
static T_InputOpr g_tTouchScreenOpr = {
.name = "touchscreen",
.DeviceInit = TouchScreenDevInit,
.DeviceExit = TouchScreenDevExit,
.GetInputEvent = TouchScreenGetInputEvent,
};
/*
* TouchScreenInit - 注册触摸屏输入操作
*
* 此函数用于注册触摸屏的输入操作处理函数。
*
* 返回值:
* 0 - 注册成功
* -1 - 注册失败
*/
int TouchScreenInit(void)
{
return RegisterInputOpr(&g_tTouchScreenOpr);
}
-
TouchScreenDevInit
函数用于初始化触摸屏设备。它首先尝试从环境变量获取触摸屏设备节点,如果未设置,则使用默认设备节点。然后打开触摸屏设备,配置设备,获取显示分辨率,并返回初始化结果(0表示成功,-1表示失败)。 -
TouchScreenDevExit
函数用于清理触摸屏设备初始化过程中的资源。该函数目前没有实现具体的功能,始终返回0表示退出成功。 -
TouchScreenGetInputEvent
函数用于从触摸屏设备读取一个输入事件,并将其填充到提供的输入事件结构体中。函数通过循环读取触摸屏事件,读取成功则将事件信息填充到结构体中并返回0,读取失败则返回-1。 -
g_tTouchScreenOpr
是一个静态结构体,定义了触摸屏操作的相关函数指针和设备名称。 -
TouchScreenInit
函数用于注册触摸屏的输入操作处理函数。它调用RegisterInputOpr
函数,并传入g_tTouchScreenOpr
结构体作为参数,以将触摸屏的操作函数注册到系统中。函数返回注册结果(0表示成功,-1表示失败)。
修改输入事件
修改PageAction结构体:
typedef struct PageAction {
char *name;
int (*Run)(void);
int (*GetInputEvent)(PT_Layout atLayout, PT_InputEvent ptInputEvent);
int (*Prepare)(void);
struct PageAction *ptNext;
}T_PageAction, *PT_PageAction;
写主页面的输入捕获事件函数:
/**
* 获取主页面的输入事件
*
* 此函数用于处理主页面上的触摸输入事件,它会分析触摸点是否落在某个按钮上,
* 如果落在按钮上,则返回对应按钮的索引;否则,返回-1。
*
* @param atLayout 指向布局结构体数组的指针,用于描述页面上的按钮布局。
* @param ptInputEvent 指向输入事件结构体的指针,用于存储获取的输入事件。
* @return 如果成功获取到输入事件且事件类型为触摸屏类型,则返回触点所在的按钮索引;
* 如果事件类型不是触摸屏类型或触点没有落在任何按钮上,返回-1。
*/
int MainPageGetInputEvent(PT_Layout atLayout, PT_InputEvent ptInputEvent)
{
T_InputEvent tInputEvent;
int iRet;
int i = 0;
/* 从输入管理器获取原始触摸屏事件 */
iRet = GetInputEvent(&tInputEvent);
if (iRet)
{
return -1; // 获取输入事件失败
}
// 检查事件类型是否为触摸屏类型
if (tInputEvent.iType != INPUT_TYPE_TOUCHSCREEN)
{
return -1; // 事件类型不是触摸屏
}
*ptInputEvent = tInputEvent; // 将获取的输入事件赋值给传入的结构体
/* 处理触摸事件,判断触点是否落在某个按钮的区域中 */
while (atLayout[i].strIconName)
{
// 判断触点是否在当前按钮的边界内
if ((tInputEvent.iX >= atLayout[i].iTopLeftX) && (tInputEvent.iX <= atLayout[i].iBotRightX) \
(tInputEvent.iY >= atLayout[i].iTopLeftY) && (tInputEvent.iY <= atLayout[i].iBotRightY))
{
// 找到被触点命中的按钮
return i;
}
else
{
i++; // 继续检查下一个按钮
}
}
/* 触点没有落在任何按钮上 */
return -1;
}
写处理主页面的输入捕获事件流程处理
/* 3. 调用GetInputEvent获得输入事件,进而处理 */
while (1)
{
iIndex = MainPageGetInputEvent(g_atMainPageLayout, &tInputEvent);
if (tInputEvent.iPressure == 0)
{
/* 如果是松开 */
if (bPressed)
{
/* 曾经有按钮被按下 */
ReleaseButton(&g_atMainPageLayout[iIndexPressed]);
bPressed = 0;
iIndexPressed = -1;
}
}
else
{
/* 按下状态 */
if (iIndex != -1)
{
if (!bPressed)
{
/* 未曾按下按钮 */
bPressed = 1;
iIndexPressed = iIndex;
PressButton(&g_atMainPageLayout[iIndexPressed]);
}
}
}
}
判断输入事件类型:
-
松开事件:
if (tInputEvent.iPressure == 0)
当检测到输入事件的压力值为0时,认为用户已松开(抬起手指)。-
释放按钮:
if (bPressed)
如果之前有按钮处于按下状态(由标志变量bPressed
记录),则执行以下操作:- 调用ReleaseButton函数释放之前按下(索引为iIndexPressed)的按钮,将其视觉效果恢复至未按下状态。然后将标志变量bPressed置为0,表示当前无按钮被按下,并将iIndexPressed重置为-1。
-
-
按下事件:
else
(即当tInputEvent.iPressure != 0
时,认为用户正在按下)-
判断有效索引:
if (iIndex != -1)
如果返回的索引iIndex
不为-1,表示触发事件的是有效的按钮。 -
处理首次按下:
if (!bPressed)
如果之前没有按钮被按下(bPressed
为0),执行以下操作:- 将标志变量bPressed置为1,表示已有按钮被按下;将iIndexPressed设置为当前触发事件的按钮索引iIndex。接着调用PressButton函数处理按钮按下事件,更新按钮的视觉效果以体现被按下的状态。
-
翻转按钮
/*
* 函数名称:InvertButton
* 功能描述:将指定区域内的按钮图像颜色取反,实现按钮按下时的视觉效果。
* 参数列表:
* - ptLayout: 指向一个PT_Layout结构体的指针,该结构体包含了按钮在屏幕上的布局信息。
* 返回值:无。
*/
static InvertButton(PT_Layout ptLayout)
{
int iX;
int iY;
int i;
unsigned char *pucVideoMem;
PT_DispOpr ptDispOpr = GetDefaultDispDev(); // 获取默认显示设备的操作接口
// 计算按钮图像在Framebuffer中的起始地址
pucVideoMem = ptDispOpr->pucDispMem;
pucVideoMem += ptLayout->iTopLeftY * ptDispOpr->iLineWidth + ptLayout->iTopLeftX * ptDispOpr->iBpp / 8;
// 遍历按钮图像的每个像素,将其颜色取反
for (iY = ptLayout->iTopLeftY; iY <= ptLayout->iBotRightY; iY++)
{
for (iX = ptLayout->iTopLeftX, i = 0; iX <= ptLayout->iBotRightX; iX++, i++)
{
pucVideoMem[i] = ~pucVideoMem[i]; /* 取反 */
}
pucVideoMem += ptDispOpr->iLineWidth; // 根据行宽度移动到下一行的起始位置
}
}
/**
* 释放按钮的资源或改变按钮状态。
* @param ptLayout 指向布局结构体的指针,该结构体中包含了按钮的相关信息。
* 该函数通过调用InvertButton函数来实现按钮状态的反转,用以模拟按钮被释放的效果。
*/
void ReleaseButton(PT_Layout ptLayout)
{
InvertButton(ptLayout); // 反转按钮状态
}