Обнаружение и отслеживание нескольких точек касания
Ниже описано, как отслеживать несколько точек касания с помощью Windows Touch.
- Создайте приложение и включите Windows Touch.
- Добавьте обработчик для WM_TOUCH и отслеживания точек.
- Рисование точек.
После запуска приложения будут отображаться круги под каждым касанием. На следующем снимке экрана показано, как может выглядеть приложение во время выполнения.
Создание приложения и включение 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;
При запуске приложения теперь он должен выглядеть примерно так, как иллюстрация в начале этого раздела.
Для удовольствия вы можете нарисовать некоторые дополнительные линии вокруг точек касания. На следующем снимке экрана показано, как приложение может выглядеть с несколькими дополнительными линиями, нарисованными вокруг кругов.