Freigeben über


Erkennen und Nachverfolgen mehrerer Touchpunkte

In den folgenden Schritten wird erläutert, wie Sie mehrere Touchpunkte mithilfe von Windows Touch nachverfolgen.

  1. Erstellen Sie eine Anwendung, und aktivieren Sie Windows Touch.
  2. Fügen Sie einen Handler für WM_TOUCH hinzu und verfolgen Sie Punkte.
  3. Zeichnen Sie die Punkte.

Nachdem Sie Ihre Anwendung ausgeführt haben, werden Kreise unter jeder Berührung angezeigt. Der folgende Screenshot zeigt, wie Ihre Anwendung während der Ausführung aussehen kann.

Screenshot einer Anwendung, die Berührungspunkte als grüne und gelbe Kreise rendert

Erstellen einer Anwendung und Aktivieren von Windows Touch

Beginnen Sie mit einer Microsoft Win32-Anwendung mit dem Microsoft Visual Studio-Assistenten. Nachdem Sie den Assistenten abgeschlossen haben, fügen Sie Unterstützung für Windows Touch-Nachrichten hinzu, indem Sie die Windows-Version in targetver.h festlegen und windows.h sowie windowsx.h in Ihre Anwendung einbinden. Der folgende Code zeigt, wie die Windows-Version in targetver.h festgelegt wird.

#ifndef WINVER                  // Specifies that the minimum required platform is Windows 7.
#define WINVER 0x0601           // Change this to the appropriate value to target other versions of Windows.
#endif

#ifndef _WIN32_WINNT            // Specifies that the minimum required platform is Windows 7.
#define _WIN32_WINNT 0x0601     // Change this to the appropriate value to target other versions of Windows.
#endif     

#ifndef _WIN32_WINDOWS          // Specifies that the minimum required platform is Windows 98.
#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
#endif

#ifndef _WIN32_IE                       // Specifies that the minimum required platform is Internet Explorer 7.0.
#define _WIN32_IE 0x0700        // Change this to the appropriate value to target other versions of IE.
#endif

Der folgende Code zeigt, wie Ihre Include-Anweisungen hinzugefügt werden. Außerdem können Sie einige globale Variablen erstellen, die später verwendet werden.

#include <windows.h>    // included for Windows Touch
#include <windowsx.h>   // included for point conversion

#define MAXPOINTS 10

// You will use this array to track touch points
int points[MAXPOINTS][2];

// You will use this array to switch the color / track ids
int idLookup[MAXPOINTS];


// You can make the touch points larger
// by changing this radius value
static int radius      = 50;

// There should be at least as many colors
// as there can be touch points so that you
// can have different colors for each point
COLORREF colors[] = { RGB(153,255,51), 
                      RGB(153,0,0), 
                      RGB(0,153,0), 
                      RGB(255,255,0), 
                      RGB(255,51,204), 
                      RGB(0,0,0),
                      RGB(0,153,0), 
                      RGB(153, 255, 255), 
                      RGB(153,153,255), 
                      RGB(0,51,153)
                    };

Hinzufügen eines Handlers für WM_TOUCH und das Verfolgen von Punkten

Deklarieren Sie zunächst einige Variablen, die vom WM_TOUCH-Handler in WndProc verwendet werden.

int wmId, wmEvent, i, x, y;

UINT cInputs;
PTOUCHINPUT pInputs;
POINT ptInput;   

Initialisieren Sie nun die Variablen, die zum Speichern von Touchpunkten verwendet werden, und registrieren Sie das Fenster für die Toucheingabe aus der InitInstance-Methode .

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

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

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd) {
      return FALSE;
   }

   // register the window for touch instead of gestures
   RegisterTouchWindow(hWnd, 0);  

   // the following code initializes the points
   for (int i=0; i< MAXPOINTS; i++){
     points[i][0] = -1;
     points[i][1] = -1;
     idLookup[i]  = -1;
   }  

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

   return TRUE;
}

Behandeln Sie als Nächstes die WM_TOUCH Nachricht aus der WndProc-Methode . Der folgende Code zeigt eine Implementierung des Handlers für WM_TOUCH.

case WM_TOUCH:        
  cInputs = LOWORD(wParam);
  pInputs = new TOUCHINPUT[cInputs];
  if (pInputs){
    if (GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs, sizeof(TOUCHINPUT))){
      for (int i=0; i < static_cast<INT>(cInputs); i++){
        TOUCHINPUT ti = pInputs[i];
        index = GetContactIndex(ti.dwID);
        if (ti.dwID != 0 && index < MAXPOINTS){                            
          // Do something with your touch input handle
          ptInput.x = TOUCH_COORD_TO_PIXEL(ti.x);
          ptInput.y = TOUCH_COORD_TO_PIXEL(ti.y);
          ScreenToClient(hWnd, &ptInput);
          
          if (ti.dwFlags & TOUCHEVENTF_UP){                      
            points[index][0] = -1;
            points[index][1] = -1;

            // Remove the old contact index to make it available for the new incremented dwID.
            // On some touch devices, the dwID value is continuously incremented.
            RemoveContactIndex(index);                
          }else{
            points[index][0] = ptInput.x;
            points[index][1] = ptInput.y;                
          }
        }
      }

      InvalidateRect(hWnd, NULL, FALSE);
    }
    // If you handled the message and don't want anything else done with it, you can close it
    CloseTouchInputHandle((HTOUCHINPUT)lParam);
    delete [] pInputs;
  }else{
    // Handle the error here 
  }  

Hinweis

Um die ScreenToClient-Funktion verwenden zu können, müssen Sie in Ihrer Anwendung hohe DPI-Unterstützung haben. Weitere Informationen zur Unterstützung von hohen DPI-Werten finden Sie unter "Hoher DPI-Wert".

