Reagindo à entrada por toque
Recolher sumário
Expandir sumário

Respondendo à entrada por toque (DirectX e C++)

[ Este artigo destina-se aos desenvolvedores do Windows 8.x e do Windows Phone 8.x que escrevem aplicativos do Windows Runtime. Se você estiver desenvolvendo para o Windows 10, consulte documentação mais recente ]

Os eventos de toque são manipulados da mesma maneira que os eventos de mouse e caneta: por um tipo de entrada genérica chamada ponteiro. Esse ponteiro representa os dados de posição da tela a partir da fonte de entrada ativa atual. Neste documento falamos sobre como você pode dar suporte à entrada por toque em seu aplicativo do Tempo de Execução do Windows em DirectX com C++.

Introdução

Veja quatro eventos básicos de ponteiro no CoreWindow que seu aplicativo pode manipular. Para nossos objetivos, trataremos esses eventos de ponteiro como eventos de entrada por toque.

  • PointerMoved. O usuário moveu seu dedo sobre a superfície de entrada.
  • PointerPressed. O dedo do usuário fez contato com a superfície de entrada.
  • PointerReleased. O usuário interrompeu o contato com a superfície de entrada.
  • PointerExited. O dedo do usuário se moveu para fora da caixa delimitadora da janela.

Se você usar a interoperabilidade entre DirectX e XAML, use os eventos por toque fornecidos pela estrutura XAML, que opera em elementos XAML individuais. Esses eventos são fornecidos como parte do tipo Windows::UI::Xaml::UIElement.

Também existem tipos de entrada mais avançados definidos em Windows::UI::Input que lidam com gestos e manipulações, que são sequências de eventos interpretados pelo tipo GestureRecognizer. Esses tipos de entrada incluem gestos de arrastar, deslizar o dedo, deslizar o dedo transversalmente e segurar.

Manipular eventos por toque básicos

Vamos analisar os manipuladores para os três eventos por toque mais comuns:

Nesta seção, nós assumimos que você criou um provedor de visualização para seu aplicativo do Tempo de Execução da Windows Store em DirectX. Caso não tenha feito isso, consulte Como configurar o aplicativo do Tempo de Execução do Windows para mostrar a exibição do DirectX.

Primeiro, vamos preencher os manipuladores de eventos de ponteiro de toque. No primeiro manipulador de eventos, OnPointerPressed, obtemos as coordenadas x-y do ponteiro na CoreWindow que gerencia a exibição quando o usuário toca na tela ou clica no mouse. Configure os manipuladores em suas implementações de IFrameworkView::Initialize ou IFrameworkView::SetWindow. (O exemplo aqui usa 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);
    
        }

Observação  Se você estiver usando a Interoperabilidade entre DirectX e XAML, a linguagem XAML fornece sua própria exibição (FrameworkView). Registre-se para os eventos de ponteiro fornecidos nos tipos UIElement para os elementos XAML em seu layout. Para saber mais, veja Guia de início rápido: manipulando a entrada do ponteiro.
 

Agora, crie as chamadas de retorno correspondentes para obter e manipular os dados do ponteiro. Se o seu aplicativo não usar o GestureRecognizer para interpretar esses eventos e dados do ponteiro, rastreie os valores de ID do ponteiro para distinguir os ponteiros em dispositivos multitoque. (A maioria das superfícies de toque é de entrada multitoque, o que significa que muitos ponteiros podem estar ativos ao mesmo tempo.) Rastreie a ID e a posição do ponteiro para cada evento, assim você pode executar a ação correta para o movimento ou o gesto associado àquele ponteiro.

OnPointerPressed


