1. 程式人生 > >C WinForm 開發Windows7多點觸控(Multi-Touch)應用程式

C WinForm 開發Windows7多點觸控(Multi-Touch)應用程式

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

 多點觸控(Multi Touch)是微軟新一代作業系統Windows 7較受關注的特點之一,本文將使用Visual C# 2008建立一個Windows Form應用程式,並說明如何取得觸控動作相關資訊。 



 在Windows 7的Home Premium、Professional、Enterprise和Ultimate版本中,只要搭配支援多點觸控的硬體即可使用多點觸控功能。而應用程式方面,對觸控的支援則可分為三個等級:Good、Better和Best(請參考表1)。 

Good等級表示不需要修改程式碼可直接支援數個基本的手勢;Better等級要能針對各種不同的手勢做出合理自然的互動;Best等級則是使用更進階的功能處理更詳細的資訊,自訂各種觸控操作經驗。 
Windows 7支援的手勢有9種(參考表2),我們可以看到除了Rotate和Two-Finger Tap之外,其餘手勢都可以對應到傳統的滑鼠或鍵盤的操作,也就是說應用程式不需大幅修改既有的程式,即可支援Windows 7大部分的手勢,然而你也可以在程式中重新定義這些手勢所對應的動作。 


如何取得裝置資訊? 
在開始處理觸控動作前,你可以呼叫GetSystemMetrics並傳入SM_DIGITIZER來得知目前電腦的觸控支援能力(參考程式1),根據GetSystemMetrics的傳回值,即可得知相關資訊(參考表3)。若你沒有適當的觸控硬體,可以使用Multi-Touch Vista這個軟體搭配2隻滑鼠模擬2點輸入。 
程式1

const int SM_DIGITIZER = 94;[DllImport("user32")]static extern int GetSystemMetrics(int n);bool SupportMultiTouch()int
r = GetSystemMetrics(SM_DIGITIZER);  if ((r & 0x40) != 0)    return trueelse    return false;}



如何取得觸控訊息? 
為了支援觸控動作,Windows 7定義了2個新的視窗訊息:WM_GESTURE與WM_TOUCH。Windows 7中的視窗預設只會收到WM_GESTURE訊息,若呼叫了RegisterTouchWindow之後則會變成只會收到WM_TOUCH訊息,然而本文將專注於探討WM_GESTURE訊息。 

由於目前的WinForm尚未將這2個訊息轉換為控制項的事件,所以為了處理這2個訊息,最直接的方式就是覆寫控制項的WndProc方法。在本文的範例中,我們覆寫Form的WndProc方法,如此便能處理表單上的觸控動作(參考程式2)。

程式2

