터치 입력에 응답(DirectX 및 C++)

Applies to Windows and Windows Phone

터치 이벤트는 포인터라고 하는 제네릭 입력 형식에 의해 마우스 및 스타일러스 이벤트와 동일한 방식으로 처리됩니다. 이 포인터는 현재 활성 입력 원본의 화면 위치 데이터를 나타냅니다.여기서는 DirectX 및 C++를 사용하는 Windows 런타임 앱에서 터치 입력을 지원하는 방법을 설명합니다.

소개

다음은 앱이 처리할 수 있는 CoreWindow의 네 가지 기본 포인터 이벤트입니다. 여기서는 이러한 포인터 이벤트를 터치 입력 이벤트로 처리합니다.

  • PointerMoved. 사용자가 입력 표면 위에서 손가락을 움직였습니다.
  • PointerPressed. 사용자 손가락이 입력 표면과 접촉했습니다.
  • PointerReleased. 사용자가 입력 표면과의 접촉을 중지했습니다.
  • PointerExited. 사용자 손가락이 창의 경계 상자 외부로 이동되었습니다.

DirectX 및 XAML interop을 사용하는 경우 개별 XAML 요소에 작동하며 XAML 프레임워크에서 제공하는 터치 이벤트를 사용합니다. 이러한 이벤트는 Windows::UI::Xaml::UIElement 형식의 일부로 제공됩니다.

GestureRecognizer 형식에 의해 해석되는 이벤트 시퀀스인 제스처 및 조작을 처리하는 Windows::UI::Input에 정의된 보다 수준 높은 입력 형식도 있습니다. 이러한 입력 형식에는 끌기, 밀기, 가로질러 밀기 및 길게 누르기가 포함됩니다.

기본 터치 이벤트 처리

다음은 가장 일반적인 세 가지 기본 터치 이벤트에 대한 처리기입니다.

이 섹션에서는 DirectX를 사용하는 Windows 런타임 앱에 대한 뷰 공급자를 만든 것으로 간주합니다. 이 작업을 아직 수행하지 않았으면 DirectX 보기를 표시하도록 Windows 런타임 앱을 설정하는 방법을 참조하세요.

먼저 터치 포인터 이벤트 처리기를 채워 보겠습니다. 첫 번째 OnPointerPressed 이벤트 처리기에서는 사용자가 화면을 터치하거나 마우스를 클릭할 때 디스플레이를 관리하는 CoreWindow에서 포인터의 x-y 좌표를 가져옵니다. IFrameworkView::Initialize 또는 IFrameworkView::SetWindow 구현에서 처리기를 설정합니다. (여기에 나오는 예제에서는 SetWindow를 사용합니다.)


void MyTouchApp::SetWindow(
    _In_ CoreWindow^ window
    )
{
    // .. Other window event initialization here ...

    window->PointerPressed +=
        ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &CoreWindowEvents::OnPointerPressed);
    window->PointerReleased +=
        ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &CoreWindowEvents::OnPointerReleased);
    window->PointerMoved +=
        ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &CoreWindowEvents::OnPointerMoved);
    
}

참고  DirectX 및 XAML interop을 사용하는 경우 XAML은 자체 보기(FrameworkView)를 제공합니다. 대신 레이아웃의 XAML 요소의 UIElement 형식에 대해 제공되는 포인터 이벤트를 등록합니다. 자세한 내용은 빠른 시작: 포인터 입력 처리를 참조하세요.

이제 해당하는 콜백을 만들어 포인터 데이터를 획득하고 처리합니다. 앱이 이러한 포인터 이벤트 및 데이터를 해석하는 데 GestureRecognizer를 사용하지 않을 경우 멀티 터치 장치의 포인터 간을 구분하기 위해 포인터 ID 값을 추적합니다. (대부분의 터치 화면은 멀티 터치 입력입니다. 즉, 많은 포인터가 동시에 작동될 수 있습니다.) 해당 포인터와 연관된 동작 또는 제스처에 대해 올바른 조치를 취할 수 있도록 각 이벤트에 대한 포인터의 ID와 위치를 추적합니다.

