Responder a la entrada táctil (DirectX y C++)

Applies to Windows and Windows Phone

Los eventos de función táctil se controlan del mismo modo que los eventos de mouse y de lápiz: mediante un tipo de entrada genérico denominado puntero. Este puntero representa los datos de la posición de pantalla con respecto al origen de entrada activo actual. En este tema trataremos cómo puedes admitir la entrada táctil en tu aplicación de Windows en tiempo de ejecución mediante DirectX con C++.

Introducción

Estos son los cuatro eventos de puntero básicos en CoreWindow que puede administrar tu aplicación. Para nuestra comodidad, trataremos estos eventos de puntero como eventos de entrada táctil.

  • PointerMoved. El usuario movió el dedo sobre la superficie de entrada.
  • PointerPressed. El dedo del usuario entró en contacto con la superficie de entrada.
  • PointerReleased. El usuario detuvo el contacto con la superficie de entrada.
  • PointerExited. El dedo del usuario se movió fuera del cuadro límite de la ventana.

Si usas la interoperabilidad de DirectX y XAML, usa los eventos táctiles que proporciona la red XAML, que funcionan en elementos XAML individuales. Estos eventos se proporcionan como parte del tipo Windows::UI::Xaml::UIElement.

También hay tipos de entrada más avanzados definidos en Windows::UI::Input que tratan gestos y manipulaciones, que son secuencias de eventos interpretados por el tipo GestureRecognizer. Entre estos tipos de entrada se incluyen los gestos de arrastrar, deslizar, deslizar transversalmente y mantener presionado.

Administración de los eventos táctiles básicos

Veamos los controladores para los tres eventos táctiles básicos más comunes:

En esta sección, se supone que creaste un proveedor de vistas para tu aplicación de Windows en tiempo de ejecución con DirectX. Si aún no lo has hecho, consulta Cómo configurar una aplicación de Windows en tiempo de ejecución para mostrar una vista DirectX.

En primer lugar, rellenemos los controladores de eventos de puntero táctiles. En el primer controlador de eventos, OnPointerPressed, obtenemos las coordenadas x-y del puntero de CoreWindow que administra nuestra pantalla cuando el usuario toca la pantalla o hace clic con el mouse. Configura los controladores en las implementaciones de IFrameworkView::Initialize o IFrameworkView::SetWindow. (En este ejemplo se 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);
    
}

Nota  Si estás usando la interoperabilidad de DirectX y XAML, XAML proporciona su propia vista (FrameworkView). Registra los eventos de puntero proporcionados en los tipos UIElement para los elementos XAML del diseño. Para obtener más información, consulta Inicio rápido: controlar la entrada de puntero.

Después, crea las devoluciones de llamada correspondientes para obtener y controlar los datos de puntero. Si tu aplicación no usa GestureRecognizer para interpretar estos eventos y datos de puntero, realiza un seguimiento de los valores de identificación del puntero para distinguir entre punteros en dispositivos multitoque. (La mayoría de las superficies táctiles son de entrada multitáctil, lo que significa que puede haber muchos punteros activos a la vez). Realiza un seguimiento del identificador y la posición del puntero para cada evento, para realizar la acción correcta para el movimiento o el gesto asociado con ese puntero.

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.

}


El controlador de eventos OnPointerMoved se desencadena cada vez que se mueve el puntero, con cada marca que el usuario arrastra por la pantalla. Usa el siguiente ejemplo de código para que la aplicación esté al corriente de la ubicación actual del puntero en movimiento:

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

Por último, cuando el usuario deja de tocar la pantalla, hay que dejar de registrar la entrada táctil e interpretar en lo posible el movimiento.

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

En este ejemplo, el código solo recupera el valor de identificador de puntero actual y la posición de ese puntero. De ti dependerá la interpretación de estos datos. Para la activación de control, es suficiente con administrar el evento PointerPressed. Para acciones táctiles más complejas, debes crear algunas variables o métodos para capturar el identificador de puntero y la posición inicial para el gesto táctil, y actualizar estas variables o llamar a estos métodos a medida que se mueve el puntero y se suelta.

Convertir eventos táctiles en gestos

Ahora que tu aplicación puede detectar la entrada táctil con devoluciones de llamada para los eventos táctiles básicos, la aplicación debe interpretar estos eventos. Un modo de hacerlo es usar la clase GestureRecognizer. Un objeto GestureRecognizer toma eventos de puntero (como PointerPressed, PointerMoved y PointerReleased), los procesa y proporciona eventos propios (como Tapped, Holding o Dragging). Estos eventos de nivel superior se llaman gestos y están diseñados para satisfacer los requisitos de interacción del usuario más comunes de las aplicaciones.