Wenn ein Benutzer nun den Bildschirm berührt, werden die Positionen, die er berührt, im Punktarray gespeichert. Das dwID-Element der TOUCHINPUT-Struktur speichert einen Bezeichner, der hardwareabhängig ist.

Um das Problem des dwID-Members zu beheben, das von der Hardware abhängig ist, verwendet der WM_TOUCH Fallhandler eine Funktion, GetContactIndex, die das dwID-Element der TOUCHINPUT-Struktur einem Punkt zuordnet, der auf dem Bildschirm gezeichnet wird. Der folgende Code zeigt eine Implementierung dieser Funktion.

// This function is used to return an index given an ID
int GetContactIndex(int dwID){
  for (int i = 0; i < MAXPOINTS; i++) {
      if (idLookup[i] == dwID) {
          return i;
      }
  }

  for (int i = 0; i < MAXPOINTS; i++) {
      if (idLookup[i] == -1) {
          idLookup[i] = dwID;
          return i;
      }
  }
  // Out of contacts
  return -1;
}

// Mark the specified index as initialized for new use
BOOL RemoveContactIndex(int index) {
    if (index >= 0 && index < MAXPOINTS) {
        idLookup[index] = -1;
        return true;
    }

    return false;
}

Von Bedeutung

Windows 11 und höher

Einige Interaktionen mit drei und vier Fingern funktionieren in Windows-Apps standardmäßig nicht mehr.

Standardmäßig werden nun Drei- und Vier-Finger-Touch-Interaktionen vom System für Vorgänge wie das Umschalten oder Minimieren von Fenstern und das Wechseln von virtuellen Desktops verwendet. Da diese Interaktionen jetzt auf Systemebene behandelt werden, kann die Funktionalität Ihrer App von dieser Änderung betroffen sein.

Um Interaktionen mit drei oder vier Fingern innerhalb einer Anwendung zu unterstützen, wurde eine neue Benutzereinstellung eingeführt, die angibt, ob das System diese Interaktionen verarbeitet oder nicht:

Bluetooth & Geräte > Touch > „Drei- und Vierfinger-Touchgesten“

Bei Festlegung auf „Ein“ (Standardeinstellung) behandelt das System alle Interaktionen mit drei und vier Fingern (Apps können sie nicht unterstützen).

Bei Festlegung auf „Aus“ können Interaktionen mit drei und vier Fingern von Apps unterstützt werden (sie werden nicht vom System behandelt).

Wenn Ihre Anwendung diese Interaktionen unterstützen muss, wird empfohlen, Die Benutzer über diese Einstellung zu informieren und einen Link bereitzustellen, über den Windows-Einstellungen auf der relevanten Seite gestartet werden (ms-settings:devices-touch). Weitere Informationen finden Sie unter Launcher.LaunchUriAsync-Methode.

Zeichnen der Punkte

Deklarieren Sie die folgenden Variablen für die Zeichnungsroutine.

    // For double buffering
    static HDC memDC       = 0;
    static HBITMAP hMemBmp = 0;
    HBITMAP hOldBmp        = 0;
   
    // For drawing / fills
    PAINTSTRUCT ps;
    HDC hdc;
    HBRUSH hBrush;
    
    // For tracking dwId to points
    int index;

Der MemDC-Speicheranzeigekontext wird zum Speichern eines temporären Grafikkontexts verwendet, der mit dem gerenderten Anzeigekontext, hdc, ausgetauscht wird, um Flackern zu vermeiden. Implementieren Sie die Zeichnungsroutine, die die gespeicherten Punkte verwendet und an diesen Punkten Kreise zeichnet. Der folgende Code zeigt, wie Sie den WM_PAINT-Handler implementieren können.

  case WM_PAINT:
    hdc = BeginPaint(hWnd, &ps);    
    RECT client;
    GetClientRect(hWnd, &client);        
  
    // start double buffering
    if (!memDC){
      memDC = CreateCompatibleDC(hdc);
    }
    hMemBmp = CreateCompatibleBitmap(hdc, client.right, client.bottom);
    hOldBmp = (HBITMAP)SelectObject(memDC, hMemBmp);          

    hBrush = CreateSolidBrush(RGB(255, 255, 255));
    FillRect(memDC, &client, hBrush);
    DeleteObject(hBrush);

    //Draw Touched Points                
    for (i=0; i < MAXPOINTS; i++){
      hBrush = CreateSolidBrush(colors[i]);        
      SelectObject( memDC, hBrush);           

      x = points[i][0];
      y = points[i][1];
      if  (x >0 && y>0){              
        Ellipse(memDC, x - radius, y - radius, x+ radius, y + radius);
      }

      DeleteObject(hBrush);
    }
  
    BitBlt(hdc, 0,0, client.right, client.bottom, memDC, 0,0, SRCCOPY);      
    EndPaint(hWnd, &ps);

    SelectObject(memDC, hOldBmp);
    DeleteObject(hMemBmp);

    break;

Wenn Sie Ihre Anwendung ausführen, sollte sie nun ungefähr wie die Abbildung am Anfang dieses Abschnitts aussehen.

Zum Spaß können Sie einige zusätzliche Linien um die Berührungspunkte zeichnen. Das folgende Bildschirmfoto zeigt, wie die Applikation mit einigen zusätzlichen Linien um die Kreise aussehen könnte.

screenshot einer Anwendung, die Berührungspunkte als Kreise mit Linien rendert, die durch die Mittelpunkte verlaufen und die Ränder der Berührungspunkte schneiden

Windows Touch Eingabe