Поделиться через


Обнаружение и отслеживание нескольких точек касания

Ниже описано, как отслеживать несколько точек касания с помощью Windows Touch.

  1. Создайте приложение и включите Windows Touch.
  2. Добавьте обработчик для WM_TOUCH и отслеживания точек.
  3. Рисование точек.

После запуска приложения будут отображаться круги под каждым касанием. На следующем снимке экрана показано, как может выглядеть приложение во время выполнения.

screen shot showing an application that renders touch points as green and yellow circles

Создание приложения и включение Windows Touch

Начните с приложения Microsoft Win32 с помощью мастера Microsoft Visual Studio. После завершения работы мастера добавьте поддержку сообщений Windows Touch, задав версию Windows в targetver.h и включая windows.h и windowsx.h в приложении. В следующем коде показано, как задать версию Windows в targetver.h.

#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

В следующем коде показано, как следует добавлять директивы включения. Кроме того, можно создать некоторые глобальные переменные, которые будут использоваться позже.

#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)
                    };

Добавление обработчика для WM_TOUCH и точек отслеживания

Сначала объявите некоторые переменные, используемые обработчиком WM_TOUCH в WndProc.

int wmId, wmEvent, i, x, y;

UINT cInputs;
PTOUCHINPUT pInputs;
POINT ptInput;   

Теперь инициализируйте переменные, используемые для хранения точек касания, и зарегистрируйте окно для сенсорного ввода из метода InitInstance .

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;
}

Затем обработайте сообщение WM_TOUCH из метода WndProc. В следующем коде показана реализация обработчика для 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 
  }  

Примечание.

Чтобы использовать функцию ScreenToClient , в приложении должна быть высокая поддержка DPI. Дополнительные сведения о поддержке высокого уровня DPI см. в разделе "Высокий DPI".

Теперь, когда пользователь прикасается к экрану, позиции, которые он или она касаются, будут храниться в массиве точек. Член dwID структуры TOUCHINPUT хранит идентификатор, который будет зависеть от оборудования.

Для решения проблемы, зависящей от оборудования, обработчик дела WM_TOUCH использует функцию GetContactIndex, которая сопоставляет член dwID структуры TOUCHINPUT с точкой, нарисованной на экране. В следующем коде показана реализация этой функции.

// 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;
}

Важно!

Windows 11 и более поздней версии

По умолчанию в приложениях Windows больше не будут работать некоторые три и четыре пальца.

По умолчанию взаимодействие касания с тремя и четырьмя пальцами теперь используется системой для операций, таких как переключение или минимизация окон и изменение виртуальных рабочих столов. Так как эти взаимодействия теперь обрабатываются на уровне системы, функциональные возможности вашего приложения могут повлиять на это изменение.

Для поддержки взаимодействия с тремя или четырьмя пальцами в приложении появился новый параметр пользователя, указывающий, обрабатывает ли система эти взаимодействия:

Bluetooth и устройства > Касание > "Три и четыре пальца сенсорные жесты"

Если задано значение "Вкл." (по умолчанию), система будет обрабатывать все взаимодействия с тремя и четырьмя пальцами (приложения не смогут поддерживать их).

Если задано значение Off, взаимодействие с тремя и четырьмя пальцами может поддерживаться приложениями (они не будут обрабатываться системой).

Если приложение должно поддерживать эти взаимодействия, рекомендуется сообщить пользователям об этом параметре и предоставить ссылку, которая запускает приложение Параметры на соответствующую страницу (ms-settings:devices-touch). Дополнительные сведения см. в разделе "Метод Launcher.LaunchUriAsync".

Рисование точек

Объявите следующие переменные для подпрограммы рисования.

    // 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;

Контекст отображения памяти используется для хранения временного графического контекста, который переключается с контекстом отображения отрисованного отображения, hdc, для устранения мерцания. Реализуйте подпрограмму рисования, которая принимает хранящиеся точки и рисует круг в точках. В следующем коде показано, как реализовать обработчик WM_PAINT.

  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;

При запуске приложения теперь он должен выглядеть примерно так, как иллюстрация в начале этого раздела.

Для удовольствия вы можете нарисовать некоторые дополнительные линии вокруг точек касания. На следующем снимке экрана показано, как приложение может выглядеть с несколькими дополнительными линиями, нарисованными вокруг кругов.

screen shot showing an application that renders touch points as circles with lines through the centers and intersecting the edges of the touch points

Входные данные Windows Touch