Nota  Si en tu caso hay varios objetos o controles que deben manipularse a la vez de manera independiente, considera la posibilidad de usar un GestureRecognizer independiente para cada uno de ellos.

Aquí te mostramos cómo usar GestureRecognizer con los eventos táctiles que procesaste en la sección anterior.

  1. Crea al menos un objeto GestureRecognizer para la aplicación e inicializa su GestureSettings para cada gesto que quieras admitir. Algunos de los gestos son los siguientes:

    • Pulsar. El usuario pulsa una vez o dos veces la superficie táctil.
    • Mantener presionado. El usuario presiona la superficie y la mantiene presionada durante un cierto tiempo.
    • Arrastrar. El usuario presiona la superficie y mueve la presión en alguna dirección.
    • Manipular. El usuario realiza un gesto de deslizar, reducir o ampliar para ajustar la escala, hacer zoom o girar la pantalla o un objeto.

    En GestureRecognizer hay un conjunto de eventos que puedes administrar para estos gestos, entre los que se incluyen:

    Veamos cómo registrar estos eventos y proporcionar a GestureRecognizer los datos de entrada táctil necesarios para identificar estos eventos. En este ejemplo, agregas el siguiente código a la implementación de IFrameworkView::SetWindow para crear un GestureRecognizer para el gesto de doble pulsación y registras un controlador para el evento GestureRecognizer::Tapped. El reconocedor del gesto se declara 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. Crea controladores en la aplicación para los gestos que quieras interpretar y enlázalos a los eventos de GestureRecognizer. En el ejemplo, creas un controlador sencillo en la clase de proveedor de vistas, OnTapped, para administrar el evento de pulsar:

    
    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. Sin embargo, para que el objeto GestureRecognizer obtenga los datos de entrada táctil para estos eventos, debes proporcionarlo pasándole los datos del puntero desde los controladores de eventos de entrada táctil básicos (como OnPointerPressed en el ejemplo anterior).

    Para ello, indica a los controladores de la aplicación que los eventos de entrada básicos (PointerPressed, PointerReleased y PointerMoved) llamen a los métodos ProcessDownEvent, ProcessUpEvent y ProcessMoveEvents correspondientes en 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()); 
    } 
     
    
    
    

    Después, GestureRecognizer puede realizar el seguimiento de la secuencia de entradas y, cuando encuentre un conjunto de entradas que coincidan con un gesto, desencadenar un evento —en este caso, el evento GestureRecognizer::Tapped.

En otros casos más complejos, especialmente los que tienen más de un GestureRecognizer, necesitas determinar qué instancias de GestureRecognizer están activas según la prueba de acceso táctil.

Distribuir mensajes de evento

En el método IFrameworkView::Run que implementaste en el proveedor de vistas de tu aplicación, creaste el bucle de procesamiento principal. Dentro de ese bucle, llama a CoreEventDispatcher::ProcessEvents para el distribuidor de eventos en CoreWindow de la aplicación, como aquí:

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

El valor de enumeración de CoreProcessEventsOption::ProcessAllIfPresent indica a ProcessEvents que distribuya las devoluciones de llamada para cada evento en la cola de mensajes en el momento en que se llama a ProcessEvents. Al hacerlo, la aplicación controla los cambios en la entrada táctil del usuario y actualiza los datos del puntero, de manera que esté sincronizada con la representación y la respuesta se mantenga suave. Usa este valor de CoreProcessEventsOption si la aplicación tiene un bucle de representación con temporizador que se está ejecutando constantemente y quieres procesar los eventos de entrada en un temporizador o con cada iteración del bucle. De nuevo, debes llamarlo en cada iteración del bucle, o en cada intervalo del temporizador.

Otra posibilidad es que tu aplicación entre en pausa o en un estado en segundo plano en el que se suspenda la representación. En este caso, cuando entre en este estado, llama a ProcessEvents con CoreProcessEventsOption::ProcessOneAndAllPending, que procesa cualquier mensaje de evento pendiente y actual a medida que la aplicación se pausa o se suspende.

En la siguiente muestra de código para una implementación de IFrameworkView::Run, se elige entre los dos valores de CoreProcessEventsOption para ProcessEvents según el estado de la aplicación:


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 obtener más información sobre la distribución de mensajes de estado, consulta Trabajar con mensajes de eventos y CoreWindow (DirectX y C++).

Muestras de entrada táctil de DirectX

Estas son algunos códigos de ejemplo completos que te ayudarán a incluir la compatibilidad con gestos y entrada táctil en tu aplicación de Windows en tiempo de ejecución con DirectX

Temas relacionados

Inicio rápido: controlar la entrada de puntero
Responder a la interacción del usuario (DirectX y C++)
Trabajar con mensajes de eventos y CoreWindow (DirectX y C++)

 

 

Mostrar:
© 2015 Microsoft