다음을 통해 공유


여러 터치 포인트 검색 및 추적

다음 단계에서는 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 Visual Studio 마법사를 사용하여 Microsoft Win32 애플리케이션으로 시작합니다. 마법사를 완료한 후 targetver.h에서 Windows 버전을 설정하고 애플리케이션에 windows.h 및 windowsx.h를 포함하여 Windows Touch 메시지에 대한 지원을 추가합니다. 다음 코드에서는 targetver.h에서 Windows 버전을 설정하는 방법을 보여 줍니다.

#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 지시문을 추가하는 방법을 보여 줍니다. 또한 나중에 사용할 일부 전역 변수를 만들 수 있습니다.

#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 및 트랙 지점에 대한 처리기 추가

먼저 WndProc에서 WM_TOUCH 처리기에서 사용하는 일부 변수를 선언합니다.

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

다음으로 WndProc 메서드에서 WM_TOUCH 메시지를 처리합니다. 다음 코드는 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를 참조하세요.

이제 사용자가 화면을 터치하면 터치하는 위치가 포인트 배열에 저장됩니다. TOUCHINPUT 구조체의 dwID 멤버는 하드웨어에 종속되는 식별자를 저장합니다.

하드웨어에 종속되는 dwID 멤버의 문제를 해결하기 위해 WM_TOUCH 사례 처리기는 TOUCHINPUT 구조체의 dwID 멤버를 화면에 그려진 지점에 매핑하는 함수 GetContactIndex를 사용합니다. 다음 코드는 이 함수의 구현을 보여줍니다.

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

Important

Windows 11 이상

일부 3-4-손가락 터치 조작은 기본적으로 Windows 앱에서 더 이상 작동하지 않습니다.

기본적으로 창을 전환하거나 최소화하고 가상 데스크톱을 변경하는 등의 작업을 위해 시스템에서 세 손가락 및 네 손가락 터치 조작을 사용합니다. 이제 이러한 조작이 시스템 수준에서 처리되기 때문에 이러한 변경으로 인해 앱 기능이 영향을 받을 수 있습니다.

애플리케이션 내에서 세 손가락 및 네 손가락 조작을 지원하기 위해 시스템에서 이러한 조작을 처리할지 여부를 지정하는 새로운 사용자 설정이 도입되었습니다.

Bluetooth 및 디바이스 > 터치 > "세 손가락 및 네 손가락 터치 제스처"

“켜짐”(기본값)으로 설정된 경우 시스템은 3 손가락 및 4 손가락 조작을 모두 처리합니다. 앱에서는 이러한 기능을 지원할 수 없습니다.

“꺼짐”으로 설정되면 앱에서 3 손가락 및 4 손가락 조작을 지원할 수 있습니다. 이러한 조작은 시스템에서 처리되지 않습니다.

애플리케이션에서 이러한 조작을 지원해야 하는 경우 이 설정을 사용자에게 알리고 해당 페이지에 설정 앱을 시작하는 링크를 제공하는 것이 좋습니다(ms-settings:devices-touch). 자세한 내용은 시작 관리자 참조하세요. 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;

메모리 디스플레이 컨텍스트 memDC는 렌더링된 디스플레이 컨텍스트인 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 터치 입력