现在的位置: 首页 > 综合 > 正文

Windows 手势识别API .

2018年04月28日 ⁄ 综合 ⁄ 共 4112字 ⁄ 字号 评论关闭

一、背景:还是不得不提及iPhone的伟大创造性工作,用手势识别来操作手机,特别是对于滚动条,想想之前是何等的痛苦,拿着触摸板,在那个只有几个像素的滚动条上又是拉又是点的。在WM6.5没有出来之前,自己也实现过手势识别的引擎,包括方向识别、画圈识别。微软为了大家不至于对他失去信心,还是在6.5上了点点东西。对于开发者来说,其实只要添加了Gesture API 和widget。最近做个新的项目,需要在WM6.5上实现,需要用到Gesture
API,自己学习了下,随便写下来,自己做个备忘。

二、轨迹识别:

当对屏幕有操作时,微软会发送WM_GESTURE消息。wParam是Gesture ID, lParam指向HGESTUREINFO,通过GetGestureInfo得到GESTUREINFO。

BOOL GetGestureInfo(

        HGESTUREINFO hGestureInfo,

        PGESTUREINFO pGestureInfo

);

GESTUREINFO 定义

typedef struct tagGESTUREINFO {

    UINT cbSize;

    DWORD dwFlags;

    DWORD dwID;         // Gesture command ID

        HWND hwndTarget;

    POINTS ptsLocation;

    DWORD dwInstanceID;     // not use

    DWORD dwSequenceID;

    ULONGLONG ullArguments; //

    UINT cbExtraArguments;  //
扩展参数buffer大小

} GESTUREINFO, *PGESTUREINFO;

微软定义了一个Gesture ID

ID

宏定义

意义

1

GID_BEGIN

按下时发送,与GID_END成对出现

2

GID_END

抬起,与GID_BEGIN成对出现

4

GID_PAN

移动的

5

GID_SCROLL

只有当加速滑动的时候,会产生GID_SCROLL

9

GID_HOLD

按住不动一定时间

10

GID_SELECT

单击,并马上弹起

11

GID_DOUBLESELECT

双击

在GID_SCROLL、GID_HOLD、GID_SELECT、GID_DOUBLESELECT这四个为连续的数值,说明四个状态时互质的。很容易明白滚动、选择、双击、长按是不可能同时发生的。

其中GID_SCROLL是相对复杂一些的,滚动我们不仅要知道当前坐标,还需要知道方向、速度和角度。微软在ullArguments保持了这三个信息,并定义了三个宏来从参数ullArguments中得到。

GESTUREINFO gi = {sizeof(gi)};

if (GetGestureInfo(reinterpret_cast<HGESTUREINFO>(lParam), &gi))

{

    static POINT ptsLast = {0};

    switch (wParam)

    {

        case GID_PAN:

        break;

        case GID_SCROLL:

            {

               
// 速度

               
int iVelocity = (int)GID_SCROLL_VELOCITY(gi.ullArguments);

               
// 角度

               
int iAngle = (int)GID_SCROLL_ANGLE(gi.ullArguments);

               
// 方向

               
int iDirection = (int)GID_SCROLL_DIRECTION(gi.ullArguments);

            }

        break;

    }

}

角度的值是从0到65535,代表0到2PI。定义了四个方向

#define ARG_SCROLL_NONE

#define ARG_SCROLL_RIGHT

#define ARG_SCROLL_UP

#define ARG_SCROLL_LEFT

#define ARG_SCROLL_DOWN

通过上面的介绍,我们了解了如何获取手势轨迹。

下面是微软Gesture API,部分API SDK中没有公布,只给OEM公布的。

Function

Description

CloseGestureInfoHandle

This function cleans up any gesture handle that is not processed by DefWindowProc.

DisableGestures

设置指定窗体或者进程Gesture
command ID无效

EnableGestures

设置指定窗体或者进程Gesture
command ID有效

Gesture

This function enables asynchronous recognizers to produce gesture messages.

GetAnimateMessageInfo

Retrieves the animation message associated with flicks or pans for window auto gestures.

GetGestureExtraArguments

得到扩展参数

GetGestureInfo

接收到WM_GESTURE时消息,获取GESTUREINFO信息

GetWindowAutoGesture

Returns the current settings for a window's flick and pan gestures.

QueryGestures

得到指定窗体或者进程所支持的Gesture ID

RegisterGesture

自定义Gesture

RegisterDefaultGestureHandler

接收未处理的WM_GESTURE消息

SetWindowAutoGesture

自动处理Gesture消息

三、滑动

一般情况下在GID_PAN和GID_ SCROLL处理滑动。GID_PAN处理拖动,GDI_SCROLL处理滑动。GID_PAN时,只要处理每次位移是多少就可以了。然后刷新窗体。GID_SCROLL需要调用

CreatePhysicsEngine来设置负的加速度,使其最终停下来。然后再设置一个TIMER去,在TIMER处理函数中用QueryPhysicsEngine去得到移动的相对位移。然后计算,重新刷新。

SDK参考代码:

HRESULT hr = S_OK;

//int nYExtendedPan = 0;

//int nXExtendedPan = 0;

PHYSICSENGINEINIT initState = {sizeof(initState)};

RECT rctClient = {0};

 

initState.dwEngineType             
= 0;

initState.dwFlags               
   = 0;

initState.lInitialVelocity         
= -nTransitionSpeed;    // 设置初始速度

initState.dwInitialAngle           
= nTransitionAngle; // 设置角度

initState.bXAxisMovementMode       
= PHYSICSENGINE_MOVEMENT_MODE_DECELERATE;

initState.bYAxisMovementMode       
= PHYSICSENGINE_MOVEMENT_MODE_DECELERATE;

initState.bXAxisBoundaryMode       
= PHYSICSENGINE_BOUNDARY_MODE_RUBBERBAND;

initState.bYAxisBoundaryMode       
= PHYSICSENGINE_BOUNDARY_MODE_RUBBERBAND;

GetClientRect(hwnd, &rctClient);

initState.rcBoundary.left   
       = 0;

initState.rcBoundary.right         
= rctClient.right + g_nMaxXExtent;  // 设置边界

initState.rcBoundary.top           
= 0;

initState.rcBoundary.bottom        
= rctClient.bottom + g_nMaxYExtent; // 设置边界

initState.sizeView.cx              
= rctClient.right;

initState.sizeView.cy              
= rctClient.bottom;

initState.ptInitialPosition.x      
= g_nXPos;

initState.ptInitialPosition.y      
= g_nYPos;

initState.sizeItem.cx              
= 1;      

initState.sizeItem.cy              
= 1;      

 

// create the physics engine and store it

if (SUCCEEDED(CreatePhysicsEngine(&initState, &g_hPhysicsEngine)))

{

    g_fAnimating = true; // we are now animating

    // Setup the timer

    g_uTimerId = SetTimer(  hwnd,

        GESTURE_ANIMATION_TIMER_ID,

        20,

        AnimationTimerProc);

}

 

OK,终于写完了,有什么不对的地方,请指正。

抱歉!评论已关闭.