Partager via


Contrôler l’entrée du pointeur

Recevez, traitez et gérez les données d’entrée à partir de périphériques pointant (par exemple, tactile, souris, stylet/stylet et pavé tactile) dans vos applications Windows.

Important

Créez des interactions personnalisées uniquement s’il existe une exigence claire et bien définie et que les interactions prises en charge par les contrôles de plateforme ne prennent pas en charge votre scénario.
Si vous personnalisez les expériences d’interaction dans votre application Windows, les utilisateurs s’attendent à ce qu’ils soient cohérents, intuitifs et détectables. Pour ces raisons, nous vous recommandons de modéliser vos interactions personnalisées sur celles prises en charge par les contrôles de plateforme. Les contrôles de plateforme fournissent l’expérience complète d’interaction utilisateur de l’application Windows, notamment les interactions standard, les effets physiques animés, les commentaires visuels et l’accessibilité.

API importantes

Pointeurs

La plupart des expériences d’interaction impliquent généralement l’utilisateur identifiant l’objet avec lequel il souhaite interagir en le pointant via des périphériques d’entrée tels que le toucher, la souris, le stylet/stylet et le pavé tactile. Étant donné que les données HID (Human Interface Device) brutes fournies par ces appareils d’entrée incluent de nombreuses propriétés courantes, les données sont promues et consolidées dans une pile d’entrée unifiée et exposées en tant que données pointeurs indépendantes de l’appareil. Vos applications Windows peuvent ensuite consommer ces données sans vous soucier de l’appareil d’entrée utilisé.

Remarque

Les informations spécifiques à l’appareil sont également promues à partir des données HID brutes si votre application en a besoin.

Chaque point d’entrée (ou contact) sur la pile d’entrée est représenté par un objet Pointer exposé via le paramètre PointerRoutedEventArgs dans les différents gestionnaires d’événements de pointeur. Dans le cas d’une entrée multi-stylet ou multi-tactile, chaque contact est traité comme un pointeur d’entrée unique.

Événements de pointeur

Les événements de pointeur exposent des informations de base telles que le type d’appareil d’entrée et l’état de détection (en plage ou en contact) et des informations étendues telles que l’emplacement, la pression et la géométrie du contact. En outre, des propriétés spécifiques de l’appareil, telles que le bouton de la souris sur lequel un utilisateur a appuyé ou si l’info-bulle de gomme du stylet est utilisée, sont également disponibles. Si votre application doit faire la distinction entre les appareils d’entrée et leurs fonctionnalités, consultez Identifier les appareils d’entrée.

Les applications Windows peuvent écouter les événements de pointeur suivants :

Remarque

Limitez l’entrée de pointeur à un élément d’interface utilisateur spécifique en appelant CapturePointer sur cet élément dans un gestionnaire d’événements de pointeur. Lorsqu’un pointeur est capturé par un élément, seul cet objet reçoit des événements d’entrée de pointeur, même lorsque le pointeur se déplace en dehors de la zone englobante de l’objet. L’IsInContact (bouton de la souris enfoncé, tactile ou stylet en contact) doit être vrai pour que CapturePointer réussisse.

Event Description

PointerCanceled

Se produit lorsqu’un pointeur est annulé par la plateforme. Cela peut se produire dans les circonstances suivantes :

  • Les pointeurs tactiles sont annulés lorsqu’un stylet est détecté dans la plage de la surface d’entrée.
  • Un contact actif n’est pas détecté pour plus de 100 ms.
  • Le moniteur/l’affichage est modifié (résolution, paramètres, configuration multi-mon).
  • Le bureau est verrouillé ou l’utilisateur s’est déconnecté.
  • Le nombre de contacts simultanés a dépassé le nombre pris en charge par l’appareil.

PointerCaptureLost

Se produit lorsqu’un autre élément d’interface utilisateur capture le pointeur, que le pointeur a été libéré ou qu’un autre pointeur a été capturé par programmation.

Notez qu’aucun événement de capture de pointeur correspondant n’est présent.
 

PointerEntered

Se produit lorsqu’un pointeur entre dans la zone englobante d’un élément. Cela peut se produire de manière légèrement différente pour l’entrée tactile, tactile, souris et stylet.

  • Le contact tactile nécessite un contact doigt pour déclencher cet événement, soit à partir d’une pression directe sur l’élément, soit de se déplacer dans la zone englobante de l’élément.
  • La souris et le pavé tactile ont tous deux un curseur à l’écran qui est toujours visible et déclenche cet événement même si aucun bouton souris ou pavé tactile n’est enfoncé.
  • Comme le toucher, le stylet déclenche cet événement avec un stylet direct vers le bas sur l’élément ou de se déplacer dans la zone englobante de l’élément. Toutefois, le stylet a également un état de pointage (IsInRange) qui, lorsqu’il est vrai, déclenche cet événement.