override void WndProc(ref Message m)bool handled = trueswitch (m.Msg)  {    case WM_GESTURENOTIFY:      //  可在此呼叫SetGestureConfig      break;    case WM_TABLET_QUERYSYSTEMGESTURESTATUS:      // 可在此決定是否停用Flicks或其他功能      break;    case WM_GESTURE:      handled = DecodeGesture(ref m);      break;    default:      handled = false;      break;  }  if (handled)    m.Result = new IntPtr(1);  else    base.WndProc(ref m);}

若你要讓其他控制項支援觸控動作,則必須另外繼承該控制項,並覆寫其WndProc方法,或是在表單的WndProc方法中實作判斷觸控目的控制項的邏輯。 
在收到一個手勢的第一個WM_GESTURE訊息前,程式會先收到一個WM_GESTURENOTIFY訊息,你可以在此時呼叫SetGestureConfig並帶入GESTURECONFIG結構,設定目前要接受或忽略哪些手勢。 
也可以在視窗一載入時就先設定好(參考程式3)。視窗預設不會收到關於Rotate手勢的訊息,若想收到所有手勢的訊息則必須呼叫 SetGestureConfig 做設定,詳細的設定專案請參考:http://msdn.microsoft.com/library/dd353241.aspx

程式3

GESTURECONFIG gc = new GESTURECONFIG();gc.dwID = 0;gc.dwWant = GC_ALLGESTURES;gc.dwBlock = 0; SetGestureConfig(this.Handle, 0, 1, ref gc, _gestureConfigSize);

如何解讀觸控資訊? 
在手勢作用的過程中成是會收到多個WM_GESTURE訊息,其所帶的引數可用來取得GESTUREINFO結構(參考程式4),其中比較重要的部分是dwFlags、dwID、ptsLocation以及ullArguments。dwID可用來分辨是哪種手勢(參考表4),dwFlags表示手勢的狀態(開始、慣性動作、停止),ptsLocation及ullArguments則根據不同的手勢有不同的意義,詳細資訊請參考:http://msdn.microsoft.com/library/dd353242.aspx 
程式4

[StructLayout(LayoutKind.Sequential)]struct GESTUREINFO{  public int cbSize;  public int dwFlags; // GF_*  public int dwID; // GID_*  public IntPtr hwndTarget;  [MarshalAs(UnmanagedType.Struct)]  internal POINTS ptsLocation;  public int dwInstanceID;  public int dwSequenceID;  public Int64 ullArguments;  public int cbExtraArgs;}


在此我們只看到5種Gesture ID,但前文卻提到了9種手勢,這是因為Flicks (筆觸,根據滑動方向提供一組功能)是對應到Pan手勢或鍵盤動作,而其他3種手勢只會引發單純的滑鼠事件。在滑鼠事件處理常式中,利用GetMessageExtraInfo可得知事件是由滑鼠還是觸控所產生,進而做不同的處理(參考程式5)。 
程式5

const uint MOUSEEVENTF_FROMTOUCH = 0xff515700;[DllImport("user32")]static extern IntPtr GetMessageExtraInfo();bool IsFromTouch(){  IntPtr p = GetMessageExtraInfo();  return MOUSEEVENTF_FROMTOUCH == ((uint)p & MOUSEEVENTF_FROMTOUCH);}

本文中的範例會於收到WM_GESTURE訊息時,在DecodeGesture方法中利用GetGestureInfo來取得與手勢相關的GESTUREINFO結構,並根據不同的手勢做對應的動作(參考程式6)。需注意的是,處理完之後必須呼叫CloseGestureInfoHandle關閉GESTUREINFO的handle,否則會造成記憶體遺漏。 
程式6

[DllImport("user32")][return: MarshalAs(UnmanagedType.Bool)]static extern bool GetGestureInfo(IntPtr hGestureInfo, ref GESTUREINFO pGestureInfo);[DllImport("user32")][return: MarshalAs(UnmanagedType.Bool)]static extern bool CloseGestureInfoHandle(IntPtr hGestureInfo);bool DecodeGesture(ref Message m)bool handled = true;  GESTUREINFO gi;  gi = new GESTUREINFO();  gi.cbSize = _gestureInfoSize;  GetGestureInfo(m.LParam, ref gi);  switch (gi.dwID)  {    case GID_ZOOM: //處理縮放      break;    case GID_PAN: //處理平移      break;    case GID_ROTATE: //處理旋轉      break;    case GID_TWOFINGERTAP: //處理兩指點選      break;    case GID_PRESSANDTAP: //處理press & tap      break;    default:      handled = false;      break;  }  if (handled)    CloseGestureInfoHandle(m.LParam);  return handled;}

處理Pan手勢的小技巧 
在處理Pan手勢時,為了避免Windows將手勢誤判為Flicks,造成不良的使用經驗,最好暫時關閉Flicks的功能。此動作可以在控制項載入時就呼叫SetProp進行設定(參考程式7),或是在WndProc中收到WM_TABLET_QUERYSYSTEMGESTURESTATUS訊息時設定m.Result為TABLET_DISABLE_FLICKS(參考程式8)。其他可設定的專案請參考http://msdn.microsoft.com/en-us/library/bb969148.aspx 
程式7

[DllImport("user32")]static extern bool SetProp(IntPtr hWnd, string lpString, IntPtr hData);SetProp(this.Handle, "MicrosoftTabletPenServiceProperty", new IntPtr(0x10000));


程式8

const int TABLET_DISABLE_FLICKS = 0x00010000;case WM_TABLET_QUERYSYSTEMGESTURESTATUS:  m.Result = (IntPtr)TABLET_DISABLE_FLICKS;  break;

結語 
瞭解以上處理WM_GESTURE訊息的方式之後,即可試著閱讀並修改Windows 7 SDK中的MTGestures範例程式。該範例會在表單上繪製一個長方形,並依據不同的手勢對表單上的長方形做出不同的動作(參考圖1)。 

           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述