OnPointerPressed


void MyTouchApp::OnPointerPressed(
                                           _In_ CoreWindow^ sender,
                                           _In_ PointerEventArgs^ args)
{
    // get the current pointer position
    uint32 pointerID = args->CurrentPoint->PointerId;
    float2 position = float2( args->CurrentPoint->Position.X, args->CurrentPoint->Position.Y );

    auto device = args->CurrentPoint->PointerDevice;
    auto deviceType = device->PointerDeviceType;
    

	   // If the pointer press event is in a specific control, set the control to active 
    // if the control is activated by a press.
    // Set the tracking variables for this control to the pointer ID and starting position.

}


OnPointerMoved 이벤트 처리기는 사용자가 화면에서 끄는 모든 틱에서 포인터가 이동할 때마다 발생합니다. 다음 코드 예제를 사용하여 앱에서 이동하는 포인터의 현재 위치를 알 수 있도록 할 수 있습니다.

OnPointerMoved


void MyTouchApp::OnPointerMoved(
                                        _In_ CoreWindow ^sender,
                                        _In_ PointerEventArgs ^args)
{
    uint32 pointerID = args->CurrentPoint->PointerId;
    float2 position = float2( args->CurrentPoint->Position.X, args->CurrentPoint->Position.Y );

    // Update the position in any tracking variables for this pointer ID. 
}

마지막으로 사용자가 화면 터치를 중지할 때 터치 입력 기록을 중지하고 동작을 해석해야 합니다.

OnPointerReleased


void MyTouchApp::OnPointerReleased(
                                             _In_ CoreWindow ^sender,
                                             _In_ PointerEventArgs ^args)
{
    uint32 pointerID = args->CurrentPoint->PointerId;
    float2 position = float2( args->CurrentPoint->Position.X, args->CurrentPoint->Position.Y );

    // Process the touch input results here. Set the tracking variable pointer ID value 
    // to 0 when you're done.
   
}

이 예제에서 코드는 해당 포인터의 현재 포인터 ID 값과 위치를 검색합니다. 이러한 데이터는 사용자가 해석해야 합니다. 컨트롤 활성화를 위해서는 PointerPressed 이벤트를 처리하는 것으로 충분합니다. 좀 더 복잡한 터치 작업의 경우 일부 변수나 메서드를 만들어 터치 제스처에 대한 포인터 ID 및 초기 위치를 캡처하고 포인터가 이동되거나 해제될 때 이러한 변수를 업데이트하거나 메서드를 호출해야 합니다.

터치 이벤트를 제스처로 변환

앱은 기본 터치 이벤트에 대한 콜백으로 터치 입력을 검색할 수 있으면 해당 이벤트를 해석해야 합니다. 이 작업을 수행하는 한 가지 방법은 GestureRecognizer클래스를 사용하는 것입니다. GestureRecognizer 개체는 포인터 이벤트(예: PointerPressed, PointerMovedPointerReleased)를 가져와서 처리하고 자체 이벤트(예: Tapped, Holding 또는 Dragging)를 제공합니다. 이러한 상위 수준 이벤트를 제스처라고 하며 앱의 가장 일반적인 사용자 조작 요구 사항을 이행하도록 디자인되었습니다.

참고  화면에 동시에 독립적으로 조작해야 하는 여러 개의 개체나 컨트롤이 있는 경우 각각에 대해 별도의 GestureRecognizer를 사용하는 것을 고려하세요.