PointerExited

Se produit lorsqu’un pointeur quitte la zone englobante d’un élément. Cela peut se produire de manière légèrement différente pour l’entrée tactile, tactile, souris et stylet.

  • Le contact tactile nécessite un contact doigt et déclenche cet événement lorsque le pointeur se déplace hors de la zone englobante de l’élément.
  • La souris et le pavé tactile ont tous deux un curseur à l’écran qui est toujours visible et déclenche cet événement même si aucun bouton souris ou pavé tactile n’est enfoncé.
  • Comme l’interaction tactile, le stylet déclenche cet événement lors du déplacement hors de la zone englobante de l’élément. Toutefois, le stylet a également un état de pointage (IsInRange) qui déclenche cet événement lorsque l’état passe de true à false.

PointerMoved

Se produit lorsqu’un pointeur modifie les coordonnées, l’état du bouton, la pression, l’inclinaison ou la géométrie de contact (par exemple, largeur et hauteur) dans la zone englobante d’un élément. Cela peut se produire de manière légèrement différente pour l’entrée tactile, tactile, souris et stylet.

  • Le contact tactile nécessite un contact doigt et déclenche cet événement uniquement lorsqu’il est en contact dans la zone englobante de l’élément.
  • La souris et le pavé tactile ont tous deux un curseur à l’écran qui est toujours visible et déclenche cet événement même si aucun bouton souris ou pavé tactile n’est enfoncé.
  • À l’instar de l’interaction tactile, le stylet déclenche cet événement en contact dans la zone englobante de l’élément. Toutefois, le stylet a également un état de pointage (IsInRange) qui, lorsqu’il est vrai et dans la zone englobante de l’élément, déclenche cet événement.

PointerPressed

Se produit lorsque le pointeur indique une action de presse (par exemple, un bouton tactile, un bouton de souris vers le bas, un stylet vers le bas ou un bouton du pavé tactile) dans la zone englobante d’un élément.

CapturePointer doit être appelé à partir du gestionnaire pour cet événement.

PointerReleased

Se produit lorsque le pointeur indique une action de mise en production (par exemple, un bouton tactile vers le haut, un stylet ou un bouton du pavé tactile) dans la zone englobante d’un élément ou, si le pointeur est capturé, en dehors de la zone englobante.

PointerWheelChanged

Se produit lorsque la roulette de la souris est actionnée.

L’entrée de la souris est associée à un pointeur unique affecté lorsque l’entrée de la souris est détectée pour la première fois. Cliquer sur un bouton de la souris (gauche, roue ou droite) crée une association secondaire entre le pointeur et ce bouton via l’événement PointerMoved .

 

Exemple d’événement de pointeur

Voici quelques extraits de code d’une application de suivi de pointeur de base qui montrent comment écouter et gérer des événements pour plusieurs pointeurs et obtenir différentes propriétés pour les pointeurs associés.

Interface utilisateur de l’application pointeur

Téléchargez cet exemple à partir de l’exemple d’entrée de pointeur (de base)

Créer l’interface utilisateur

Pour cet exemple, nous utilisons un Rectangle (Target) comme entrée de pointeur consommant l’objet. La couleur de la cible change lorsque l’état du pointeur change.

Les détails de chaque pointeur sont affichés dans un TextBlock flottant qui suit le pointeur au fur et à mesure qu’il se déplace. Les événements de pointeur eux-mêmes sont signalés dans RichTextBlock à droite du rectangle.

Il s’agit du langage XAML (Extensible Application Markup Language) de l’interface utilisateur dans cet exemple.

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="250"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="320" />
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Canvas Name="Container" 
            Grid.Column="0"
            Grid.Row="1"
            HorizontalAlignment="Center" 
            VerticalAlignment="Center" 
            Margin="245,0" 
            Height="320"  Width="640">
        <Rectangle Name="Target" 
                    Fill="#FF0000" 
                    Stroke="Black" 
                    StrokeThickness="0"
                    Height="320" Width="640" />
    </Canvas>
    <Grid Grid.Column="1" Grid.Row="0" Grid.RowSpan="3">
        <Grid.RowDefinitions>
            <RowDefinition Height="50" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Button Name="buttonClear" 
                Grid.Row="0"
                Content="Clear"
                Foreground="White"
                HorizontalAlignment="Stretch" 
                VerticalAlignment="Stretch">
        </Button>
        <ScrollViewer Name="eventLogScrollViewer" Grid.Row="1" 
                        VerticalScrollMode="Auto" 
                        Background="Black">                
            <RichTextBlock Name="eventLog"  
                        TextWrapping="Wrap" 
                        Foreground="#FFFFFF" 
                        ScrollViewer.VerticalScrollBarVisibility="Visible" 
                        ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                        Grid.ColumnSpan="2">
            </RichTextBlock>
        </ScrollViewer>
    </Grid>
