Single-Finger 이동 환경 개선

Windows Touch를 대상으로 하는 애플리케이션을 빌드하는 경우 기본 이동 지원을 자동으로 제공합니다. 그러나 WM_GESTURE 메시지를 사용하여 한 손가락 이동에 대한 향상된 지원을 제공할 수 있습니다.

개요

한 손가락 이동 환경을 개선하려면 이 항목의 후속 섹션에서 설명한 대로 다음 단계를 사용합니다.

  • 스크롤 막대가 있고 터치가 비활성화된 애플리케이션을 만듭니다.
  • 제스처 이동 메시지에 대한 지원을 추가합니다.
  • 바운스를 사용하도록 설정합니다.

스크롤 막대 및 플리트를 사용하지 않도록 설정된 애플리케이션 만들기

시작하기 전에 스크롤 막대가 있는 애플리케이션을 만들어야 합니다. 스크롤 막대를 사용하여 이동하기 위한 레거시 지원 섹션에서는 이 프로세스를 설명합니다. 예제 콘텐츠로 시작하려면 해당 섹션으로 이동하여 스크롤 막대가 있는 애플리케이션을 만든 다음 터치를 사용하지 않도록 설정합니다. 작동 중인 스크롤 막대가 있는 애플리케이션이 이미 있는 경우 해당 섹션에 설명된 대로 터치를 사용하지 않도록 설정합니다.

제스처 이동 메시지에 대한 사용자 지정 이동 지원 추가

제스처 이동 메시지를 지원하려면 WndProc 메서드에서 처리해야 합니다. 제스처 메시지는 이동 메시지의 가로 및 세로 델타를 결정하는 데 사용됩니다. 델타는 사용자 인터페이스를 업데이트하는 스크롤 막대 개체를 업데이트하는 데 사용됩니다.

먼저 targetver.h 파일에서 Windows 버전 설정을 업데이트하여 Windows Touch를 사용하도록 설정합니다. 다음 코드는 targetver.h의 설정을 대체해야 하는 다양한 Windows 버전 설정을 보여줍니다.

#ifndef WINVER                  // Specifies that the minimum required platform is Windows Vista.
#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 Vista.
#define _WIN32_WINNT 0x0601     // Change this to the appropriate value to target other versions of Windows.
#endif

다음으로 프로젝트에 UXTheme.h 파일을 추가하고 uxtheme.lib 라이브러리를 프로젝트의 추가 종속성에 추가합니다.

#include <uxtheme.h>

다음으로 WndProc 함수의 맨 위에 다음 변수를 추가합니다. 이러한 항목은 이동 계산에 사용됩니다.

// The following are used for the custom panning handler      
BOOL bResult = FALSE;

static int scale = 8;   // altering the scale value will change how fast the page scrolls
static int lastY = 0;   // used for panning calculations (initial / previous vertical position)
static int lastX = 0;   // used for panning calculations (initial / previous horizontal position)
GESTUREINFO gi;  

그런 다음 이동 제스처에 따라 스크롤 막대가 델타로 업데이트되도록 WM_GESTURE 메시지에 대한 처리기를 추가합니다. 이렇게 하면 훨씬 세분화된 이동 제어가 가능합니다.

