Loading

数码相框-主界面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); // 反转按钮状态
}

posted @ 2024-04-12 15:10  阿四与你  阅读(29)  评论(0编辑  收藏  举报