Partilhar via


Detetando e rastreando vários pontos de toque

As etapas a seguir explicam como rastrear vários pontos de toque usando o Windows Touch.

  1. Crie um aplicativo e habilite o Windows Touch.
  2. Adicione um manipulador para WM_TOUCH e rastreie os pontos.
  3. Desenhe os pontos.

Depois de executar seu aplicativo, ele renderizará círculos sob cada toque. A captura de tela a seguir mostra a aparência do seu aplicativo durante a execução.

captura de tela mostrando um aplicativo que processa pontos de toque como círculos verdes e amarelos

Criar um aplicativo e habilitar o Windows Touch

Comece com um aplicativo Microsoft Win32 usando o assistente do Microsoft Visual Studio. Depois de concluir o assistente, adicione suporte para mensagens do Windows Touch definindo a versão do Windows em targetver.h e incluindo windows.h e windowsx.h em seu aplicativo. O código a seguir mostra como definir a versão do Windows em 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

O código a seguir exibe como as suas diretivas include devem ser adicionadas. Além disso, você pode criar algumas variáveis globais que serão usadas posteriormente.

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

Adicionar manipulador para WM_TOUCH e pontos de controle

Primeiro, declare algumas variáveis que são usadas pelo manipulador de WM_TOUCH em WndProc.

int wmId, wmEvent, i, x, y;

UINT cInputs;
PTOUCHINPUT pInputs;
POINT ptInput;   

Agora, inicialize as variáveis usadas para armazenar pontos de toque e registre a janela para entrada de toque do método 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;
}

Em seguida, manipule a mensagem WM_TOUCH do métodoWndProc. O código a seguir mostra uma implementação do manipulador para 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 
  }  

Observação

Para usar a função ScreenToClient, deve ter suporte a DPI alto na sua aplicação. Para obter mais informações sobre como oferecer suporte a DPI alto, consulte Alta DPI.

Agora, quando um utilizador toca na tela, as posições que ele ou ela está a tocar serão armazenadas no array de pontos. O membro dwID da estrutura TOUCHINPUT armazena um identificador que será dependente do hardware.

Para resolver o problema de o membro dwID ser dependente de hardware, o manipulador de caso WM_TOUCH usa uma função, GetContactIndex, que mapeia o dwID membro da estrutura TOUCHINPUT para um ponto que é desenhado na tela. O código a seguir mostra uma implementação dessa função.

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

Importante

Windows 11 e mais recentes

Algumas interações de toque com três e quatro dedos não funcionarão mais em aplicativos do Windows por padrão.

Por padrão, as interações de toque com três e quatro dedos agora são consumidas pelo sistema para operações como alternar ou minimizar janelas e alterar áreas de trabalho virtuais. Como essas interações agora são tratadas no nível do sistema, a funcionalidade do seu aplicativo pode ser afetada por essa alteração.

Para oferecer suporte a interações de três ou quatro dedos em um aplicativo, uma nova configuração de usuário foi introduzida que especifica se o sistema lida ou não com essas interações:

dispositivos Bluetooth & > Touch > "Gestos de toque com três e quatro dedos"

Quando definido como "Ativado" (padrão), o sistema lidará com todas as interações de três e quatro dedos (os aplicativos não poderão suportá-las).

Quando definido como "Desativado", as interações com três e quatro dedos podem ser suportadas por aplicativos (eles não serão manipulados pelo sistema).

Se o seu aplicativo precisar oferecer suporte a essas interações, recomendamos que você informe os usuários sobre essa configuração e forneça um link que inicie as Configurações do Windows para a página relevante (ms-settings:devices-touch). Para mais detalhes, consulte o método Launcher.LaunchUriAsync .

Desenhe os pontos

Declare as seguintes variáveis para a rotina de desenho.

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

O contexto de exibição de memória memDC é usado para armazenar um contexto gráfico temporário que é trocado com o contexto de exibição renderizado, hdc, para eliminar a cintilação. Implemente a rotina de desenho, que pega os pontos que você armazenou e desenha um círculo nos pontos. O código a seguir mostra como você pode implementar o manipulador de 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;

Quando você executa seu aplicativo, ele agora deve se parecer com a ilustração no início desta seção.

Para se divertir, você pode desenhar algumas linhas extras em torno dos pontos de toque. A captura de tela a seguir mostra como o aplicativo poderia parecer com algumas linhas extras desenhadas ao redor dos círculos.

imagem de ecrã mostrando uma aplicação que exibe pontos de toque como círculos com linhas que atravessam os centros e intersectam as bordas dos pontos de toque

Entrada por Toque do Windows