Windows Dev Center

Réponse à l’entrée tactile (DirectX et C++)

Les événements tactiles sont gérés de la même manière que les événements de stylet et de souris : par un type d’entrée générique nommé pointeur. Ce pointeur représente les données de position à l’écran de la source d’entrée active actuellement. Cette rubrique traite de la façon dont vous pouvez prendre en charge l’entrée tactile dans votre application Windows Runtime en C++ avec DirectX.

Introduction

Voici les quatre événements de pointeur de base sur le CoreWindow que votre application peut gérer. Pour les besoins de cette rubrique, nous traiterons ces événements de pointeur comme des événements d’entrée tactile.

  • PointerMoved. L’utilisateur a déplacé son doigt sur la surface d’entrée.
  • PointerPressed. Le doigt de l’utilisateur est entré en contact avec la surface d’entrée.
  • PointerReleased. Le doigt de l’utilisateur n’est plus en contact avec la surface d’entrée.
  • PointerExited. Le doigt de l’utilisateur s’est déplacé en dehors du cadre englobant de la fenêtre.

Si vous utilisez la technologie interop DirectX et XAML, utilisez les événements tactiles fournis par l’infrastructure XAML, qui opèrent sur des éléments XAML individuels. Ces événements sont fournis dans le cadre du type Windows::UI::Xaml::UIElement.

Il existe également des types d’entrée plus avancés définis dans Windows::UI::Input, qui traitent des mouvements et des manipulations, c’est-à-dire des séquences d’événements interprétées par le type GestureRecognizer. Parmi ces types d’entrée figurent les mouvements de glissement, de glisser transversal et de maintien.

Gestion des événements tactiles de base

Examinons les gestionnaires pour les trois événements tactiles de base les plus courants :

Dans cette section, nous supposons que vous avez créé un fournisseur d’affichage pour votre application Windows Runtime, en utilisant DirectX. Si tel n’est pas le cas, consultez la section Comment configurer une application Windows Runtime pour afficher une vue DirectX.

Remplissons d’abord les gestionnaires d’événements de pointeur tactile. Dans le premier gestionnaire d’événements (OnPointerPressed), nous obtenons les coordonnées x-y du pointeur de la part de l’élément CoreWindow qui gère notre affichage lorsque l’utilisateur clique sur la souris ou touche l’écran. Définissez les gestionnaires dans vos implémentations de l’élément IFrameworkView::Initialize ou IFrameworkView::SetWindow. (Le présent exemple utilise 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);
    
        }

Remarque  Si vous utilisez la technologie interop DirectX et XAML, XAML fournit son propre affichage (FrameworkView). Inscrivez-vous plutôt pour obtenir les événements de pointeur fournis sur les types UIElement pour les éléments XAML de votre disposition. Pour en savoir plus, consultez la section Démarrage rapide : gestion des entrées de pointeur.

Créez maintenant les rappels correspondants pour obtenir et gérer les données de pointeur. Si votre application n’utilise pas l’élément GestureRecognizer pour interpréter ces données et événements de pointeur, effectuez le suivi des valeurs d’ID de pointeur pour effectuer la distinction entre les pointeurs sur les périphériques tactiles multipoints. (La plupart des surfaces tactiles sont multipoints, ce qui signifie que la plupart des pointeurs peuvent être activés en même temps.) Effectuez le suivi de l’ID et de la position du pointeur pour chaque événement, de façon à pouvoir exécuter l’action correcte pour le mouvement associé au pointeur.

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.

}
        

Remarque  L’élément XMFLOAT2 est défini dans le fichier DirectXMath.h.

Le gestionnaire d’événements OnPointerMoved se déclenche chaque fois que le pointeur se déplace, sur chaque graduation que l’utilisateur le fait glisser sur l’écran. Utilisez l’exemple de code suivant pour que l’application connaisse l’emplacement actuel du pointeur en déplacement :

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

Pour finir, nous devons cesser d’enregistrer l’entrée tactile et, si possible, interpréter le mouvement lorsque l’utilisateur cesse de toucher l’écran.

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

Dans cet exemple, le code extrait simplement la valeur actuelle de l’ID de pointeur et la position de ce pointeur. C’est à vous d’interpréter ces données. Pour l’activation du contrôle, la gestion de l’événement PointerPressed est suffisante. Pour les actions tactiles plus complexes, vous devez créer certaines variables ou méthodes pour capturer l’ID et la position initiale du pointeur pour le mouvement tactile, et mettre à jour ces variables ou appeler ces méthodes à mesure que le pointeur est déplacé et relâché.

Conversion d’événements tactiles en mouvements

Maintenant que votre application peut détecter l’entrée tactile avec des rappels pour les événements tactiles de base, elle doit interpréter ces événements. L’une des manières de procéder consiste à utiliser la classe GestureRecognizer. Un objet GestureRecognizer prend les événements de pointeur (tels que PointerPressed, PointerMoved et PointerReleased), les traite et fournit des événements de son propre chef (tels que Tapped, Holding ou Dragging). Ces événements de niveau supérieur sont appelés mouvements, et sont conçus pour répondre aux besoins les plus courants des applications en matière d’interaction utilisateur.

Remarque  Si votre scène comporte plusieurs objets ou contrôles qui doivent être manipulés indépendamment et simultanément, envisagez d’utiliser un autre élément GestureRecognizer pour chacun d’eux.

