Udostępnij przez


Symulowanie danych wejściowych użytkownika za pomocą iniekcji danych wejściowych

Symulowanie i automatyzowanie danych wejściowych użytkownika z urządzeń, takich jak klawiatura, mysz, dotyk, pióro i gamepad w aplikacjach systemu Windows.

Ważne interfejsy API: Windows.UI.Input.Preview.Injection

Przegląd

Iniekcja danych wejściowych umożliwia aplikacji systemu Windows symulowanie danych wejściowych z różnych urządzeń wejściowych i kierowanie tych danych wejściowych w dowolnym miejscu, w tym poza obszarem klienta aplikacji (nawet do aplikacji uruchomionych z uprawnieniami administratora, takich jak Edytor rejestru).

Iniekcja danych wejściowych jest przydatna w przypadku aplikacji i narzędzi systemu Windows, które muszą zapewniać funkcje, które obejmują ułatwienia dostępu, testowanie (ad hoc, zautomatyzowane) oraz funkcje dostępu zdalnego i obsługi technicznej.

Konfiguracja

Aby użyć API wprowadzania danych w aplikacji systemu Windows, należy dodać następujący kod do manifestu aplikacji:

  1. Kliknij prawym przyciskiem myszy plik Package.appxmanifest i wybierz pozycję Wyświetl kod.
  2. Wstaw następujące elementy do węzła Package :
    • xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
    • IgnorableNamespaces="rescap"
  3. Wstaw następujące elementy do węzła Capabilities :
    • <rescap:Capability Name="inputInjectionBrokered" />

Zduplikowane dane wejściowe użytkownika

Przykład wstrzyknięcia wejścia dotykowego
Przykład wstrzykiwania wejścia dotykowego

W tym przykładzie pokazano, jak używać interfejsów API iniekcji danych wejściowych (Windows.UI.Input.Preview.Injection), aby nasłuchiwać zdarzeń wprowadzania myszy w jednym regionie aplikacji i symulować odpowiednie zdarzenia wejściowe dotyku w innym regionie.

