触摸屏手指滑动方向检测

参考:移动应用滑动屏幕方向判断解决方案

 底层芯片驱动就不写了,每款芯片的寄存器不一样,可是最终要获取的东西都是一样的--触摸坐标。

底层芯片驱动提供能返回触摸坐标的接口就行。

中间层触摸检测的思路是:

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();

posted @ 2017-10-07 15:00  酒醉的Tiger  阅读(1428)  评论(0编辑  收藏  举报