</Grid>

Écouter les événements de pointeur

Dans la plupart des cas, nous vous recommandons d’obtenir des informations de pointeur via pointerRoutedEventArgs du gestionnaire d’événements.

Si l’argument d’événement n’expose pas les détails du pointeur requis, vous pouvez accéder aux informations Pointeur étendues exposées via les méthodes GetCurrentPoint et GetIntermediatePoints de PointerRoutedEventArgs.

Le code suivant configure l’objet dictionnaire global pour le suivi de chaque pointeur actif et identifie les différents écouteurs d’événements de pointeur pour l’objet cible.

// Dictionary to maintain information about each active pointer. 
// An entry is added during PointerPressed/PointerEntered events and removed 
// during PointerReleased/PointerCaptureLost/PointerCanceled/PointerExited events.
Dictionary<uint, Windows.UI.Xaml.Input.Pointer> pointers;

public MainPage()
{
    this.InitializeComponent();

    // Initialize the dictionary.
    pointers = new Dictionary<uint, Windows.UI.Xaml.Input.Pointer>();

    // Declare the pointer event handlers.
    Target.PointerPressed += 
        new PointerEventHandler(Target_PointerPressed);
    Target.PointerEntered += 
        new PointerEventHandler(Target_PointerEntered);
    Target.PointerReleased += 
        new PointerEventHandler(Target_PointerReleased);
    Target.PointerExited += 
        new PointerEventHandler(Target_PointerExited);
    Target.PointerCanceled += 
        new PointerEventHandler(Target_PointerCanceled);
    Target.PointerCaptureLost += 
        new PointerEventHandler(Target_PointerCaptureLost);
    Target.PointerMoved += 
        new PointerEventHandler(Target_PointerMoved);
    Target.PointerWheelChanged += 
        new PointerEventHandler(Target_PointerWheelChanged);

    buttonClear.Click += 
        new RoutedEventHandler(ButtonClear_Click);
}

Gérer les événements de pointeur

Ensuite, nous utilisons les commentaires de l’interface utilisateur pour illustrer les gestionnaires d’événements de pointeur de base.

/// <summary>
/// The pointer pressed event handler.
/// PointerPressed and PointerReleased don't always occur in pairs. 
/// Your app should listen for and handle any event that can conclude 
/// a pointer down (PointerExited, PointerCanceled, PointerCaptureLost).
/// </summary>
/// <param name="sender">Source of the pointer event.</param>
/// <param name="e">Event args for the pointer routed event.</param>
void Target_PointerPressed(object sender, PointerRoutedEventArgs e)
{
    // Prevent most handlers along the event route from handling the same event again.
    e.Handled = true;

    PointerPoint ptrPt = e.GetCurrentPoint(Target);

    // Update event log.
    UpdateEventLog("Down: " + ptrPt.PointerId);

    // Lock the pointer to the target.
    Target.CapturePointer(e.Pointer);

    // Update event log.
    UpdateEventLog("Pointer captured: " + ptrPt.PointerId);

    // Check if pointer exists in dictionary (ie, enter occurred prior to press).
    if (!pointers.ContainsKey(ptrPt.PointerId))
    {
        // Add contact to dictionary.
        pointers[ptrPt.PointerId] = e.Pointer;
    }

    // Change background color of target when pointer contact detected.
    Target.Fill = new SolidColorBrush(Windows.UI.Colors.Green);

    // Display pointer details.
    CreateInfoPop(ptrPt);
}
  • Ce gestionnaire gère l’événement PointerEntered . Nous ajoutons l’événement au journal des événements, ajoutez le pointeur à la collection de pointeurs et affichons les détails du pointeur.
