Interazioni con sguardi e rilevamento degli occhi nelle app di WindowsGaze interactions and eye tracking in Windows apps

Eroe di rilevamento occhi

Fornire il supporto per tenere traccia degli sguardi, dell'attenzione e della presenza di un utente in base alla posizione e allo spostamento degli occhi.Provide support for tracking a user's gaze, attention, and presence based on the location and movement of their eyes.

Nota

Per l'input dello sguardo nella realtà mista di Windows, vedere sguardi.For gaze input in Windows Mixed Reality, see Gaze.

API importanti : Windows. Devices. input. Preview, GazeDevicePreview, GazePointPreview, GazeInputSourcePreviewImportant APIs : Windows.Devices.Input.Preview, GazeDevicePreview, GazePointPreview, GazeInputSourcePreview

PanoramicaOverview

L'input di sguardi è un modo efficace per interagire e usare applicazioni Windows particolarmente utili come tecnologia per l'accessibilità per gli utenti con malattie neuro-muscolari (ad esempio ALS) e altre disabilità che coinvolgono funzioni muscolari o nervose non associate.Gaze input is a powerful way to interact and use Windows applications that is especially useful as an assistive technology for users with neuro-muscular diseases (such as ALS) and other disabilities involving impaired muscle or nerve functions.

L'input di sguardi offre anche opportunità ugualmente interessanti sia per i giochi (incluse le acquisizioni di destinazione sia per il rilevamento) e per le applicazioni di produttività tradizionali, i chioschi e altri scenari interattivi in cui i dispositivi di input tradizionali (tastiera, mouse, tocco) non sono disponibili o dove potrebbero essere utili o utili per liberare le mani dell'utente per altre attività, ad esempio la conservazione dei sacchetti diIn addition, gaze input offers equally compelling opportunities for both gaming (including target acquisition and tracking) and traditional productivity applications, kiosks, and other interactive scenarios where traditional input devices (keyboard, mouse, touch) are not available, or where it might be useful/helpful to free up the user's hands for other tasks (such as holding shopping bags).

Nota

Il supporto per l'hardware di rilevamento degli occhi è stato introdotto in Windows 10 Fall Creators Update insieme al controllo deglisguardi, una funzionalità incorporata che consente di usare gli occhi per controllare il puntatore sullo schermo, digitare con la tastiera sullo schermo e comunicare con gli utenti che usano la sintesi vocale.Support for eye tracking hardware was introduced in Windows 10 Fall Creators Update along with Eye control, a built-in feature that lets you use your eyes to control the on-screen pointer, type with the on-screen keyboard, and communicate with people using text-to-speech. Un set di API di Windows Runtime ( Windows. Devices. input. Preview) per la creazione di applicazioni che possono interagire con l'hardware di monitoraggio degli occhi è disponibile con l' aggiornamento di windows 10 aprile 2018 (versione 1803, Build 17134) e versioni successive.A set of Windows Runtime APIs ( Windows.Devices.Input.Preview) for building applications that can interact with eye tracking hardware is available with Windows 10 April 2018 Update (Version 1803, build 17134) and newer.

PrivacyPrivacy