Voici comment utiliser l’élément GestureRecognizer avec les événements tactiles que vous avez traités dans la section précédente.

  1. Créez au moins un objet GestureRecognizer pour votre application et initialisez son GestureSettings pour chaque mouvement que vous voulez prendre en charge. Voici quelques exemples de mouvements :

    • Appuyer. L’utilisateur appuie une ou deux fois sur la surface tactile.
    • Maintenir. L’utilisateur appuie sur la surface et maintient l’appui pendant un certain laps de temps.
    • Glisser. L’utilisateur appuie sur la surface et déplace l’appui dans une certaine direction.
    • Manipuler. L’utilisateur effectue un mouvement de glissement, de pincement ou d’étirement pour mettre à l’échelle, agrandir ou faire pivoter l’affichage ou un objet.

    Il existe un ensemble d’événements sur l’élément, GestureRecognizer que vous pouvez gérer pour ces mouvements, notamment :

    Voyons comment s’inscrire pour ces événements et fournir à l’élément GestureRecognizer les données d’entrée tactile dont il a besoin pour identifier ces événements. Dans cet exemple, vous ajoutez le code suivant à votre implémentation de l’élément IFrameworkView::SetWindow afin de créer un élément GestureRecognizer pour le mouvement de double appui et pour l’enregistrement d’un gestionnaire pour l’événement GestureRecognizer::Tapped. La reconnaissance de mouvement est déclarée comme suit :

    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. Créez des gestionnaires dans votre application pour les mouvements que vous souhaitez interpréter, puis raccordez-les aux événements de l’élément GestureRecognizer. Dans l’exemple, vous créez un gestionnaire unique sur la classe de fournisseur d’affichage, OnTapped, afin de gérer l’événement d’appui :

    
    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. Toutefois, pour que l’objet GestureRecognizer obtienne les données d’entrée tactile pour ces événements, vous devez les lui fournir en lui passant les données de pointeur à partir des gestionnaires d’événements d’entrée tactile de base (comme OnPointerPressed dans notre exemple précédent).

    Pour cela, faites en sorte que les gestionnaires d’événements d’entrée tactile de base de votre application (PointerPressed, PointerReleased, et PointerMoved) appellent les méthodes ProcessDownEvent, ProcessUpEventet ProcessMoveEvents correspondantes sur votre objet 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()); 
    } 
     
    
    
    

    Maintenant, l’objet GestureRecognizer peut effectuer le suivi de la séquence d’entrées et, lorsqu’il rencontre un ensemble d’entrées qui correspond à un mouvement, déclencher un événement—dans le cas présent, l’événement GestureRecognizer::Tapped.

Dans les scénarios plus complexes, en particulier ceux qui comportent plusieurs objets GestureRecognizer, vous devez identifier les instances GestureRecognizer qui sont actives d’après des tests de positionnement tactile.

Distribution de messages d’événements

Dans la méthode IFrameworkView::Run que vous avez mise en œuvre sur le fournisseur d’affichage de votre application, vous avez créé votre boucle de traitement principale. Dans cette boucle, appelez CoreEventDispatcher::ProcessEvents pour le répartiteur d’événements sur la classe CoreWindow de votre application, comme suit :

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

La valeur d’énumération CoreProcessEventsOption::ProcessAllIfPresent indique à la méthode ProcessEvents qu’elle doit distribuer les rappels pour chaque événement contenu dans la file d’attente des messages au moment où la méthode ProcessEvents est appelée. Ce faisant, votre application gère les modifications de l’entrée tactile utilisateur et met à jour les données de votre pointeur de telle sorte qu’elles sont synchronisées avec le rendu, ce qui permet de conserver un retour fluide. Utilisez cette valeur CoreProcessEventsOption si votre application comporte une boucle de rendu à exécution constante pilotée par le minuteur et que vous souhaitez traiter vos événements d’entrée sur un minuteur ou à chaque itération de la boucle. Là encore, vous devez appeler cette valeur à chaque itération de la boucle ou à chaque intervalle du minuteur.

En guise d’alternative, votre application peut basculer en pause ou à l’état d’exécution en arrière-plan lorsque le rendu est suspendu. Dans ce cas, lors du basculement vers cet état, appelez ProcessEvents avec CoreProcessEventsOption::ProcessOneAndAllPending, ce qui traite tous les messages d’événements actuels et en attente lorsque votre application est mise en pause ou suspendue.

L’exemple de code suivant pour une implémentation de IFrameworkView::Run choisit parmi les deux valeurs de CoreProcessEventsOption pour ProcessEvents en fonction de l’état de l’application :


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

Pour plus d’informations sur la distribution des messages d’événements, voir Utilisation de messages d’événements et de CoreWindow (DirectX et C++).

Exemples DirectX d’entrée tactile

Voici quelques exemples de code complets qui illustrent la prise en charge des mouvements et de l’entrée tactile pour une application Windows Runtime utilisant DirectX :

Rubriques associées

Démarrage rapide : gestion des entrées de pointeur
Réponse à l’interaction utilisateur (DirectX et C++)
Utilisation de messages d’événements et de CoreWindow (DirectX et C++)

 

 

Afficher:
© 2015 Microsoft