/// <summary>
/// The pointer entered event handler.
/// We do not capture the pointer on this event.
/// </summary>
/// <param name="sender">Source of the pointer event.</param>
/// <param name="e">Event args for the pointer routed event.</param>
private void Target_PointerEntered(object sender, PointerRoutedEventArgs e)
{
    // Prevent most handlers along the event route from handling the same event again.
    e.Handled = true;

    PointerPoint ptrPt = e.GetCurrentPoint(Target);

    // Update event log.
    UpdateEventLog("Entered: " + ptrPt.PointerId);

    // Check if pointer already exists (if enter occurred prior to down).
    if (!pointers.ContainsKey(ptrPt.PointerId))
    {
        // Add contact to dictionary.
        pointers[ptrPt.PointerId] = e.Pointer;
    }

    if (pointers.Count == 0)
    {
        // Change background color of target when pointer contact detected.
        Target.Fill = new SolidColorBrush(Windows.UI.Colors.Blue);
    }

    // Display pointer details.
    CreateInfoPop(ptrPt);
}
  • Ce gestionnaire gère l’événement PointerMoved . Nous ajoutons l’événement au journal des événements et mettons à jour les détails du pointeur.

    Important

    L’entrée de la souris est associée à un pointeur unique affecté lorsque l’entrée de la souris est détectée pour la première fois. Cliquer sur un bouton de la souris (gauche, roue ou droite) crée une association secondaire entre le pointeur et ce bouton via l’événement PointerPressed . L’événement PointerReleased est déclenché uniquement lorsque ce même bouton de la souris est libéré (aucun autre bouton ne peut être associé au pointeur tant que cet événement n’est pas terminé). En raison de cette association exclusive, d’autres clics de bouton de souris sont routés via l’événement PointerMoved .  

/// <summary>
/// The pointer moved event handler.
/// </summary>
/// <param name="sender">Source of the pointer event.</param>
/// <param name="e">Event args for the pointer routed event.</param>
private void Target_PointerMoved(object sender, PointerRoutedEventArgs e)
{
    // Prevent most handlers along the event route from handling the same event again.
    e.Handled = true;

    PointerPoint ptrPt = e.GetCurrentPoint(Target);

    // Multiple, simultaneous mouse button inputs are processed here.
    // Mouse input is associated with a single pointer assigned when 
    // mouse input is first detected. 
    // Clicking additional mouse buttons (left, wheel, or right) during 
    // the interaction creates secondary associations between those buttons 
    // and the pointer through the pointer pressed event. 
    // The pointer released event is fired only when the last mouse button 
    // associated with the interaction (not necessarily the initial button) 
    // is released. 
    // Because of this exclusive association, other mouse button clicks are 
    // routed through the pointer move event.          
    if (ptrPt.PointerDevice.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse)
    {
        if (ptrPt.Properties.IsLeftButtonPressed)
        {
            UpdateEventLog("Left button: " + ptrPt.PointerId);
        }
        if (ptrPt.Properties.IsMiddleButtonPressed)
        {
            UpdateEventLog("Wheel button: " + ptrPt.PointerId);
        }
        if (ptrPt.Properties.IsRightButtonPressed)
        {
            UpdateEventLog("Right button: " + ptrPt.PointerId);
        }
    }

    // Display pointer details.
    UpdateInfoPop(ptrPt);
}
  • Ce gestionnaire gère l’événement PointerWheelChanged . Nous ajoutons l’événement au journal des événements, ajoutez le pointeur au tableau de pointeurs (si nécessaire) et affichons les détails du pointeur.
/// <summary>
/// The pointer wheel event handler.
/// </summary>
/// <param name="sender">Source of the pointer event.</param>
/// <param name="e">Event args for the pointer routed event.</param>
private void Target_PointerWheelChanged(object sender, PointerRoutedEventArgs e)
{
    // Prevent most handlers along the event route from handling the same event again.
    e.Handled = true;

    PointerPoint ptrPt = e.GetCurrentPoint(Target);

    // Update event log.
    UpdateEventLog("Mouse wheel: " + ptrPt.PointerId);

    // Check if pointer already exists (for example, enter occurred prior to wheel).
    if (!pointers.ContainsKey(ptrPt.PointerId))
    {
        // Add contact to dictionary.
        pointers[ptrPt.PointerId] = e.Pointer;
    }

    // Display pointer details.
    CreateInfoPop(ptrPt);
}
  • Ce gestionnaire gère l’événement PointerReleased où le contact avec le numériseur est arrêté. Nous ajoutons l’événement au journal des événements, supprimez le pointeur de la collection de pointeurs et mettez à jour les détails du pointeur.