Pobierz ten przykład z przykładu iniekcji danych wejściowych (mysz do dotyku)

  1. Najpierw skonfigurujemy interfejs użytkownika (MainPage.xaml).

    Mamy dwa obszary Grid (jeden dla danych wejściowych myszy i jeden dla wstrzykiwania danych dotykowych), każdy z czterema przyciskami.

    Uwaga / Notatka

    Tło siatki musi mieć przypisaną wartość (Transparentw tym przypadku), w przeciwnym razie zdarzenia wskaźnika nie są wykrywane.

    Po wykryciu jakichkolwiek kliknięć myszy w obszarze wejściowym odpowiednie zdarzenie dotykowe jest wstrzykiwane do obszaru iniekcji wejściowej. Kliknięcia przycisku z wprowadzanie danych wejściowych są zgłaszane w obszarze tytułu.

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0"
                    Margin="10">
            <TextBlock Style="{ThemeResource TitleTextBlockStyle}" 
                       Name="titleText"
                       Text="Touch input injection"
                       HorizontalTextAlignment="Center" />
            <TextBlock Style="{ThemeResource BodyTextBlockStyle}"
                       Name="statusText"
                       HorizontalTextAlignment="Center" />
        </StackPanel>
        <Grid HorizontalAlignment="Center"
                        Grid.Row="1">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <TextBlock Grid.Column="0" 
                       Grid.Row="0" 
                       Style="{ThemeResource CaptionTextBlockStyle}"
                       Text="User mouse input area"/>
            <!-- Background must be set to something, otherwise pointer events are not detected. -->
            <Grid Name="ContainerInput" 
                  Grid.Column="0" 
                  Grid.Row="1"
                  HorizontalAlignment="Stretch" 
                  Background="Transparent" 
                  BorderBrush="Green" 
                  BorderThickness="2" 
                  MinHeight="100" MinWidth="300" 
                  Margin="10">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <Button Name="B1" 
                        Grid.Column="0" 
                        HorizontalAlignment="Center" 
                        Width="50" Height="50"
                        Content="B1" />
                <Button Name="B2" 
                        Grid.Column="1" 
                        HorizontalAlignment="Center" 
                        Width="50" Height="50"
                        Content="B2" />
                <Button Name="B3" 
                        Grid.Column="2" 
                        HorizontalAlignment="Center" 
                        Width="50" Height="50"
                        Content="B3" />
                <Button Name="B4" 
                        Grid.Column="3" 
                        HorizontalAlignment="Center" 
                        Width="50" Height="50"
                        Content="B4" />
            </Grid>
            <TextBlock Grid.Column="1" 
                       Grid.Row="0"                         
                       Style="{ThemeResource CaptionTextBlockStyle}"
                       Text="Injected touch input area"/>
            <Grid Name="ContainerInject"
                  Grid.Column="1"  
                  Grid.Row="1"
                  HorizontalAlignment="Stretch"
                  BorderBrush="Red" 
                  BorderThickness="2" 
                  MinHeight="100" MinWidth="300" 
                  Margin="10">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <Button Name="B1i" Click="Button_Click_Injected"
                        Content="B1i"
                        Grid.Column="0" 
                        HorizontalAlignment="Center" 
                        Width="50" Height="50" />
                <Button Name="B2i" Click="Button_Click_Injected"
                        Content="B2i"
                        Grid.Column="1" 
                        HorizontalAlignment="Center" 
                        Width="50" Height="50" />
                <Button Name="B3i" Click="Button_Click_Injected"
                        Content="B3i"
                        Grid.Column="2" 
                        HorizontalAlignment="Center" 
                        Width="50" Height="50" />
                <Button Name="B4i" Click="Button_Click_Injected"
                        Content="B4i"
                        Grid.Column="3" 
                        HorizontalAlignment="Center" 
                        Width="50" Height="50" />
            </Grid>
        </Grid>
    </Grid>
    
  2. Następnie zainicjujemy naszą aplikację.

    W tym fragmencie kodu deklarujemy nasze obiekty globalne i deklarujemy odbiorniki dla zdarzeń wskaźnika (AddHandler) w obszarze wprowadzania myszy, które mogą być oznaczone jako obsługiwane w zdarzeniach kliknięcia przycisku.

    Obiekt InputInjector reprezentuje wirtualne urządzenie wejściowe do wysyłania danych wejściowych.

    W programie obsługującym ContainerInput_PointerPressed wywołujemy funkcję wstrzykiwania dotyku.

    W obsłudze ContainerInput_PointerReleased wywołujemy metodę UninitializeTouchInjection, aby zamknąć obiekt InputInjector.

    public sealed partial class MainPage : Page
    {
        /// <summary>
        /// The virtual input device.
        /// </summary>
        InputInjector _inputInjector;
    
        /// <summary>
        /// Initialize the app, set the window size, 
        /// and add pointer input handlers for the container.
        /// </summary>
        public MainPage()
        {
            this.InitializeComponent();
    
            ApplicationView.PreferredLaunchViewSize =
                new Size(600, 200);
            ApplicationView.PreferredLaunchWindowingMode =
                ApplicationViewWindowingMode.PreferredLaunchViewSize;
    
            // Button handles PointerPressed/PointerReleased in 
            // the Tapped routed event, but we need the container Grid 
            // to handle them also. Add a handler for both 
            // PointerPressedEvent and PointerReleasedEvent on the input Grid 
            // and set handledEventsToo to true.
            ContainerInput.AddHandler(PointerPressedEvent,
                new PointerEventHandler(ContainerInput_PointerPressed), true);
            ContainerInput.AddHandler(PointerReleasedEvent,
                new PointerEventHandler(ContainerInput_PointerReleased), true);
        }
    
        /// <summary>
        /// PointerReleased handler for all pointer conclusion events.
        /// PointerPressed and PointerReleased events do not always occur 
        /// in pairs, so your app should listen for and handle any event that 
        /// might conclude a pointer down (such as PointerExited, PointerCanceled, 
        /// and PointerCaptureLost).  
        /// </summary>
        /// <param name="sender">Source of the click event</param>
        /// <param name="e">Event args for the button click routed event</param>
        private void ContainerInput_PointerReleased(
            object sender, PointerRoutedEventArgs e)
        {
            // Prevent most handlers along the event route from handling event again.
            e.Handled = true;
    
            // Shut down the virtual input device.
            _inputInjector.UninitializeTouchInjection();
        }
    
        /// <summary>
        /// PointerPressed handler.
        /// PointerPressed and PointerReleased events do not always occur 
        /// in pairs. Your app should listen for and handle any event that 
        /// might conclude a pointer down (such as PointerExited, 
        /// PointerCanceled, and PointerCaptureLost).  
        /// </summary>
        /// <param name="sender">Source of the click event</param>
        /// <param name="e">Event args for the button click routed event</param>
        private void ContainerInput_PointerPressed(
            object sender, PointerRoutedEventArgs e)
        {
            // Prevent most handlers along the event route from 
            // handling the same event again.
            e.Handled = true;
    
            InjectTouchForMouse(e.GetCurrentPoint(ContainerInput));
    
        }
        ...
    }
    
  3. Oto funkcja wstrzykiwania dotykowego wejścia.

    Najpierw wywołujemy metodę TryCreate, aby utworzyć wystąpienie obiektu InputInjector.

    Następnie wywołujemy InitializeTouchInjection z InjectedInputVisualizationModeDefault.

    Po obliczeniu punktu iniekcji wywołujemy metodę InjectedInputTouchInfo , aby zainicjować listę punktów dotykowych do wstrzykiwania (w tym przykładzie tworzymy jeden punkt dotykowy odpowiadający wskaźnikowi wejściowemu myszy).

    Na koniec dwukrotnie wywołujemy funkcję InjectTouchInput , pierwszą dla wskaźnika w dół i drugą dla wskaźnika w górę.

    /// <summary>
    /// Inject touch input on injection target corresponding 
    /// to mouse click on input target.
    /// </summary>
    /// <param name="pointerPoint">The mouse click pointer.</param>
    private void InjectTouchForMouse(PointerPoint pointerPoint)
    {
        // Create the touch injection object.
        _inputInjector = InputInjector.TryCreate();
    
        if (_inputInjector != null)
        {
            _inputInjector.InitializeTouchInjection(
                InjectedInputVisualizationMode.Default);
    
            // Create a unique pointer ID for the injected touch pointer.
            // Multiple input pointers would require more robust handling.
            uint pointerId = pointerPoint.PointerId + 1;
    
            // Get the bounding rectangle of the app window.
            Rect appBounds =
                Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().VisibleBounds;
    
            // Get the top left screen coordinates of the app window rect.
            Point appBoundsTopLeft = new Point(appBounds.Left, appBounds.Top);
    
            // Get a reference to the input injection area.
            GeneralTransform injectArea =
                ContainerInject.TransformToVisual(Window.Current.Content);
    
            // Get the top left screen coordinates of the input injection area.
            Point injectAreaTopLeft = injectArea.TransformPoint(new Point(0, 0));
    
            // Get the screen coordinates (relative to the input area) 
            // of the input pointer.
            int pointerPointX = (int)pointerPoint.Position.X;
            int pointerPointY = (int)pointerPoint.Position.Y;
    
            // Create the point for input injection and calculate its screen location.
            Point injectionPoint =
                new Point(
                    appBoundsTopLeft.X + injectAreaTopLeft.X + pointerPointX,
                    appBoundsTopLeft.Y + injectAreaTopLeft.Y + pointerPointY);
    
            // Create a touch data point for pointer down.
            // Each element in the touch data list represents a single touch contact. 
            // For this example, we're mirroring a single mouse pointer.
            List<InjectedInputTouchInfo> touchData =
                new List<InjectedInputTouchInfo>
                {
                    new InjectedInputTouchInfo
                    {
                        Contact = new InjectedInputRectangle
                        {
                            Left = 30, Top = 30, Bottom = 30, Right = 30
                        },
                        PointerInfo = new InjectedInputPointerInfo
                        {
                            PointerId = pointerId,
                            PointerOptions =
                            InjectedInputPointerOptions.PointerDown |
                            InjectedInputPointerOptions.InContact |
                            InjectedInputPointerOptions.New,
                            TimeOffsetInMilliseconds = 0,
                            PixelLocation = new InjectedInputPoint
                            {
                                PositionX = (int)injectionPoint.X ,
                                PositionY = (int)injectionPoint.Y
                            }
                    },
                    Pressure = 1.0,
                    TouchParameters =
                        InjectedInputTouchParameters.Pressure |
                        InjectedInputTouchParameters.Contact
                }
            };
    
            // Inject the touch input. 
            _inputInjector.InjectTouchInput(touchData);
    
            // Create a touch data point for pointer up.
            touchData = new List<InjectedInputTouchInfo>
            {
                new InjectedInputTouchInfo
                {
                    PointerInfo = new InjectedInputPointerInfo
                    {
                        PointerId = pointerId,
                        PointerOptions = InjectedInputPointerOptions.PointerUp
                    }
                }
            };
    
            // Inject the touch input. 
            _inputInjector.InjectTouchInput(touchData);
        }
    }
    
  4. Na koniec obsługujemy wszystkie zdarzenia kliknięte przyciskiem w obszarze wstrzykiwania danych wejściowych i aktualizujemy interfejs użytkownika przy użyciu nazwy klikniętego przycisku.

Zobacz także

Przykłady tematów