A causa dei dati personali potenzialmente sensibili raccolti dai dispositivi di rilevamento degli occhi, è necessario dichiarare la gazeInput funzionalità nel manifesto dell'applicazione (vedere la sezione seguente relativa all' installazione ).Due to the potentially sensitive personal data collected by eye tracking devices, you are required to declare the gazeInput capability in the app manifest of your application (see the following Setup section). Quando viene dichiarata, Windows chiede automaticamente agli utenti una finestra di dialogo di consenso (quando l'app viene eseguita per la prima volta), in cui l'utente deve concedere l'autorizzazione affinché l'app comunichi con il dispositivo di rilevamento degli occhi e acceda a questi dati.When declared, Windows automatically prompts users with a consent dialog (when the app is first run), where the user must grant permission for the app to communicate with the eye-tracking device and access this data.

Inoltre, se l'app raccoglie, archivia o trasferisce i dati di rilevamento degli occhi, è necessario descriverli nell'informativa sulla privacy dell'app e seguire tutti gli altri requisiti per le informazioni personali nel contratto per sviluppatori di app e i criteri di Microsoft Store.In addition, if your app collects, stores, or transfers eye tracking data, you must describe this in your app's privacy statement and follow all other requirements for Personal Information in the App Developer Agreement and the Microsoft Store Policies.

ConfigurazioneSetup

Per usare le API di input di sguardi nell'app di Windows, è necessario:To use the gaze input APIs in your Windows app you'll need to:

  • Specificare la gazeInput funzionalità nel manifesto dell'applicazione.Specify the gazeInput capability in the app manifest.

    Aprire il file Package. appxmanifest con Progettazione manifesto di Visual Studio o aggiungere manualmente la funzionalità selezionando Visualizza codice e inserendo quanto segue DeviceCapability nel Capabilities nodo:Open the Package.appxmanifest file with the Visual Studio manifest designer, or add the capability manually by selecting View code , and inserting the following DeviceCapability into the Capabilities node:

    <Capabilities>
       <DeviceCapability Name="gazeInput" />
    </Capabilities>
    
  • Un dispositivo con rilevamento degli occhi compatibile con Windows connesso al sistema (incorporato o periferico) e attivato.A Windows-compatible eye-tracking device connected to your system (either built-in or peripheral) and turned on.

    Per un elenco dei dispositivi di rilevamento degli occhi supportati, vedere Introduzione al controllo degli occhi in Windows 10 .See Get started with eye control in Windows 10 for a list of supported eye-tracking devices.

Rilevamento degli occhi di baseBasic eye tracking

In questo esempio viene illustrato come tenere traccia dello sguardo dell'utente all'interno di un'app di Windows e usare una funzione di temporizzazione con hit testing di base per indicare in che modo è possibile mantenere lo stato attivo sullo sguardo di un elemento specifico.In this example, we demonstrate how to track the user's gaze within a Windows app and use a timing function with basic hit testing to indicate how well they can maintain their gaze focus on a specific element.

Una piccola ellisse viene utilizzata per mostrare dove il punto di osservazione si trova all'interno del viewport dell'applicazione, mentre un RadialProgressBar di Windows community Toolkit viene inserito in modo casuale nell'area di disegno.A small ellipse is used to show where the gaze point is within the application viewport, while a RadialProgressBar from the Windows Community Toolkit is placed randomly on the canvas. Quando viene rilevato lo stato attivo dello sguardo sull'indicatore di stato, viene avviato un timer e l'indicatore di stato viene rilocato in modo casuale nell'area di disegno quando l'indicatore di stato raggiunge il 100%.When gaze focus is detected on the progress bar, a timer is started and the progress bar is randomly relocated on the canvas when the progress bar reaches 100%.

Esempio di rilevamento degli sguardi con timer

Esempio di rilevamento degli sguardi con timerGaze tracking with timer sample

Scaricare questo esempio dall' esempio di input di sguardi (Basic)Download this sample from Gaze input sample (basic)

  1. In primo luogo, viene configurata l'interfaccia utente (MainPage. Xaml).First, we set up the UI (MainPage.xaml).

    <Page
        x:Class="gazeinput.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:gazeinput"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"    
        mc:Ignorable="d">
    
        <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
            <Grid x:Name="containerGrid">
                <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="Gaze tracking sample" 
                           Style="{ThemeResource HeaderTextBlockStyle}" 
                           Margin="10,0,0,0" />
                    <TextBlock x:Name="TrackerCounterLabel"
                           VerticalAlignment="Center"                 
                           Style="{ThemeResource BodyTextBlockStyle}"
                           Text="Number of trackers: " 
                           Margin="50,0,0,0"/>
                    <TextBlock x:Name="TrackerCounter"
                           VerticalAlignment="Center"                 
                           Style="{ThemeResource BodyTextBlockStyle}"
                           Text="0" 
                           Margin="10,0,0,0"/>
                    <TextBlock x:Name="TrackerStateLabel"
                           VerticalAlignment="Center"                 
                           Style="{ThemeResource BodyTextBlockStyle}"
                           Text="State: " 
                           Margin="50,0,0,0"/>
                    <TextBlock x:Name="TrackerState"
                           VerticalAlignment="Center"                 
                           Style="{ThemeResource BodyTextBlockStyle}"
                           Text="n/a" 
                           Margin="10,0,0,0"/>
                </StackPanel>
                <Canvas x:Name="gazePositionCanvas" Grid.Row="1">
                    <controls:RadialProgressBar
                        x:Name="GazeRadialProgressBar" 
                        Value="0"
                        Foreground="Blue" 
                        Background="White"
                        Thickness="4"
                        Minimum="0"
                        Maximum="100"
                        Width="100"
                        Height="100"
                        Outline="Gray"
                        Visibility="Collapsed"/>
                    <Ellipse 
                        x:Name="eyeGazePositionEllipse"
                        Width="20" Height="20"
                        Fill="Blue" 
                        Opacity="0.5" 
                        Visibility="Collapsed">
                    </Ellipse>
                </Canvas>
            </Grid>
        </Grid>
    </Page>
    
  2. Si inizia quindi a inizializzare l'app.Next, we initialize our app.

    In questo frammento di codice vengono dichiarati gli oggetti globali ed è stato eseguito l'override dell'evento della pagina OnNavigatedTo per avviare Watcher Device Watcher e l'evento della pagina OnNavigatedFrom per arrestare il Watcher del dispositivo.In this snippet, we declare our global objects and override the OnNavigatedTo page event to start our gaze device watcher and the OnNavigatedFrom page event to stop our gaze device watcher.

    using System;
    using Windows.Devices.Input.Preview;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml;
    using Windows.Foundation;
    using System.Collections.Generic;
    using Windows.UI.Xaml.Media;
    using Windows.UI.Xaml.Navigation;
    
    namespace gazeinput
    {
        public sealed partial class MainPage : Page
        {
            /// <summary>
            /// Reference to the user's eyes and head as detected
            /// by the eye-tracking device.
            /// </summary>
            private GazeInputSourcePreview gazeInputSource;
    
            /// <summary>
            /// Dynamic store of eye-tracking devices.
            /// </summary>
            /// <remarks>
            /// Receives event notifications when a device is added, removed, 
            /// or updated after the initial enumeration.
            /// </remarks>
            private GazeDeviceWatcherPreview gazeDeviceWatcher;
    
            /// <summary>
            /// Eye-tracking device counter.
            /// </summary>
            private int deviceCounter = 0;
    
            /// <summary>
            /// Timer for gaze focus on RadialProgressBar.
            /// </summary>
            DispatcherTimer timerGaze = new DispatcherTimer();
    
            /// <summary>
            /// Tracker used to prevent gaze timer restarts.
            /// </summary>
            bool timerStarted = false;
    
            /// <summary>
            /// Initialize the app.
            /// </summary>
            public MainPage()
            {
                InitializeComponent();
            }
    
            /// <summary>
            /// Override of OnNavigatedTo page event starts GazeDeviceWatcher.
            /// </summary>
            /// <param name="e">Event args for the NavigatedTo event</param>
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                // Start listening for device events on navigation to eye-tracking page.
                StartGazeDeviceWatcher();
            }
    
            /// <summary>
            /// Override of OnNavigatedFrom page event stops GazeDeviceWatcher.
            /// </summary>
            /// <param name="e">Event args for the NavigatedFrom event</param>
            protected override void OnNavigatedFrom(NavigationEventArgs e)
            {
                // Stop listening for device events on navigation from eye-tracking page.
                StopGazeDeviceWatcher();
            }
        }
    }
    
  3. Successivamente, vengono aggiunti i metodi Watcher Device Watcher.Next, we add our gaze device watcher methods.

    In viene StartGazeDeviceWatcher chiamato CreateWatcher e vengono dichiarati i listener di eventi del dispositivo con rilevamento degli occhi (DeviceAdded, DeviceUpdatede DeviceRemoved).In StartGazeDeviceWatcher, we call CreateWatcher and declare the eye-tracking device event listeners (DeviceAdded, DeviceUpdated, and DeviceRemoved).

    In viene DeviceAdded controllato lo stato del dispositivo di rilevamento degli occhi.In DeviceAdded, we check the state of the eye-tracking device. Se un dispositivo valido, si incrementa il numero di dispositivi e si Abilita il rilevamento degli sguardi.If a viable device, we increment our device count and enable gaze tracking. Per informazioni dettagliate, vedere il passaggio successivo.See next step for details.

    In DeviceUpdated è anche possibile abilitare il rilevamento degli sguardi perché questo evento viene attivato se un dispositivo viene ricalibrato.In DeviceUpdated, we also enable gaze tracking as this event is triggered if a device is recalibrated.

    In viene DeviceRemoved decrementato il contatore del dispositivo e vengono rimossi i gestori eventi del dispositivo.In DeviceRemoved, we decrement our device counter and remove the device event handlers.

    In viene StopGazeDeviceWatcher arrestato il Watcher del dispositivo sguardi.In StopGazeDeviceWatcher, we shut down the gaze device watcher.

    /// <summary>
    /// Start gaze watcher and declare watcher event handlers.
    /// </summary>
    private void StartGazeDeviceWatcher()
    {
        if (gazeDeviceWatcher == null)
        {
            gazeDeviceWatcher = GazeInputSourcePreview.CreateWatcher();
            gazeDeviceWatcher.Added += this.DeviceAdded;
            gazeDeviceWatcher.Updated += this.DeviceUpdated;
            gazeDeviceWatcher.Removed += this.DeviceRemoved;
            gazeDeviceWatcher.Start();
        }
    }

    /// <summary>
    /// Shut down gaze watcher and stop listening for events.
    /// </summary>
    private void StopGazeDeviceWatcher()
    {
        if (gazeDeviceWatcher != null)
        {
            gazeDeviceWatcher.Stop();
            gazeDeviceWatcher.Added -= this.DeviceAdded;
            gazeDeviceWatcher.Updated -= this.DeviceUpdated;
            gazeDeviceWatcher.Removed -= this.DeviceRemoved;
            gazeDeviceWatcher = null;
        }
    }

    /// <summary>
    /// Eye-tracking device connected (added, or available when watcher is initialized).
    /// </summary>
    /// <param name="sender">Source of the device added event</param>
    /// <param name="e">Event args for the device added event</param>
    private void DeviceAdded(GazeDeviceWatcherPreview source, 
        GazeDeviceWatcherAddedPreviewEventArgs args)
    {
        if (IsSupportedDevice(args.Device))
        {
            deviceCounter++;
            TrackerCounter.Text = deviceCounter.ToString();
        }
        // Set up gaze tracking.
        TryEnableGazeTrackingAsync(args.Device);
    }

    /// <summary>
    /// Initial device state might be uncalibrated, 
    /// but device was subsequently calibrated.
    /// </summary>
    /// <param name="sender">Source of the device updated event</param>
    /// <param name="e">Event args for the device updated event</param>
    private void DeviceUpdated(GazeDeviceWatcherPreview source,
        GazeDeviceWatcherUpdatedPreviewEventArgs args)
    {
        // Set up gaze tracking.
        TryEnableGazeTrackingAsync(args.Device);
    }

    /// <summary>
    /// Handles disconnection of eye-tracking devices.
    /// </summary>
    /// <param name="sender">Source of the device removed event</param>
    /// <param name="e">Event args for the device removed event</param>
    private void DeviceRemoved(GazeDeviceWatcherPreview source,
        GazeDeviceWatcherRemovedPreviewEventArgs args)
    {
        // Decrement gaze device counter and remove event handlers.
        if (IsSupportedDevice(args.Device))
        {
            deviceCounter--;
            TrackerCounter.Text = deviceCounter.ToString();

            if (deviceCounter == 0)
            {
                gazeInputSource.GazeEntered -= this.GazeEntered;
                gazeInputSource.GazeMoved -= this.GazeMoved;
                gazeInputSource.GazeExited -= this.GazeExited;
            }
        }
    }
  1. Qui viene verificato se il dispositivo è valido in IsSupportedDevice e, in caso affermativo, provare ad abilitare il rilevamento degli sguardi in TryEnableGazeTrackingAsync .Here, we check if the device is viable in IsSupportedDevice and, if so, attempt to enable gaze tracking in TryEnableGazeTrackingAsync.

    In TryEnableGazeTrackingAsync si dichiarano i gestori degli eventi di sguardi e si chiama GazeInputSourcePreview. GetForCurrentView () per ottenere un riferimento all'origine di input (questo deve essere chiamato sul thread UI, vedere Keep the UI thread reattivo).In TryEnableGazeTrackingAsync, we declare the gaze event handlers, and call GazeInputSourcePreview.GetForCurrentView() to get a reference to the input source (this must be called on the UI thread, see Keep the UI thread responsive).

    Nota

    È necessario chiamare GazeInputSourcePreview. GetForCurrentView () solo quando un dispositivo di rilevamento occhi compatibile è connesso e richiesto dall'applicazione.You should call GazeInputSourcePreview.GetForCurrentView() only when a compatible eye-tracking device is connected and required by your application. In caso contrario, la finestra di dialogo di consenso non è necessaria.Otherwise, the consent dialog is unnecessary.

    /// <summary>
    /// Initialize gaze tracking.
    /// </summary>
    /// <param name="gazeDevice"></param>
    private async void TryEnableGazeTrackingAsync(GazeDevicePreview gazeDevice)
    {
        // If eye-tracking device is ready, declare event handlers and start tracking.
        if (IsSupportedDevice(gazeDevice))
        {
            timerGaze.Interval = new TimeSpan(0, 0, 0, 0, 20);
            timerGaze.Tick += TimerGaze_Tick;

            SetGazeTargetLocation();

            // This must be called from the UI thread.
            gazeInputSource = GazeInputSourcePreview.GetForCurrentView();

            gazeInputSource.GazeEntered += GazeEntered;
            gazeInputSource.GazeMoved += GazeMoved;
            gazeInputSource.GazeExited += GazeExited;
        }
        // Notify if device calibration required.
        else if (gazeDevice.ConfigurationState ==
                    GazeDeviceConfigurationStatePreview.UserCalibrationNeeded ||
                    gazeDevice.ConfigurationState ==
                    GazeDeviceConfigurationStatePreview.ScreenSetupNeeded)
        {
            // Device isn't calibrated, so invoke the calibration handler.
            System.Diagnostics.Debug.WriteLine(
                "Your device needs to calibrate. Please wait for it to finish.");
            await gazeDevice.RequestCalibrationAsync();
        }
        // Notify if device calibration underway.
        else if (gazeDevice.ConfigurationState == 
            GazeDeviceConfigurationStatePreview.Configuring)
        {
            // Device is currently undergoing calibration.  
            // A device update is sent when calibration complete.
            System.Diagnostics.Debug.WriteLine(
                "Your device is being configured. Please wait for it to finish"); 
        }
        // Device is not viable.
        else if (gazeDevice.ConfigurationState == GazeDeviceConfigurationStatePreview.Unknown)
        {
            // Notify if device is in unknown state.  
            // Reconfigure/recalbirate the device.  
            System.Diagnostics.Debug.WriteLine(
                "Your device is not ready. Please set up your device or reconfigure it."); 
        }
    }

    /// <summary>
    /// Check if eye-tracking device is viable.
    /// </summary>
    /// <param name="gazeDevice">Reference to eye-tracking device.</param>
    /// <returns>True, if device is viable; otherwise, false.</returns>
    private bool IsSupportedDevice(GazeDevicePreview gazeDevice)
    {
        TrackerState.Text = gazeDevice.ConfigurationState.ToString();
        return (gazeDevice.CanTrackEyes &&
                    gazeDevice.ConfigurationState == 
                    GazeDeviceConfigurationStatePreview.Ready);
    }
  1. Successivamente, si configurano i gestori degli eventi di sguardi.Next, we set up our gaze event handlers.

    Viene visualizzata e nascosta l'ellisse di rilevamento degli sguardi GazeEntered rispettivamente in e GazeExited .We display and hide the gaze tracking ellipse in GazeEntered and GazeExited, respectively.

    In l' GazeMoved ellisse di rilevamento degli sguardi viene spostata in base al EyeGazePosition fornito da currentPoint di GazeEnteredPreviewEventArgs.In GazeMoved, we move our gaze tracking ellipse based on the EyeGazePosition provided by the CurrentPoint of the GazeEnteredPreviewEventArgs. Viene inoltre gestito il timer dello stato attivo dello sguardo sul RadialProgressBar, che attiva il riposizionamento dell'indicatore di stato.We also manage the gaze focus timer on the RadialProgressBar, which triggers repositioning of the progress bar. Per informazioni dettagliate, vedere il passaggio successivo.See next step for details.

    /// <summary>
    /// GazeEntered handler.
    /// </summary>
    /// <param name="sender">Source of the gaze entered event</param>
    /// <param name="e">Event args for the gaze entered event</param>
    private void GazeEntered(
        GazeInputSourcePreview sender, 
        GazeEnteredPreviewEventArgs args)
    {
        // Show ellipse representing gaze point.
        eyeGazePositionEllipse.Visibility = Visibility.Visible;
    
        // Mark the event handled.
        args.Handled = true;
    }
    
    /// <summary>
    /// GazeExited handler.
    /// Call DisplayRequest.RequestRelease to conclude the 
    /// RequestActive called in GazeEntered.
    /// </summary>
    /// <param name="sender">Source of the gaze exited event</param>
    /// <param name="e">Event args for the gaze exited event</param>
    private void GazeExited(
        GazeInputSourcePreview sender, 
        GazeExitedPreviewEventArgs args)
    {
        // Hide gaze tracking ellipse.
        eyeGazePositionEllipse.Visibility = Visibility.Collapsed;
    
        // Mark the event handled.
        args.Handled = true;
    }
    
    /// <summary>
    /// GazeMoved handler translates the ellipse on the canvas to reflect gaze point.
    /// </summary>
    /// <param name="sender">Source of the gaze moved event</param>
    /// <param name="e">Event args for the gaze moved event</param>
    private void GazeMoved(GazeInputSourcePreview sender, GazeMovedPreviewEventArgs args)
    {
        // Update the position of the ellipse corresponding to gaze point.
        if (args.CurrentPoint.EyeGazePosition != null)
        {
            double gazePointX = args.CurrentPoint.EyeGazePosition.Value.X;
            double gazePointY = args.CurrentPoint.EyeGazePosition.Value.Y;
    
            double ellipseLeft = 
                gazePointX - 
                (eyeGazePositionEllipse.Width / 2.0f);
            double ellipseTop = 
                gazePointY - 
                (eyeGazePositionEllipse.Height / 2.0f) - 
                (int)Header.ActualHeight;
    
            // Translate transform for moving gaze ellipse.
            TranslateTransform translateEllipse = new TranslateTransform
            {
                X = ellipseLeft,
                Y = ellipseTop
            };
    
            eyeGazePositionEllipse.RenderTransform = translateEllipse;
    
            // The gaze point screen location.
            Point gazePoint = new Point(gazePointX, gazePointY);
    
            // Basic hit test to determine if gaze point is on progress bar.
            bool hitRadialProgressBar = 
                DoesElementContainPoint(
                    gazePoint, 
                    GazeRadialProgressBar.Name, 
                    GazeRadialProgressBar); 
    
            // Use progress bar thickness for visual feedback.
            if (hitRadialProgressBar)
            {
                GazeRadialProgressBar.Thickness = 10;
            }
            else
            {
                GazeRadialProgressBar.Thickness = 4;
            }
    
            // Mark the event handled.
            args.Handled = true;
        }
    }
    
  2. Infine, di seguito sono riportati i metodi usati per gestire il timer dello stato attivo dello sguardo per questa app.Finally, here are the methods used to manage the gaze focus timer for this app.

    DoesElementContainPoint Verifica se il puntatore a sguardi è posizionato sull'indicatore di stato.DoesElementContainPoint checks if the gaze pointer is over the progress bar. In tal caso, viene avviato il timer dello sguardo e viene incrementato l'indicatore di stato per ogni segno di avanzamento del timer.If so, it starts the gaze timer and increments the progress bar on each gaze timer tick.

    SetGazeTargetLocation imposta la posizione iniziale dell'indicatore di stato e, se l'indicatore di stato viene completato (a seconda del timer dello stato attivo dello sguardo), sposta l'indicatore di stato in un percorso casuale.SetGazeTargetLocation sets the initial location of the progress bar and, if the progress bar completes (depending on the gaze focus timer), moves the progress bar to a random location.

    /// <summary>
    /// Return whether the gaze point is over the progress bar.
    /// </summary>
    /// <param name="gazePoint">The gaze point screen location</param>
    /// <param name="elementName">The progress bar name</param>
    /// <param name="uiElement">The progress bar UI element</param>
    /// <returns></returns>
    private bool DoesElementContainPoint(
        Point gazePoint, string elementName, UIElement uiElement)
    {
        // Use entire visual tree of progress bar.
        IEnumerable<UIElement> elementStack = 
            VisualTreeHelper.FindElementsInHostCoordinates(gazePoint, uiElement, true);
        foreach (UIElement item in elementStack)
        {
            //Cast to FrameworkElement and get element name.
            if (item is FrameworkElement feItem)
            {
                if (feItem.Name.Equals(elementName))
                {
                    if (!timerStarted)
                    {
                        // Start gaze timer if gaze over element.
                        timerGaze.Start();
                        timerStarted = true;
                    }
                    return true;
                }
            }
        }
    
        // Stop gaze timer and reset progress bar if gaze leaves element.
        timerGaze.Stop();
        GazeRadialProgressBar.Value = 0;
        timerStarted = false;
        return false;
    }
    
    /// <summary>
    /// Tick handler for gaze focus timer.
    /// </summary>
    /// <param name="sender">Source of the gaze entered event</param>
    /// <param name="e">Event args for the gaze entered event</param>
    private void TimerGaze_Tick(object sender, object e)
    {
        // Increment progress bar.
        GazeRadialProgressBar.Value += 1;
    
        // If progress bar reaches maximum value, reset and relocate.
        if (GazeRadialProgressBar.Value == 100)
        {
            SetGazeTargetLocation();
        }
    }
    
    /// <summary>
    /// Set/reset the screen location of the progress bar.
    /// </summary>
    private void SetGazeTargetLocation()
    {
        // Ensure the gaze timer restarts on new progress bar location.
        timerGaze.Stop();
        timerStarted = false;
    
        // Get the bounding rectangle of the app window.
        Rect appBounds = Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().VisibleBounds;
    
        // Translate transform for moving progress bar.
        TranslateTransform translateTarget = new TranslateTransform();
    
        // Calculate random location within gaze canvas.
            Random random = new Random();
            int randomX = 
                random.Next(
                    0, 
                    (int)appBounds.Width - (int)GazeRadialProgressBar.Width);
            int randomY = 
                random.Next(
                    0, 
                    (int)appBounds.Height - (int)GazeRadialProgressBar.Height - (int)Header.ActualHeight);
    
        translateTarget.X = randomX;
        translateTarget.Y = randomY;
    
        GazeRadialProgressBar.RenderTransform = translateTarget;
    
        // Show progress bar.
        GazeRadialProgressBar.Visibility = Visibility.Visible;
        GazeRadialProgressBar.Value = 0;
    }
    

Vedi ancheSee also

RisorseResources

Esempi di argomentoTopic samples