void MyTouchApp::OnPointerPressed(
                                           _In_ CoreWindow^ sender,
                                           _In_ PointerEventArgs^ args)
{
    // get the current pointer position
    uint32 pointerID = args->CurrentPoint->PointerId;
    XMFLOAT2 position = XMFLOAT2( 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.

}
        

Observação  XMFLOAT2 é definido em DirectXMath.h.
 

O manipulador de eventos OnPointerMoved é acionado sempre que o ponteiro se move, a cada "tique" que o jogador arrasta na tela. Use o próximo exemplo de código para manter o aplicativo ciente do local atual do ponteiro de movimento:

OnPointerMoved


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

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

Por fim, precisamos parar de gravar a entrada por toque e, possivelmente, interpretar o movimento quando o usuário para de tocar na tela.

OnPointerReleased


void MyTouchApp::OnPointerReleased(
                                             _In_ CoreWindow ^sender,
                                             _In_ PointerEventArgs ^args)
{
    uint32 pointerID = args->CurrentPoint->PointerId;
    XMFLOAT2 position = XMFLOAT2( 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.
   
}

Nesse exemplo, o código simplesmente recupera o valor de ID do ponteiro atual e a posição para aquele ponteiro. Depende de você interpretar aqueles dados. Para a ativação do controle, manipular o evento PointerPressed é suficiente. Para obter ações de toque mais complexas, você deverá criar algumas variáveis ou métodos para capturar a ID do ponteiro e a posição inicial do gesto de toque, e para atualizar essas variáveis ou chamar esses métodos à medida que o ponteiro se move e é liberado.

Transformando eventos de toque em gestos

Agora que seu aplicativo pode detectar a entrada de toque com chamadas de retorno para os eventos básicos de toque, seu aplicativo deve interpretar aqueles eventos. Uma maneira de fazer isso é usar a classe GestureRecognizer. Um objeto GestureRecognizer pega os eventos de ponteiro (como PointerPressed, PointerMoved e PointerReleased), processa-os e fornece seus próprios eventos (como Tapped, Holding ou Dragging). Esses eventos de nível mais alto são chamados gestos e são criados para atender às exigências mais comuns de interação do usuário dos aplicativos.

Observação  Se sua cena tem vários objetos ou controles que precisam ser manipulados ao mesmo tempo de forma independente, considere usar um GestureRecognizer separado para cada um deles.
 

Veja como usar o GestureRecognizer com os eventos de toque que você processou na seção anterior.

  1. Crie pelo menos um objeto GestureRecognizer para seu aplicativo e inicialize seu GestureSettings para cada gesto ao qual você deseja dar suporte. Alguns gestos incluem:

    • Toque. O usuário dá um toque simples ou um toque duplo na superfície de toque.
    • Segurar. O usuário pressiona a superfície e segura o pressionamento por alguns instantes.
    • Arrastar. O usuário pressiona a superfície e move o pressionamento em alguma direção.
    • Manipular. O usuário faz um gesto de deslizar, pinçar ou ampliar para dimensionar, aplicar zoom ou girar a tela ou um objeto.

    Existe um conjunto de eventos no GestureRecognizer que você pode manipular para esses gestos, incluindo:

    Vamos examinar como registrar-se para esses eventos e fornecer ao GestureRecognizer os dados de entrada por toque necessários para ele identificar esses eventos. Neste exemplo, adicione o código a seguir à sua implementação do IFrameworkView::SetWindow para criar um GestureRecognizer para o gesto de toque duplo e para registrar um manipulador para o evento GestureRecognizer::Tapped. O reconhecedor de gesto é declarado como:

    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. Crie manipuladores em seu aplicativo para os gestos que você deseja interpretar e vinculá-los aos eventos do GestureRecognizer. No exemplo, crie um único manipulador na classe do provedor de exibição, OnTapped, para manipular o evento de toque:

    
    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. Entretanto, para o objeto GestureRecognizer obter os dados de entrada de toque para esses eventos, você deve fornecê-los enviando os dados do ponteiro para ele a partir de seus manipuladores de eventos de entrada de toque básicos (como OnPointerPressed em nosso exemplo anterior).

    Para fazer isso, instrua os manipuladores de seu aplicativo para os eventos de entrada básicos (PointerPressed, PointerReleased, e PointerMoved) para chamar os métodos ProcessDownEvent, ProcessUpEvent e ProcessMoveEvents correspondentes em seu GestureRecognizer.

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

    Agora, o GestureRecognizer pode rastrear a sequência de entradas e quando encontra um conjunto de entradas correspondente a um gesto, acionar um evento—neste caso, o evento GestureRecognizer::Tapped.

Em situações mais complexas, especialmente as que têm mais de um GestureRecognizer, você precisa determinar quais instâncias GestureRecognizer estão ativas com base no teste de hit de toque.

Expedindo mensagens de eventos

No método IFrameworkView::Run você implementou o provedor de visualização para seu aplicativo e criou seu loop de processamento principal. Dentro desse loop, chame CoreEventDispatcher::ProcessEvents para o dispatcher de eventos no CoreWindow se seu aplicativo, de uma forma parecida com essa:

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

O valor da enumeração CoreProcessEventsOption::ProcessAllIfPresent instrui o ProcessEvents para expedir as chamadas de retorno para cada evento na fila de mensagens no momento em que o ProcessEvents é chamado. Ao fazer isso, seu aplicativo manipula as mudanças efetuadas na entrada de toque do usuário e atualiza os dados do ponteiro que são sincronizados com a renderização, mantendo o feedback uniforme. Use este valor CoreProcessEventsOption se o seu aplicativo tiver um loop de renderização controlada por timer constantemente em execução e você deseje processar os eventos de entrada em um timer ou com cada iteração do loop. Novamente, você deve chamar isso em cada iteração do loop ou em cada intervalo do timer.

Alternativamente, seu aplicativo pode entrar em um estado de pausa ou em segundo plano onde a renderização é suspensa. Neste caso, quando você entrar no estado, chame ProcessEvents com o CoreProcessEventsOption::ProcessOneAndAllPending, que processará quaisquer mensagens de eventos atuais e pendentes, quando o aplicativo estiver pausado ou suspenso.

O seguinte exemplo de código para uma implementação do IFrameworkView::Run escolhe entre os dois valores do CoreProcessEventsOption para o ProcessEvents com base no estado do aplicativo:


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

Para saber mais sobre como expedir mensagens de eventos, veja Trabalhando com mensagens de eventos e CoreWindow (DirectX e C++).

Exemplos de DirectX de entrada de toque

Veja alguns exemplos de códigos completos para orientá-lo sobre o suporte à entrada por toque e ao gesto no aplicativo do Tempo de Execução do Windows em DirectX

Tópicos relacionados

Guia de início rápido: manipulando a entrada do ponteiro
Respondendo à interação do usuário (DirectX e C++)
Trabalhando com mensagens de eventos e CoreWindow (DirectX e C++)

 

 

Mostrar:
© 2016 Microsoft