이전 섹션에서 처리한 터치 이벤트와 함께 GestureRecognizer를 사용하는 방법은 다음과 같습니다.

  1. 앱에 대한 하나 이상의 GestureRecognizer 개체를 만들고 지원하려는 각 제스처에 대해 GestureSettings를 초기화합니다. 제스처에는 다음이 포함됩니다.

    • 탭하기. 사용자가 터치 화면을 한 번 탭하거나 두 번 탭합니다.
    • 길게 누르기. 사용자가 화면을 일정 시간 동안 계속 누릅니다.
    • 끌기. 사용자가 화면을 누르고 특정 방향으로 이동합니다.
    • 조작. 사용자가 밀기, 손가락 모으기 또는 확대 제스처를 만들어 디스플레이나 개체를 확대, 축소 또는 회전합니다.

    이러한 제스처에 대해 처리할 수 있는 GestureRecognizer에 대한 이벤트에는 다음이 포함됩니다.

    이러한 이벤트를 등록하고 GestureRecognizer에 이러한 이벤트를 식별하는 데 필요한 터치 입력 데이터를 제공하는 방법을 살펴 보겠습니다. 이 예제에서는 IFrameworkView::SetWindow 구현에 다음 코드를 추가하여 두 번 탭하기 제스처에 대해 GestureRecognizer를 만들고 GestureRecognizer::Tapped 이벤트에 대한 처리기를 등록합니다. 제스처 인식기는 다음으로 선언됩니다.

    Platform::Agile<Windows::UI::Input::GestureRecognizer> m_gestureRecognizer;
    
    m_gestureRecognizer = ref new GestureRecognizer(); 
    
    m_gestureRecognizer->GestureSettings = 
            GestureSettings::DoubleTap; 
     
    m_gestureRecognizer->Tapped += 
            ref new TypedEventHandler<GestureRecognizer^, TappedEventArgs^>(this, &CommandListRenderer::OnTapped); 
     
    
    
    
    
  2. 해석하려는 제스처에 대한 처리기를 앱에 만들고 GestureRecognizer의 이벤트에 연결합니다. 이 예에서는 탭 이벤트를 처리하기 위해 뷰 공급자 클래스에 대한 단일 처리기인 OnTapped를 만듭니다.

    
    void MyTouchApp::OnTapped( 
        _In_ GestureRecognizer^ gestureRecognizer, 
        _In_ TappedEventArgs^ args 
        ) 
    { 
        if (args->TapCount == 2) // the tap event is a double tap
        { 
            HandlePointerDoubleTapped(args->Position); 
        } 
    } 
    
    void MyTouchApp::HandlePointerDoubleTapped(Point position) 
    { 
        // Recenter the object around the screen location of the first tap of the 
        //double tap gesture.
        m_recenter = true; 
        m_recenterStartPosition.x = m_viewPosition.X; 
        m_recenterStartPosition.y = m_viewPosition.Y; 
        m_recenterStartZoom = m_zoom; 
    } 
    
    
    
    

  3. 그러나 GestureRecognizer 개체가 이러한 이벤트에 대한 터치 입력 데이터를 가져오려면 기본 터치 입력 이벤트 처리기의 포인터 데이터를 전달하여 개체에 전달해야 합니다(이전 예제의 OnPointerPressed와 유사).

    이렇게 하려면 기본 입력 이벤트(PointerPressed, PointerReleasedPointerMoved)에 대한 앱 처리기에 GestureRecognizer에 대해 해당 ProcessDownEvent, ProcessUpEventProcessMoveEvents 메서드를 호출하도록 지시합니다.

    
    void MyTouchApp::OnPointerPressed( 
        _In_ CoreWindow^ window, 
        _In_ PointerEventArgs^ args 
        ) 
    { 
        m_gestureRecognizer->ProcessDownEvent(args->CurrentPoint); 
    } 
    
    void MyTouchApp::OnPointerReleased( 
        _In_ CoreWindow^ window, 
        _In_ PointerEventArgs^ args 
        ) 
    { 
        m_gestureRecognizer->ProcessUpEvent(args->CurrentPoint); 
    } 
     
    // We don't need to provide pointer move event data if we're just looking for double
    // taps, but  we'll do so anyhow just because many apps will need this data.
    void MyTouchApp::OnPointerMoved( 
        _In_ CoreWindow^ window, 
        _In_ PointerEventArgs^ args 
        ) 
    { 
        m_gestureRecognizer->ProcessMoveEvents(args->GetIntermediatePoints()); 
    } 
     
    
    
    

    이제 GestureRecognizer는 입력 시퀀스를 추적할 수 있으며 제스처와 일치하는 입력 모음을 만나면 이벤트를 발생합니다(—이 경우 GestureRecognizer::Tapped 이벤트).