/// <summary>
/// The pointer released event handler.
/// PointerPressed and PointerReleased don't always occur in pairs. 
/// Your app should listen for and handle any event that can conclude 
/// a pointer down (PointerExited, PointerCanceled, PointerCaptureLost).
/// </summary>
/// <param name="sender">Source of the pointer event.</param>
/// <param name="e">Event args for the pointer routed event.</param>
void Target_PointerReleased(object sender, PointerRoutedEventArgs e)
{
    // Prevent most handlers along the event route from handling the same event again.
    e.Handled = true;

    PointerPoint ptrPt = e.GetCurrentPoint(Target);

    // Update event log.
    UpdateEventLog("Up: " + ptrPt.PointerId);

    // If event source is mouse or touchpad and the pointer is still 
    // over the target, retain pointer and pointer details.
    // Return without removing pointer from pointers dictionary.
    // For this example, we assume a maximum of one mouse pointer.
    if (ptrPt.PointerDevice.PointerDeviceType != Windows.Devices.Input.PointerDeviceType.Mouse)
    {
        // Update target UI.
        Target.Fill = new SolidColorBrush(Windows.UI.Colors.Red);

        DestroyInfoPop(ptrPt);

        // Remove contact from dictionary.
        if (pointers.ContainsKey(ptrPt.PointerId))
        {
            pointers[ptrPt.PointerId] = null;
            pointers.Remove(ptrPt.PointerId);
        }

        // Release the pointer from the target.
        Target.ReleasePointerCapture(e.Pointer);

        // Update event log.
        UpdateEventLog("Pointer released: " + ptrPt.PointerId);
    }
    else
    {
        Target.Fill = new SolidColorBrush(Windows.UI.Colors.Blue);
    }
}
  • Ce gestionnaire gère l’événement PointerExited (lorsque le contact avec le numériseur est conservé). Nous ajoutons l’événement au journal des événements, supprimez le pointeur du tableau de pointeurs et mettons à jour les détails du pointeur.
/// <summary>
/// The pointer exited event handler.
/// </summary>
/// <param name="sender">Source of the pointer event.</param>
/// <param name="e">Event args for the pointer routed event.</param>
private void Target_PointerExited(object sender, PointerRoutedEventArgs e)
{
    // Prevent most handlers along the event route from handling the same event again.
    e.Handled = true;

    PointerPoint ptrPt = e.GetCurrentPoint(Target);

    // Update event log.
    UpdateEventLog("Pointer exited: " + ptrPt.PointerId);

    // Remove contact from dictionary.
    if (pointers.ContainsKey(ptrPt.PointerId))
    {
        pointers[ptrPt.PointerId] = null;
        pointers.Remove(ptrPt.PointerId);
    }

    if (pointers.Count == 0)
    {
        Target.Fill = new SolidColorBrush(Windows.UI.Colors.Red);
    }

    // Update the UI and pointer details.
    DestroyInfoPop(ptrPt);
}
  • Ce gestionnaire gère l’événement PointerCanceled . Nous ajoutons l’événement au journal des événements, supprimez le pointeur du tableau de pointeurs et mettons à jour les détails du pointeur.
/// <summary>
/// The pointer canceled event handler.
/// Fires for various reasons, including: 
///    - Touch contact canceled by pen coming into range of the surface.
///    - The device doesn't report an active contact for more than 100ms.
///    - The desktop is locked or the user logged off. 
///    - The number of simultaneous contacts exceeded the number supported by the device.
/// </summary>
/// <param name="sender">Source of the pointer event.</param>
/// <param name="e">Event args for the pointer routed event.</param>
private void Target_PointerCanceled(object sender, PointerRoutedEventArgs e)
{
    // Prevent most handlers along the event route from handling the same event again.
    e.Handled = true;

    PointerPoint ptrPt = e.GetCurrentPoint(Target);

    // Update event log.
    UpdateEventLog("Pointer canceled: " + ptrPt.PointerId);

    // Remove contact from dictionary.
    if (pointers.ContainsKey(ptrPt.PointerId))
    {
        pointers[ptrPt.PointerId] = null;
        pointers.Remove(ptrPt.PointerId);
    }

    if (pointers.Count == 0)
    {
        Target.Fill = new SolidColorBrush(Windows.UI.Colors.Black);
    }

    DestroyInfoPop(ptrPt);
}
/// <summary>
/// The pointer capture lost event handler.
/// Fires for various reasons, including: 
///    - User interactions
///    - Programmatic capture of another pointer
///    - Captured pointer was deliberately released
// PointerCaptureLost can fire instead of PointerReleased. 
/// </summary>
/// <param name="sender">Source of the pointer event.</param>
/// <param name="e">Event args for the pointer routed event.</param>
private void Target_PointerCaptureLost(object sender, PointerRoutedEventArgs e)
{
    // Prevent most handlers along the event route from handling the same event again.
    e.Handled = true;

    PointerPoint ptrPt = e.GetCurrentPoint(Target);

    // Update event log.
    UpdateEventLog("Pointer capture lost: " + ptrPt.PointerId);

    if (pointers.Count == 0)
    {
        Target.Fill = new SolidColorBrush(Windows.UI.Colors.Black);
    }

    // Remove contact from dictionary.
    if (pointers.ContainsKey(ptrPt.PointerId))
    {
        pointers[ptrPt.PointerId] = null;
        pointers.Remove(ptrPt.PointerId);
    }

    DestroyInfoPop(ptrPt);
}

Obtenir les propriétés du pointeur

