Detectando e rastreando vários pontos de toque
As etapas a seguir explicam como acompanhar vários pontos de toque usando o Windows Touch.
- Crie um aplicativo e habilite o Windows Touch.
- Adicione um manipulador para WM_TOUCH e rastrear pontos.
- Desenhe os pontos.
Depois que o aplicativo estiver em execução, ele renderizará círculos em cada toque. A captura de tela a seguir mostra a aparência do aplicativo durante a execução.
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 mostra como suas diretivas de inclusão 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 rastrear pontos
Primeiro, declare algumas variáveis que são usadas pelo manipulador de WM_TOUCH no 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 por 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étodo WndProc . 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;
}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 , você deve ter alto suporte a DPI em seu aplicativo. Para obter mais informações sobre como dar suporte a DPI alto, consulte DPI alto.
Agora, quando um usuário toca na tela, as posições que ele está tocando serão armazenadas na matriz de pontos. O membro dwID da estrutura TOUCHINPUT armazena um identificador que dependerá de hardware.
Para resolver o problema de o membro dwID depender do hardware, o manipulador de maiúsculas e minúsculas WM_TOUCH usa uma função , GetContactIndex, que mapeia o membro dwID da estrutura TOUCHINPUT para um ponto 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] == -1){
idLookup[i] = dwID;
return i;
}else{
if (idLookup[i] == dwID){
return i;
}
}
}
// Out of contacts
return -1;
}
Importante
Windows 11 e mais recentes
Algumas interações por toque de três e quatro dedos não funcionarão mais em aplicativos do Windows por padrão.
Por padrão, as interações por toque de 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 aplicativo pode ser afetada por essa alteração.
Para dar suporte a interações de três ou quatro dedos em um aplicativo, foi introduzida uma nova configuração de usuário que especifica se o sistema lida ou não com essas interações:
Dispositivos Bluetooth & Tocam > "Gestos > de toque de três e quatro dedos"
Quando definido como "Ativado" (padrão), o sistema manipulará todas as interações de três e quatro dedos (os aplicativos não poderão dar suporte a elas).
Quando definido como "Desativado", as interações de três e quatro dedos podem ser suportadas por aplicativos (eles não serão manipulados pelo sistema).
Se o aplicativo precisar dar suporte a essas interações, recomendamos que você informe os usuários sobre essa configuração e forneça um link que inicie o aplicativo Configurações para a página relevante (ms-settings:devices-touch). Para obter mais detalhes, consulte Método Launcher.LaunchUriAsync.
Desenhar os pontos
Declare as variáveis a seguir 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 memDC de contexto de exibição de memória é 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 usa 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 ser semelhante à ilustração no início desta seção.
Por diversão, você pode desenhar algumas linhas extras ao redor dos pontos de toque. A captura de tela a seguir mostra como o aplicativo pode ficar com algumas linhas extras desenhadas ao redor dos círculos.