触摸屏手指滑动方向检测
底层芯片驱动就不写了,每款芯片的寄存器不一样,可是最终要获取的东西都是一样的--触摸坐标。
底层芯片驱动提供能返回触摸坐标的接口就行。
中间层触摸检测的思路是:
1、判断是否有手指触点,当手指触点>=1,进入有手指触点处理,否则进入无手指触点处理;
2、有手指触点处理:首先判断当前触点与上一个触点是否在误差范围内(#define TP_ERR_RANGE 20);
a、在误差范围内并且在防抖时间之外,则确认为手指按下状态;
b、不在误差范围内并且在防抖时间之外,如果上一状态为手指按下状态,则为手指滑动ing状态;否则不做处理,使相应变量及状态复位;
3、无手指触点处理:在有手指触点处理进入到无手指触点处理的第一次为手指松开状态处理;
a、手指松开的坐标与手指按下时的坐标在在误差范围内,确认为手指松开状态;
b、手指松开的坐标与手指按下时的坐标在在误差范围内,确认为手指滑动状态;
最终通过接口返回给应用层4种状态:手指按下,手指松开,手指滑动中,手指滑动。
滑动方向检测的核心在于方向的判断:
#include "math.h" #define PI 3.1415926f //返回角度 float GetSlideAngle(int dx, int dy) { /* atan2()接受两个参数x和y: angel=Math.atan2(y,x) x 指定两个点横坐标的差 y 指定两个点纵坐标的差 计算出来的结果angel是一个弧度值,要换算成角度,也必须乘以180/PI。 */ return(atan2(dy, dx) * 180 / PI); } //根据起点和终点返回方向 1:向上,2:向下,3:向左,4:向右, 0:未滑动 MMP_UBYTE GetSlideDirection(MMP_USHORT startX, MMP_USHORT startY, MMP_USHORT endX, MMP_USHORT endY) { MMP_UBYTE result = TP_SlideDirection_NONE; int dy = startY - endY; int dx = endX - startX; float angle; //如果滑动距离太短 if (abs(dx) < 2 && abs(dy) < 2) { return result; } angle = GetSlideAngle(dx, dy); if (angle >= -45 && angle < 45) { result = TP_SlideDirection_RIGHT;// 4; } else if (angle >= 45 && angle < 135) { result = TP_SlideDirection_UP;// 1; } else if (angle >= -135 && angle < -45) { result = TP_SlideDirection_DOWN;// 2; } else if ((angle >= 135 && angle <= 180) || (angle >= -180 && angle < -135)) { result = TP_SlideDirection_LEFT;// 3; } return result; }
注意:没有 #include "math.h" 也能编译通过,却不能产生正确的结果。
TouchPanel.c
#include "math.h" #define PI 3.1415926f #define TP_ERR_RANGE 20 //误差范围 STPBUTTON TPButton = {TOUCH_PANEL_PRESS, TOUCH_PANEL_REL, 0, 15, KEYPAD_NONE, 0, 0, 0, 0, TP_ERR_RANGE, "TouchPanel"}; //返回角度 float GetSlideAngle(int dx, int dy) { /* atan2()接受两个参数x和y: angel=Math.atan2(y,x) x 指定两个点横坐标的差 y 指定两个点纵坐标的差 计算出来的结果angel是一个弧度值,要换算成角度,也必须乘以180/PI。 */ return(atan2(dy, dx) * 180 / PI); } //根据起点和终点返回方向 1:向上,2:向下,3:向左,4:向右, 0:未滑动 MMP_UBYTE GetSlideDirection(MMP_USHORT startX, MMP_USHORT startY, MMP_USHORT endX, MMP_USHORT endY) { MMP_UBYTE result = TP_SlideDirection_NONE; int dy = startY - endY; int dx = endX - startX; float angle; //如果滑动距离太短 if (abs(dx) < 2 && abs(dy) < 2) { return result; } angle = GetSlideAngle(dx, dy); if (angle >= -45 && angle < 45) { result = TP_SlideDirection_RIGHT;// 4; } else if (angle >= 45 && angle < 135) { result = TP_SlideDirection_UP;// 1; } else if (angle >= -135 && angle < -45) { result = TP_SlideDirection_DOWN;// 2; } else if ((angle >= 135 && angle <= 180) || (angle >= -180 && angle < -135)) { result = TP_SlideDirection_LEFT;// 3; } return result; } AHC_BOOL AHC_TouchPanel_CheckUpdate(MMP_ULONG* pulKeyEvent, MMP_ULONG* pulPosition, MMP_UBYTE dir, MMP_UBYTE* finger, MMP_UBYTE* pucSlideDirection) { MMP_ERR status = MMP_ERR_NONE; static MMP_ULONG ulPosition = 0; MMP_ULONG ulNow; if (*pulKeyEvent == TOUCH_PANEL_PRESS || *pulKeyEvent == TOUCH_PANEL_REL || *pulKeyEvent == TOUCH_PANEL_MOVE) { // Read position MMP_USHORT uwX = 0; MMP_USHORT uwY = 0; UINT16 x1, y1;//last pos UINT16 x2, y2;//now pos *finger = AHC_TouchPanel_ReadPosition(&uwX, &uwY, dir); *pulKeyEvent = KEYPAD_NONE; MMPF_OS_GetTime(&ulNow); if (*finger != 0) { x1 = TPButton.uwLastPosX; y1 = TPButton.uwLastPosY; x2 = uwX; y2 = uwY; if ((((x2 <= x1) && (x1 < x2 + TPButton.uwErrRange)) || ((x1 <= x2) && (x2 < x1 + TPButton.uwErrRange))) && \ (((y2 <= y1) && (y1 < y2 + TPButton.uwErrRange)) || ((y1 <= y2) && (y2 < y1 + TPButton.uwErrRange)))) { //前后两次采样在+-20内 if (ulNow - TPButton.ulKeyLastTime > TPButton.ulDebounceTime) { if (TPButton.ulKeyLastEvent == KEYPAD_NONE) { *pulKeyEvent = TOUCH_PANEL_PRESS; TPButton.ulKeyLastEvent = *pulKeyEvent; TPButton.uwPressPosX = (x1 + x2) >> 1; TPButton.uwPressPosY = (y1 + y2) >> 1; printc("--Harry-- PRESS: xPos = %d, yPos = %d --1\r\n", TPButton.uwPressPosX, TPButton.uwPressPosY); } TPButton.uwLastPosX = x2; TPButton.uwLastPosY = y2; TPButton.ulKeyLastTime = ulNow; } } else { //前后两次采样大于+-20 if ((ulNow - TPButton.ulKeyLastTime) > (TPButton.ulDebounceTime >> 1)) { //printc("--Harry-- MOVE: xPos = %d, yPos = %d --2\r\n", uwX, uwY); if (TPButton.ulKeyLastEvent == TOUCH_PANEL_PRESS) { #if 0//Moveing x1 = TPButton.uwPressPosX; y1 = TPButton.uwPressPosY; if ((x1 > (x2 + TPButton.uwErrRange * 2)) || (x2 > (x1 + TPButton.uwErrRange * 2)) || \ (y1 > (y2 + TPButton.uwErrRange * 2)) || (y2 > (y1 + TPButton.uwErrRange * 2))) { *pulKeyEvent = TOUCH_PANEL_MOVE; TPButton.ulKeyLastEvent = *pulKeyEvent; TPButton.uwPressPosX = (x1 + x2) >> 1; TPButton.uwPressPosY = (y1 + y2) >> 1; } #endif } else { *pulKeyEvent = KEYPAD_NONE; TPButton.ulKeyLastEvent = *pulKeyEvent; TPButton.uwPressPosX = 0; TPButton.uwPressPosY = 0; } TPButton.uwLastPosX = x2; TPButton.uwLastPosY = y2; TPButton.ulKeyLastTime = ulNow; } } } else { //按键松开 x1 = TPButton.uwPressPosX; y1 = TPButton.uwPressPosY; x2 = TPButton.uwLastPosX; y2 = TPButton.uwLastPosY; if (TPButton.ulKeyLastEvent == TOUCH_PANEL_PRESS) { if ((((x2 <= x1) && (x1 < x2 + TPButton.uwErrRange)) || ((x1 <= x2) && (x2 < x1 + TPButton.uwErrRange))) && \ (((y2 <= y1) && (y1 < y2 + TPButton.uwErrRange)) || ((y1 <= y2) && (y2 < y1 + TPButton.uwErrRange)))) { //按下时的点与松开时的点小于容错范围 *pulKeyEvent = TOUCH_PANEL_REL; uwX = (x1 + x2) >> 1; uwY = (y1 + y2) >> 1; } else { //按下时的点与松开时的点大于容错范围 *pulKeyEvent = TOUCH_PANEL_MOVE; //printc("--Harry-- MOVE: x1=%d, y1=%d x2=%d, y2=%d --22\r\n", x1, y1, x2, y2); *pucSlideDirection = GetSlideDirection(x1, y1, x2, y2); uwX = x2; uwY = y2; } } else { *pulKeyEvent = KEYPAD_NONE; } TPButton.uwLastPosX = 0; TPButton.uwLastPosY = 0; TPButton.uwPressPosX = 0; TPButton.uwPressPosY = 0; TPButton.ulKeyLastTime = ulNow; TPButton.ulKeyLastEvent = *pulKeyEvent; } if (*pulKeyEvent != KEYPAD_NONE) { ulPosition = uwY; ulPosition = (ulPosition << 16) + uwX; *pulPosition = ulPosition; status = AHC_TOUCHPANEL_RET_TRUE; } else { *pulPosition = 0; status = AHC_TOUCHPANEL_RET_FALSE; } } AHC_TOUCHPANEL_CHECK_RETURE_VALUE(status, AHC_TOUCHPANEL_NO_ERROR, AHC_TOUCHPANEL_RET_TRUE, AHC_TOUCHPANEL_RET_FALSE) }
TouchPanel.h
typedef enum { TP_SlideDirection_NONE = 0, TP_SlideDirection_UP, TP_SlideDirection_DOWN, TP_SlideDirection_LEFT, TP_SlideDirection_RIGHT } TP_SlideDirection_Enum; /* For Touch Panel Button */ typedef struct tagTPButton { int iPressId; int iReleaseId; unsigned int ulKeyLastTime; unsigned int ulDebounceTime; unsigned int ulKeyLastEvent; unsigned short uwLastPosX; unsigned short uwLastPosY; unsigned short uwPressPosX; unsigned short uwPressPosY; unsigned short uwErrRange; unsigned char ubkeyname[16]; } STPBUTTON;
应用层通过接口获取中间层所得的触摸状态做相应事件处理。
typedef struct _TP_Position { unsigned short xPos; unsigned short yPos; } TP_Position; /* For Touch Panel Event */ typedef struct _TouchPanel { TP_Position PrevPosition; TP_Position CurrPosition; unsigned char SlideDirection; void (*PressEvent)(void); void (*ReleaseEvent)(void); void (*MoveEvent)(void); } TouchPanelEvent; static TouchPanelEvent TouchPanel; static void TouchPanel_PressEvent(void) { printc("--Harry-- %s Line:%d\r\n", __func__, __LINE__); TouchPanel.PrevPosition.xPos = TouchPanel.CurrPosition.xPos; TouchPanel.PrevPosition.yPos = TouchPanel.CurrPosition.yPos; } static void TouchPanel_ReleaseEvent(void) { printc("--Harry-- %s Line:%d\r\n", __func__, __LINE__); TouchPanel.PrevPosition.xPos = TouchPanel.CurrPosition.xPos; TouchPanel.PrevPosition.yPos = TouchPanel.CurrPosition.yPos; } static void TouchPanel_MoveEvent(void) { //printc("--Harry-- %s Line:%d\r\n", __func__, __LINE__); } static void TouchPanelEventInit(void) { TouchPanel.PrevPosition.xPos = 0; TouchPanel.PrevPosition.yPos = 0; TouchPanel.CurrPosition.xPos = 0; TouchPanel.CurrPosition.yPos = 0; TouchPanel.SlideDirection = 0; TouchPanel.PressEvent = TouchPanel_PressEvent; TouchPanel.ReleaseEvent = TouchPanel_ReleaseEvent; TouchPanel.MoveEvent = TouchPanel_MoveEvent; } void UIKeyTask(void) { MMP_ULONG ulKeyEvent; MMPF_OS_FLAGS flags; MMPF_OS_FLAGS waitflags; MMP_ULONG ulNow; MMP_ULONG ulPosition; #if (KEYPAD_DETECT_METHOD == KEYPAD_DETECT_TASK) UITaskReady = MMP_TRUE; #endif #if (TASK_MONITOR_ENABLE) memcpy(&gsTaskMonitorUIKey.TaskName[0], __func__, TASK_MONITOR_MAXTASKNAMELEN); gsTaskMonitorUIKey.sTaskMonitorStates = MMPF_TASK_MONITOR_STATES_WAITING; gsTaskMonitorUIKey.ulExecTime = 0; memset((void *)gsTaskMonitorUIKey.ParaArray, 0x0, sizeof(gsTaskMonitorUIKey.ParaArray)); gsTaskMonitorUIKey.ulParaLength = 0; gsTaskMonitorUIKey.pTimeoutCB = (TASK_MONITOR_TimeoutCallback *)NULL; MMPF_TaskMonitor_RegisterTask(&gsTaskMonitorUIKey); #endif waitflags = CDV_KEYPAD_FLAG | CDV_TIME_FLAG; #if (UPDATE_UI_USE_MULTI_TASK) waitflags |= CDV_UI_FLAG; #endif #if (SUPPORT_TOUCH_PANEL) TouchPanelEventInit(); #endif while(1){ MMPF_OS_WaitFlags(CDV_UI_Flag, waitflags, MMPF_OS_FLAG_WAIT_SET_ANY|MMPF_OS_FLAG_CONSUME, 0, &flags); #if (TASK_MONITOR_ENABLE) MMPF_OS_GetTime(&gsTaskMonitorUIKey.ulExecTime); gsTaskMonitorUIKey.sTaskMonitorStates = MMPF_TASK_MONITOR_STATES_RUNNING; *(MMP_ULONG *)(gsTaskMonitorUIKey.ParaArray) = (MMP_ULONG)flags; gsTaskMonitorUIKey.ulParaLength = sizeof(MMP_ULONG); #endif if (flags & CDV_TIME_FLAG) { // The KeyTask priority is higher then NETWORK to update Video Time Stamp for better performance. UpdateVideoCurrentTimeStamp(); } #if (UPDATE_UI_USE_MULTI_TASK) if (flags & CDV_UI_FLAG) { DrawStateVideoRecUpdate(EVENT_VIDREC_UPDATE_MESSAGE); } #endif if (flags & CDV_KEYPAD_FLAG) { MMPF_OS_GetTime(&ulNow); GetKeyPadEvent(&ulKeyEvent); #if (SUPPORT_TOUCH_PANEL) if ((ulKeyEvent == TOUCH_PANEL_PRESS) || (ulKeyEvent == TOUCH_PANEL_REL)) { UINT32 dir; MMP_UBYTE finger; MMP_ERR status; MMP_UBYTE slide = 0; AHC_GetParam(PARAM_ID_LCD_STATUS, &dir); status = AHC_TouchPanel_CheckUpdate(&ulKeyEvent, &ulPosition, dir, &finger, &slide); if (ulKeyEvent != KEYPAD_NONE) { if (ulKeyEvent == TOUCH_PANEL_PRESS) { TouchPanel.CurrPosition.xPos = ulPosition & 0x0000FFFF; TouchPanel.CurrPosition.yPos = ulPosition >> 16; TouchPanel.PressEvent(); } else if (ulKeyEvent == TOUCH_PANEL_REL) { TouchPanel.CurrPosition.xPos = ulPosition & 0x0000FFFF; TouchPanel.CurrPosition.yPos = ulPosition >> 16; TouchPanel.ReleaseEvent(); } else if (ulKeyEvent == TOUCH_PANEL_MOVE) { TouchPanel.CurrPosition.xPos = ulPosition & 0x0000FFFF; TouchPanel.CurrPosition.yPos = ulPosition >> 16; TouchPanel.SlideDirection = slide; TouchPanel.MoveEvent(); } ulKeyEvent = KEYPAD_NONE; } } #endif if (ulKeyEvent != KEYPAD_NONE) { AHC_SendAHLMessage(AHLM_GPIO_BUTTON_NOTIFICATION, ulKeyEvent, ulNow); } } #if (TASK_MONITOR_ENABLE) gsTaskMonitorUIKey.sTaskMonitorStates = MMPF_TASK_MONITOR_STATES_WAITING; #endif } }
注意:TouchPanel 事件在调用前必须先初始化 TouchPanelEventInit();