Simulace vstupu v UWP aplikacích

Visual Studio WinUI

6 years ago

Jednou z méně známých funkcí UWP API je možnost simulace vstupu ( input injection). Tu lze s výhodou využít, když chcete uživateli nabídnout automatickou prohlídku aplikací, poskytnout zpětnou vazbu uživatelům asistenčních technologií nebo implementovat ve vaší aplikaci možnost vzdálené pomoci. V tomto článku si prohlédneme jmenný prostor Windows.UI.Input.Preview.Injection a ukážeme si, jak používat jeho členy.

Podporované formy vstupu

Windows 10 podporuje několik různých forem vstupu a všechny lze použít i se simulátorem vstupu v UWP API. Lze simulovat:

  • Gamepad

  • Klávesnici

  • Myš

  • Pero

  • Dotyk

    V článku se podíváme na simulaci klávesnice a myši.

Deklarace simulace vstupu

Předtím než budeme moci simulaci vstupu využít, musíme to deklarovat v aplikačním manifestu, protože jde o nestandardní funkcionalitu. Patří do kategorie restricted capability, což znamená že výslednou aplikaci můžeme publikovat na Windows Store, ale vyžaduje rozšířenou kontrolu při schvalovacím procesu. Otevřeme Package.appxmanifest jako XML soubor a doplníme o novou deklaraci jmenného prostoru v elementu Package:

<Package
   ...
   xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
  IgnorableNamespaces="uap mp rescap">

Jmenný prostor rescap je domovem pro všechny restricted capabilities. Dále musíme přidat samotnou capability inputInjectionBrokered v sekci Capabilities:

<Capabilities>
  <Capability Name="internetClient" />
  <rescap:Capability Name="inputInjectionBrokered" />
</Capabilities>

Základy

Hlavní třídou ve jmenném prostoru Windows.UI.Input.Preview.Injection je InputInjector. Její instanci vytvoříme pomocí statické metody TryCreate. Následně můžeme volat odpovídající metody pro každou z forem vstupu:

var inputInfo = new InjectedInputMouseInfo();
...
InputInjector inputInjector = InputInjector.TryCreate();
inputInjector.InjectMouseInput(new[] { inputInfo });

Jak lze vidět, tyto metody přijímají seznam instancí input info, takže můžeme provést více operací za sebou.

Vstup myši

Simulovaný vstup myši můžeme připravit pomocí třídy InjectedInputMouseInfo. Pro pohyb myší použijeme vlastnosti DeltaX a DeltaY:

var info = new InjectedInputMouseInfo();
info.MouseOptions = InjectedInputMouseOptions.Move;
info.DeltaY = 100; //move down 100 points

Vlastnost MouseOptions nám umožňuje nastavit flagy, které určují operace, jež se mají provést. Mezi těmi jsou i LeftDown a LeftUp, kterými můžeme simulovat kliknutí levého tlačítka myši:

var down = new InjectedInputMouseInfo();
down.MouseOptions = InjectedInputMouseOptions.LeftDown;

var up = new InjectedInputMouseInfo();
up.MouseOptions = InjectedInputMouseOptions.LeftUp;

InputInjector inputInjector = InputInjector.TryCreate();
inputInjector.InjectMouseInput(new[] { down, up });

Můžeme ale simulovat i scrollovací kolečka myši a to jak vertikální tak horizontální pomocí vlastností Wheel resp. HWheel. Vzdálenost pro scrollování můžete nastavit vlastností MouseData:

var info = new InjectedInputMouseInfo();
info.MouseOptions = InjectedInputMouseOptions.Wheel;
info.MouseData = 500; //scrollovat nahoru

InputInjector inputInjector = InputInjector.TryCreate();
inputInjector.InjectMouseInput(new[] { info });

Scrollování nahoru je snadné, ale co dolů?

info.MouseData = -500; //chyba při kompilaci!

Překvapivě, vlastnost MouseData je typu uint, což znemožňuje přiřazení záporných hodnot. Můžeme však využít přetečení, jehož důsledek bude očekávané chování:

unchecked
{
    info.MouseData = (uint)-500; //scrollovat dolů
}

V tomto případě musíme použít unchecked blok, protože používáme konstantu a kompilátor se brání numerickému přetečení. Pokud bychom použili dočasnou lokální proměnnou, kompilátor by si již problému nemohl "všimnout" a nemuseli bychom unchecked používat. Info pro vstup myší také zahrnuje vlastnostTimeOffsetInMilliseconds, přes kterou můžete nastavit zpoždění jednotlivých akcí. To je užitečné pro korektní simulací oprací jako je dvojklik.

Vstup klávesnice

Třída InjectedInputKeyboardInfo je základem pro simulaci vstupu z klávesnice. Nejdůežitější vlastnost je VirtualKey, která určuje klávesu, se kterou pracujeme. Následující příklad vypíše do aktivního vstupního pole řetězec "hello":

InputInjector inputInjector = InputInjector.TryCreate();
foreach (var letter in "hello")
{
    var info = new InjectedInputKeyboardInfo();
    info.VirtualKey = (ushort)((VirtualKey)Enum.Parse(typeof(VirtualKey),
                                 letter.ToString(), true));
    inputInjector.InjectKeyboardInput(new[] { info });
    await Task.Delay(100);
}

Na konci cyklu je volání metody Task.Delay, které zde není jen pro efekt :-D . Zajišťuje, že opakované stisky kláves nebudou zaregistrovány jako jedno stisknutí, což by zabránilo zaregistrování druhého písmena L.

Ukázkový kód

Zdrojový kód k tomuto článku je k dispozici na mém GitHubu.

Input injection sample app

Ukázková aplikace pro simulaci vstupu

Shrnutí

Prohlédli jsme si jmenný prostor Windows.<wbr />UI.<wbr />Input.<wbr />Preview.<wbr />Injection a ukázali, jak jej můžeme využít pro simulaci vstupních zařízení. Přestože tuto funkci příliš často nevyužijeme, je velmi pěkné ji vidět jako součást UWP API.