2009年6月25日 星期四

Windows 7 Gesture Sample

看完了MSDN中Gesture information的介紹, 我們就開始寫一個簡單的Gesture應用程式 Application,
其功能包含利用手勢對物體旋轉,縮放和平移, 如下圖所示:


放 大


縮 小


旋 轉


平 移


部分程式碼如下所示:

1. 利用SetGestureConfig將某些手勢作開啟或關閉(依程式需求)

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;

g_hInst = hInstance; // Store instance handle in our global variable

hWnd = CreateWindow(g_wszWindowClass, g_wszTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

if (!hWnd)
{
return FALSE;
}

//在預設中rotate手勢是被關閉, 如果你想要rotate手勢, 可以透過GESTURECONFIG來開啟
//GESTURECONFIG的dwWant/dwBlock 可以用來打開或關閉某種手勢, 或是手指的細緻控制, 例如單一手指的pan或兩指的pan; 下面的code, 我們將rotate打開, 並將單一手指的pan給關掉
GESTURECONFIG config = { 0 };
config.dwWant = GC_ROTATE; //打開rotate手勢
config.dwID = GID_ROTATE;
config.dwBlock = 0;

BOOL result = SetGestureConfig(
hWnd,
0,
1,
&config,
sizeof(GESTURECONFIG)
);

config.dwID = GID_PAN;
config.dwWant = GC_PAN;
config.dwBlock = GC_PAN_WITH_GUTTER;
config.dwBlock |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY; //關掉單一手指垂直平移
config.dwBlock |= GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;//關掉單一手指水平移動

result = SetGestureConfig(
hWnd,
0,
1,
&config,
sizeof(GESTURECONFIG)
);


ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

return TRUE;
}


2. 處理WM_GESTURE訊息

LRESULT CALLBACK WndProc(HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;

switch (message)
{
case WM_GESTURE:
// 我們利用GestureEngine class 來處理WM_GESTURE
return g_cGestureEngine.WndProc(hWnd,wParam,lParam);
break;
.....
}


3. 利用GetGestureInfo得到
GESTUREINFO

LRESULT CGestureEngine::WndProc(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
POINT ptZoomCenter;
double k;

// 利用GetGestureInfo函數去取得 GESTUREINFO的資料結構
GESTUREINFO gi;
ZeroMemory(&gi,sizeof(GESTUREINFO));
gi.cbSize = sizeof(GESTUREINFO);
BOOL result = GetGestureInfo((HGESTUREINFO)lParam, &gi)
;

4. 處理平移手勢


// GID_PAN:
// _ptFirst - 兩手指間的中間點
// _dwArguments - 這手勢沒用到

case GID_PAN:
if (gi.dwFlags & GF_BEGIN)
{
_dwID = gi.dwID;
_dwArguments = gi.ullArguments;
_ptFirst.x = gi.ptsLocation.x;
_ptFirst.y = gi.ptsLocation.y;
ScreenToClient(hWnd,&_ptFirst);
break;

}
else
{
// We read the second point of this gesture. It's a middle point
// between fingers in this new position

_ptSecond.x = gi.ptsLocation.x;
_ptSecond.y = gi.ptsLocation.y;
ScreenToClient(hWnd,&_ptSecond);

// We apply move operation the the object
ProcessMove(_ptSecond.x-_ptFirst.x,_ptSecond.y-_ptFirst.y);

InvalidateRect(hWnd,NULL,TRUE);

// We have to copy second point into first one to prepare
// for next pan message.
_ptFirst.x = _ptSecond.x;
_ptFirst.y = _ptSecond.y;

}
fGHandled = TRUE;
break;



5. 處理縮放手勢

// GID_ZOOM:
// _ptFirst - 兩手指間的中間點
// _dwArguments - 兩手指間的距離
case GID_ZOOM:
if (gi.dwFlags & GF_BEGIN)
{

_dwID = gi.dwID;
_dwArguments = gi.ullArguments;
_ptFirst.x = gi.ptsLocation.x;
_ptFirst.y = gi.ptsLocation.y;
ScreenToClient(hWnd,&_ptFirst);

break;
}
else if (gi.dwFlags & GF_END)
{
//at end of gesture, zero the arguments
_dwArguments = 0;
}
else
{
// We read here the second point of the gesture. This is middle point between
// fingers in this new position.
_ptSecond.x = gi.ptsLocation.x;
_ptSecond.y = gi.ptsLocation.y;
ScreenToClient(hWnd,&_ptSecond);

// We have to calculate zooming center point and coefficient of straching
// _dwArguments holds the old distance between two fingers and new
// distance is stored in gi.dwArguments
ptZoomCenter.x = (_ptFirst.x + _ptSecond.x)/2;
ptZoomCenter.y = (_ptFirst.y + _ptSecond.y)/2;
k = (double)gi.ullArguments/_dwArguments; //縮放比例

// Now we process zooming in/out of object
ProcessZoom(k,ptZoomCenter.x,ptZoomCenter.y);

InvalidateRect(hWnd,NULL,TRUE);

// Now we have to store new information as a starting information
// for next step in this gesture.
_ptFirst.x = _ptSecond.x;
_ptFirst.y = _ptSecond.y;
_dwArguments = gi.ullArguments;
}

fGHandled = TRUE;

break;


6. 處理旋轉手勢

// GID_ROTATE:
// _ptFirst - 旋轉中心 (兩手指旋轉時, 位置變化比較少的手指)
// _dwArguments - 初始角度

case GID_ROTATE:
if (gi.dwFlags & GF_BEGIN)
{
_dwID = gi.dwID;
_dwArguments = gi.ullArguments;
_ptFirst.x = gi.ptsLocation.x;
_ptFirst.y = gi.ptsLocation.y;
ScreenToClient(hWnd,&_ptFirst);
ProcessRotate(ArgToRadians(gi.ullArguments),_ptFirst.x,_ptFirst.y);
InvalidateRect(hWnd,NULL,TRUE);

}
else
{

ProcessRotate(ArgToRadians(gi.ullArguments-_dwArguments),_ptFirst.x,_ptFirst.y);
InvalidateRect(hWnd,NULL,TRUE);
_dwArguments = gi.ullArguments;

}

fGHandled = TRUE;

break;

2 則留言:

  1. Dear Johnnie,

    我們是CTimes, 目前已開很多觸控課程或活動,
    (http://www.ctimes.com.tw/cf/default.asp)
    有可能請你開課講授Windows 7 Touch SDK嗎?
    請與我聯絡~

    Owen 0922 309 767, ou.owen@gmail.com

    回覆刪除
  2. 請問方便給我完整的程式碼嗎?
    寄到我信箱也可以~非常感謝
    chihchianglu@gmail.com

    回覆刪除