다음 코드는 lParam에서 GESTUREINFO 구조를 가져오고, 구조체에서 마지막 y 좌표를 저장하고, 스크롤 막대 개체를 업데이트하기 위한 위치 변경을 결정합니다. 다음 코드는 WndProc switch 문에 배치해야 합니다.

    case WM_GESTURE:        
        // Get all the vertial scroll bar information
        si.cbSize = sizeof (si);
        si.fMask  = SIF_ALL;
        GetScrollInfo (hWnd, SB_VERT, &si);
        yPos = si.nPos;

        ZeroMemory(&gi, sizeof(GESTUREINFO));
        gi.cbSize = sizeof(GESTUREINFO);
        bResult = GetGestureInfo((HGESTUREINFO)lParam, &gi);

        if (bResult){
            // now interpret the gesture            
            switch (gi.dwID){
                case GID_BEGIN:
                   lastY = gi.ptsLocation.y;
                   CloseGestureInfoHandle((HGESTUREINFO)lParam);
                   break;                     
                // A CUSTOM PAN HANDLER
                // COMMENT THIS CASE OUT TO ENABLE DEFAULT HANDLER BEHAVIOR
                case GID_PAN:                                                  
                    
                    si.nPos -= (gi.ptsLocation.y - lastY) / scale;

                    si.fMask = SIF_POS;
                    SetScrollInfo (hWnd, SB_VERT, &si, TRUE);
                    GetScrollInfo (hWnd, SB_VERT, &si);                                                        
                                               
                    yOverpan -= lastY - gi.ptsLocation.y;
                    lastY = gi.ptsLocation.y;
                     
                    if (gi.dwFlags & GF_BEGIN){
                        BeginPanningFeedback(hWnd);
                        yOverpan = 0;
                    } else if (gi.dwFlags & GF_END) {
                        EndPanningFeedback(hWnd, TRUE);
                        yOverpan = 0;
                    }
                           
                    if (si.nPos == si.nMin || si.nPos >= (si.nMax - si.nPage)){                    
                        // we reached the bottom / top, pan
                        UpdatePanningFeedback(hWnd, 0, yOverpan, gi.dwFlags & GF_INERTIA);
                    }
                    ScrollWindow(hWnd, 0, yChar * (yPos - si.nPos), NULL, NULL);
                    UpdateWindow (hWnd);                    
                                        
                    return DefWindowProc(hWnd, message, lParam, wParam);
                case GID_ZOOM:
                   // Add Zoom handler 
                   return DefWindowProc(hWnd, message, lParam, wParam);
                default:
                   // You have encountered an unknown gesture
                   return DefWindowProc(hWnd, message, lParam, wParam);
             }          
        }else{
            DWORD dwErr = GetLastError();
            if (dwErr > 0){
                // something is wrong 
                // 87 indicates that you are probably using a bad
                // value for the gi.cbSize
            }
        } 
        return DefWindowProc (hWnd, message, wParam, lParam);

이제 창에서 이동 제스처를 수행하면 관성 텍스트 스크롤이 표시됩니다. 이 시점에서 텍스트의 큰 섹션을 탐색할 수 있도록 텍스트를 더 많은 줄로 변경할 수 있습니다.

WndProc의 경계 피드백

경계 피드백은 이동 가능한 영역의 끝에 도달할 때 사용자에게 제공되는 시각적 피드백의 유형입니다. 경계에 도달하면 애플리케이션에 의해 트리거됩니다. WM_GESTURE 메시지의 이전 예제 구현에서 WM_GESTURE 사례의 끝 조건은 (si.nPos == si.yPos) 이동 가능한 영역의 끝에 도달했는지 테스트하는 데 사용됩니다. 다음 변수는 값을 추적하고 오류를 테스트하는 데 사용됩니다.

// The following are used for panning feedback (Window Bounce)
static int animCount = 0;
static DWORD dwErr   = 0;

static BOOL isOverpan  = FALSE;
static long xOverpan   = 0;
static long yOverpan   = 0;

팬 제스처 사례가 업데이트되어 경계 피드백을 트리거합니다. 다음 코드는 WM_GESTURE 메시지 처리기의 GID_PAN 사례를 보여 줍니다.

                case GID_PAN:                                                  
                    
                    si.nPos -= (gi.ptsLocation.y - lastY) / scale;

                    si.fMask = SIF_POS;
                    SetScrollInfo (hWnd, SB_VERT, &si, TRUE);
                    GetScrollInfo (hWnd, SB_VERT, &si);                                                        
                                               
                    yOverpan -= lastY - gi.ptsLocation.y;
                    lastY = gi.ptsLocation.y;
                     
                    if (gi.dwFlags & GF_BEGIN){
                        BeginPanningFeedback(hWnd);
                        yOverpan = 0;
                    } else if (gi.dwFlags & GF_END) {
                        EndPanningFeedback(hWnd, TRUE);
                        yOverpan = 0;
                    }
                           
                    if (si.nPos == si.nMin){                    
                        // we reached the top, pan upwards in y direction
                        UpdatePanningFeedback(hWnd, 0, yOverpan, gi.dwFlags & GF_INERTIA);
                    }else if (si.nPos >= (si.nMax - si.nPage)){
                        // we reached the bottom, pan downwards in y direction
                        UpdatePanningFeedback(hWnd, 0, yOverpan, gi.dwFlags & GF_INERTIA);
                    }
                    ScrollWindow(hWnd, 0, yChar * (yPos - si.nPos), NULL, NULL);
                    UpdateWindow (hWnd);                    
                                        
                    return DefWindowProc(hWnd, message, lParam, wParam);
  

이제 사용자가 스크롤 막대 영역의 아래쪽을 지나면 애플리케이션 창에 경계 피드백이 있어야 합니다.

Windows 터치 제스처

BeginPanningFeedback

EndPanningFeedback

UpdatePanningFeedback