Comme indiqué précédemment, vous devez obtenir des informations de pointeur étendues à partir d’un objet Windows.UI.Input.PointerPoint obtenu via les méthodes GetCurrentPoint et GetIntermediatePoints de PointerRoutedEventArgs. Les extraits de code suivants montrent comment procéder.

  • Tout d’abord, nous créons un TextBlock pour chaque pointeur.
/// <summary>
/// Create the pointer info popup.
/// </summary>
/// <param name="ptrPt">Reference to the input pointer.</param>
void CreateInfoPop(PointerPoint ptrPt)
{
    TextBlock pointerDetails = new TextBlock();
    pointerDetails.Name = ptrPt.PointerId.ToString();
    pointerDetails.Foreground = new SolidColorBrush(Windows.UI.Colors.White);
    pointerDetails.Text = QueryPointer(ptrPt);

    TranslateTransform x = new TranslateTransform();
    x.X = ptrPt.Position.X + 20;
    x.Y = ptrPt.Position.Y + 20;
    pointerDetails.RenderTransform = x;

    Container.Children.Add(pointerDetails);
}
  • Ensuite, nous fournissons un moyen de mettre à jour les informations de pointeur dans un TextBlock existant associé à ce pointeur.
/// <summary>
/// Update the pointer info popup.
/// </summary>
/// <param name="ptrPt">Reference to the input pointer.</param>
void UpdateInfoPop(PointerPoint ptrPt)
{
    foreach (var pointerDetails in Container.Children)
    {
        if (pointerDetails.GetType().ToString() == "Windows.UI.Xaml.Controls.TextBlock")
        {
            TextBlock textBlock = (TextBlock)pointerDetails;
            if (textBlock.Name == ptrPt.PointerId.ToString())
            {
                // To get pointer location details, we need extended pointer info.
                // We get the pointer info through the getCurrentPoint method
                // of the event argument. 
                TranslateTransform x = new TranslateTransform();
                x.X = ptrPt.Position.X + 20;
                x.Y = ptrPt.Position.Y + 20;
                pointerDetails.RenderTransform = x;
                textBlock.Text = QueryPointer(ptrPt);
            }
        }
    }
}
  • Enfin, nous interrogeons différentes propriétés de pointeur.
/// <summary>
/// Get pointer details.
/// </summary>
/// <param name="ptrPt">Reference to the input pointer.</param>
/// <returns>A string composed of pointer details.</returns>
String QueryPointer(PointerPoint ptrPt)
{
    String details = "";

    switch (ptrPt.PointerDevice.PointerDeviceType)
    {
        case Windows.Devices.Input.PointerDeviceType.Mouse:
            details += "\nPointer type: mouse";
            break;
        case Windows.Devices.Input.PointerDeviceType.Pen:
            details += "\nPointer type: pen";
            if (ptrPt.IsInContact)
            {
                details += "\nPressure: " + ptrPt.Properties.Pressure;
                details += "\nrotation: " + ptrPt.Properties.Orientation;
                details += "\nTilt X: " + ptrPt.Properties.XTilt;
                details += "\nTilt Y: " + ptrPt.Properties.YTilt;
                details += "\nBarrel button pressed: " + ptrPt.Properties.IsBarrelButtonPressed;
            }
            break;
        case Windows.Devices.Input.PointerDeviceType.Touch:
            details += "\nPointer type: touch";
            details += "\nrotation: " + ptrPt.Properties.Orientation;
            details += "\nTilt X: " + ptrPt.Properties.XTilt;
            details += "\nTilt Y: " + ptrPt.Properties.YTilt;
            break;
        default:
            details += "\nPointer type: n/a";
            break;
    }

    GeneralTransform gt = Target.TransformToVisual(this);
    Point screenPoint;

    screenPoint = gt.TransformPoint(new Point(ptrPt.Position.X, ptrPt.Position.Y));
    details += "\nPointer Id: " + ptrPt.PointerId.ToString() +
        "\nPointer location (target): " + Math.Round(ptrPt.Position.X) + ", " + Math.Round(ptrPt.Position.Y) +
        "\nPointer location (container): " + Math.Round(screenPoint.X) + ", " + Math.Round(screenPoint.Y);

    return details;
}

Pointeur principal

Certains appareils d’entrée, tels qu’un numériseur tactile ou un pavé tactile, prennent en charge plus que le pointeur unique classique d’une souris ou d’un stylet (dans la plupart des cas, le Surface Hub prend en charge deux entrées de stylet).

Utilisez la propriété IsPrimary en lecture seule de la classe PointerPointerProperties pour identifier et différencier un pointeur principal unique (le pointeur principal est toujours le premier pointeur détecté pendant une séquence d’entrée).