좀 더 복잡한 시나리오(둘 이상의 GestureRecognizer가 있는 경우)에서는 터치 적중 테스트에 따라 활성 상태인 GestureRecognizer 인스턴스를 확인해야 합니다.

이벤트 메시지 디스패치

앱의 뷰 공급자에 대해 구현한 IFrameworkView::Run 메서드에서 주 처리 루프를 만들었습니다. 해당 루프 내에서 다음과 같이 앱의 CoreWindow에서 이벤트 디스패처에 대한 CoreEventDispatcher::ProcessEvents를 호출합니다.

CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);

CoreProcessEventsOption::ProcessAllIfPresent 열거형 값은 ProcessEvents가 호출될 때 메시지 큐의 각 이벤트에 대해 콜백을 디스패치하도록 ProcessEvents에 지시합니다. 이렇게 하면 앱은 사용자 터치 입력의 변경 내용을 처리하고 포인터 데이터를 업데이트하여 렌더링과 동기화되고 피드백이 원활하게 제공되도록 합니다. 앱에 지속적으로 실행되는 타이머 구동 렌더 루프가 있고 타이머에 대해 또는 루프가 반복될 때마다 입력 이벤트를 처리하려는 경우 이 CoreProcessEventsOption 값을 사용합니다. 또한 루프가 반복될 때마다 또는 타이머 간격마다 호출해야 합니다.

렌더링이 일시 중단될 경우 앱이 일시 중단 또는 백그라운드 상태가 될 수도 있습니다. 이러한 상태가 되면 앱이 일시 중지되거나 일시 중단될 때 현재 및 보류 중인 이벤트 메시지를 처리합니다.CoreProcessEventsOption::ProcessOneAndAllPending을 사용하여 ProcessEvents를 호출합니다.

IFrameworkView::Run 구현에 대한 다음 코드 샘플은 앱 상태를 기반으로 ProcessEvents의 2가지 CoreProcessEventsOption 값 중에서 선택합니다.


void MyTouchApp::Run()
{
	while (!m_coreWindowClosed)
	{
		switch (m_updateState)
		{
			case UpdateEngineState::Deactivated: // the app's process is not active (it's suspended)
			case UpdateEngineState::Snapped: // the app's window is snapped
				if (!m_renderNeeded)
				{
					CoreWindow::GetForCurrentThread()->Dispatcher->
						ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
					break;
				}
			default: // the app is active and not snapped
					CoreWindow::GetForCurrentThread()->Dispatcher->
						ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
					m_myGameObject->Render();
					m_myGameObject->PresentSwapChain(); // calls IDXGISwapChain::Present()
					m_renderNeeded = false;
				}
		}
	}
}

이벤트 메시지 디스패치에 대한 자세한 내용은 이벤트 메시징 및 CoreWindow 작업(DirectX and C++)을 참조하세요.

터치 입력 DirectX 샘플

다음은 DirectX를 사용하는 Windows 런타임 앱에 대한 터치 입력 및 제스처 지원을 설명하기 위한 몇 가지 전체 코드 샘플입니다.

관련 항목

빠른 시작: 포인터 입력 처리
사용자 조작에 응답(DirectX 및 C++)
이벤트 메시징 및 CoreWindow 작업(DirectX and C++)

 

 

표시:
© 2014 Microsoft