En identifiant le pointeur principal, vous pouvez l’utiliser pour émuler l’entrée de la souris ou du stylet, personnaliser les interactions ou fournir d’autres fonctionnalités ou interface utilisateur spécifiques.

Remarque

Si le pointeur principal est libéré, annulé ou perdu pendant une séquence d’entrée, un pointeur d’entrée principal n’est pas créé tant qu’une nouvelle séquence d’entrée n’est pas lancée (une séquence d’entrée se termine lorsque tous les pointeurs ont été libérés, annulés ou perdus).

Exemple d’animation de pointeur principal

Ces extraits de code montrent comment vous pouvez fournir des commentaires visuels spéciaux pour aider un utilisateur à différencier les entrées de pointeur dans votre application.

Cette application particulière utilise à la fois la couleur et l’animation pour mettre en surbrillance le pointeur principal.

Application pointeur avec commentaires visuels animés

Téléchargez cet exemple à partir de l’exemple d’entrée de pointeur (UserControl avec animation)

Retour visuel

Nous définissons un UserControl, basé sur un objet Ellipse XAML, qui met en évidence l’endroit où chaque pointeur se trouve sur le canevas et utilise un Storyboard pour animer l’ellipse qui correspond au pointeur principal.

Voici le code XAML :

<UserControl
    x:Class="UWP_Pointers.PointerEllipse"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:UWP_Pointers"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="100"
    d:DesignWidth="100">

    <UserControl.Resources>
        <Style x:Key="EllipseStyle" TargetType="Ellipse">
            <Setter Property="Transitions">
                <Setter.Value>
                    <TransitionCollection>
                        <ContentThemeTransition/>
                    </TransitionCollection>
                </Setter.Value>
            </Setter>
        </Style>
        
        <Storyboard x:Name="myStoryboard">
            <!-- Animates the value of a Double property between 
            two target values using linear interpolation over the 
            specified Duration. -->
            <DoubleAnimation
              Storyboard.TargetName="ellipse"
              Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleY)"  
              Duration="0:0:1" 
              AutoReverse="True" 
              RepeatBehavior="Forever" From="1.0" To="1.4">
            </DoubleAnimation>

            <!-- Animates the value of a Double property between 
            two target values using linear interpolation over the 
            specified Duration. -->
            <DoubleAnimation
              Storyboard.TargetName="ellipse"
              Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleX)"  
              Duration="0:0:1" 
              AutoReverse="True" 
              RepeatBehavior="Forever" From="1.0" To="1.4">
            </DoubleAnimation>

            <!-- Animates the value of a Color property between 
            two target values using linear interpolation over the 
            specified Duration. -->
            <ColorAnimation 
                Storyboard.TargetName="ellipse" 
                EnableDependentAnimation="True" 
                Storyboard.TargetProperty="(Fill).(SolidColorBrush.Color)" 
                From="White" To="Red"  Duration="0:0:1" 
                AutoReverse="True" RepeatBehavior="Forever"/>
        </Storyboard>
    </UserControl.Resources>

    <Grid x:Name="CompositionContainer">
        <Ellipse Name="ellipse" 
        StrokeThickness="2" 
        Width="{x:Bind Diameter}" 
        Height="{x:Bind Diameter}"  
        Style="{StaticResource EllipseStyle}" />
    </Grid>
</UserControl>

Voici le code-behind :

using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;

// The User Control item template is documented at 
// https://go.microsoft.com/fwlink/?LinkId=234236

namespace UWP_Pointers
{
    /// <summary>
    /// Pointer feedback object.
    /// </summary>
    public sealed partial class PointerEllipse : UserControl
    {
        // Reference to the application canvas.
        Canvas canvas;

        /// <summary>
        /// Ellipse UI for pointer feedback.
        /// </summary>
        /// <param name="c">The drawing canvas.</param>
        public PointerEllipse(Canvas c)
        {
            this.InitializeComponent();
            canvas = c;
        }

        /// <summary>
        /// Gets or sets the pointer Id to associate with the PointerEllipse object.
        /// </summary>
        public uint PointerId
        {
            get { return (uint)GetValue(PointerIdProperty); }
            set { SetValue(PointerIdProperty, value); }
        }
        // Using a DependencyProperty as the backing store for PointerId.  
        // This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PointerIdProperty =
            DependencyProperty.Register("PointerId", typeof(uint), 
                typeof(PointerEllipse), new PropertyMetadata(null));


        /// <summary>
        /// Gets or sets whether the associated pointer is Primary.
        /// </summary>
        public bool PrimaryPointer
        {
            get { return (bool)GetValue(PrimaryPointerProperty); }
            set
            {
                SetValue(PrimaryPointerProperty, value);
            }
        }
        // Using a DependencyProperty as the backing store for PrimaryPointer.  
        // This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PrimaryPointerProperty =
            DependencyProperty.Register("PrimaryPointer", typeof(bool), 
                typeof(PointerEllipse), new PropertyMetadata(false));


        /// <summary>
        /// Gets or sets the ellipse style based on whether the pointer is Primary.
        /// </summary>
        public bool PrimaryEllipse 
        {
            get { return (bool)GetValue(PrimaryEllipseProperty); }
            set
            {
                SetValue(PrimaryEllipseProperty, value);
                if (value)
                {
                    SolidColorBrush fillBrush = 
                        (SolidColorBrush)Application.Current.Resources["PrimaryFillBrush"];
                    SolidColorBrush strokeBrush = 
                        (SolidColorBrush)Application.Current.Resources["PrimaryStrokeBrush"];

                    ellipse.Fill = fillBrush;
                    ellipse.Stroke = strokeBrush;
                    ellipse.RenderTransform = new CompositeTransform();
                    ellipse.RenderTransformOrigin = new Point(.5, .5);
                    myStoryboard.Begin();
                }
                else
                {
                    SolidColorBrush fillBrush = 
                        (SolidColorBrush)Application.Current.Resources["SecondaryFillBrush"];
                    SolidColorBrush strokeBrush = 
                        (SolidColorBrush)Application.Current.Resources["SecondaryStrokeBrush"];
                    ellipse.Fill = fillBrush;
                    ellipse.Stroke = strokeBrush;
                }
            }
        }
        // Using a DependencyProperty as the backing store for PrimaryEllipse.  
        // This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PrimaryEllipseProperty =
            DependencyProperty.Register("PrimaryEllipse", 
                typeof(bool), typeof(PointerEllipse), new PropertyMetadata(false));


        /// <summary>
        /// Gets or sets the diameter of the PointerEllipse object.
        /// </summary>
        public int Diameter
        {
            get { return (int)GetValue(DiameterProperty); }
            set { SetValue(DiameterProperty, value); }
        }
        // Using a DependencyProperty as the backing store for Diameter.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DiameterProperty =
            DependencyProperty.Register("Diameter", typeof(int), 
                typeof(PointerEllipse), new PropertyMetadata(120));
    }
}

Créer l’interface utilisateur

L’interface utilisateur de cet exemple est limitée au canevas d’entrée où nous suivons tous les pointeurs et restituons les indicateurs de pointeur et l’animation du pointeur principal (le cas échéant), ainsi qu’une barre d’en-tête contenant un compteur de pointeur et un identificateur de pointeur principal.

Voici le fichier MainPage.xaml :

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <StackPanel x:Name="HeaderPanel" 
                Orientation="Horizontal" 
                Grid.Row="0">
        <StackPanel.Transitions>
            <TransitionCollection>
                <AddDeleteThemeTransition/>
            </TransitionCollection>
        </StackPanel.Transitions>
        <TextBlock x:Name="Header" 
                    Text="Basic pointer tracking sample - IsPrimary" 
                    Style="{ThemeResource HeaderTextBlockStyle}" 
                    Margin="10,0,0,0" />
        <TextBlock x:Name="PointerCounterLabel"
                    VerticalAlignment="Center"                 
                    Style="{ThemeResource BodyTextBlockStyle}"
                    Text="Number of pointers: " 
                    Margin="50,0,0,0"/>
        <TextBlock x:Name="PointerCounter"
                    VerticalAlignment="Center"                 
                    Style="{ThemeResource BodyTextBlockStyle}"
                    Text="0" 
                    Margin="10,0,0,0"/>
        <TextBlock x:Name="PointerPrimaryLabel"
                    VerticalAlignment="Center"                 
                    Style="{ThemeResource BodyTextBlockStyle}"
                    Text="Primary: " 
                    Margin="50,0,0,0"/>
        <TextBlock x:Name="PointerPrimary"
                    VerticalAlignment="Center"                 
                    Style="{ThemeResource BodyTextBlockStyle}"
                    Text="n/a" 
                    Margin="10,0,0,0"/>
    </StackPanel>
    
    <Grid Grid.Row="1">
        <!--The canvas where we render the pointer UI.-->
        <Canvas x:Name="pointerCanvas"/>
    </Grid>
</Grid>

Gérer les événements de pointeur

Enfin, nous définissons nos gestionnaires d’événements de pointeur de base dans le code-behind MainPage.xaml.cs. Nous ne reproduireons pas le code ici, car les principes de base ont été abordés dans l’exemple précédent, mais vous pouvez télécharger l’exemple de travail à partir de l’exemple d’entrée de pointeur (UserControl avec animation).

Exemples de la rubrique

Autres exemples

Exemples d’archive