Události klávesnice

Události klávesnice a fokus

U hardwarových i dotykových klávesnic může dojít k následujícím událostem klávesnice.

Event Description
KeyDown Nastane, když je stisknuta klávesa.
KeyUp Nastane při uvolnění klíče.

Důležité

Některé ovládací prvky XAML zpracovávají vstupní události interně. V těchto případech se může zdát, že vstupní událost není zaznamenána, protože váš naslouchač nevyvolá přidruženou obslužnou rutinu. Tuto podmnožinu kláves obvykle zpracovává obslužná rutina třídy, která poskytuje integrovanou podporu základní přístupnosti klávesnice. Třída Button například přepíše události OnKeyDown pro klávesu Mezerník i Enter (stejně jako OnPointerPressed) a směruje je do události Click ovládacího prvku. Když zpracovává třída ovládacího prvku stisk klávesy, nejsou události KeyDown a KeyUp vyvolány.
To poskytuje integrovaný ekvivalent klávesnice pro vyvolání tlačítka, podobně jako když na něj klepnete prstem nebo na něj kliknete myší. Klávesy jiné než mezera nebo Enter stále aktivují události KeyDown a KeyUp . Další informace o tom, jak funguje zpracování událostí na základě tříd (konkrétně v části Obslužné rutiny událostí vstupu v ovládacích prvcích), najdete v tématu Události a přehled směrovaných událostí.

Ovládací prvky v uživatelském rozhraní generují události klávesnice pouze v případech, kdy mají fokus vstupu. Jednotlivý ovládací prvek získá fokus, když uživatel klikne nebo klepne přímo na tento ovládací prvek v rozložení prvků, nebo pomocí klávesy Tab vstoupí do tabulátorové sekvence v oblasti obsahu.

Můžete také volat metodu Focus ovládacího prvku, která vynutí fokus. To je nutné při implementaci klávesových zkratek, protože fokus klávesnice není ve výchozím nastavení nastaven při načítání uživatelského rozhraní. Další informace najdete v příkladu klávesových zkratek dále v tomto tématu.

Aby ovládací prvek mohl přijímat vstupní fokus, musí být povolen, viditelný a mít IsTabStop a HitTestVisible hodnoty vlastnosti true. Toto je výchozí stav většiny ovládacích prvků. Pokud má ovládací prvek fokus vstupu, může vyvolat události zadávání klávesnice a reagovat na ně, jak je popsáno dále v tomto tématu. Můžete také reagovat na ovládací prvek, který získává nebo ztrácí fokus, zpracováním událostí GotFocus a LostFocus.

Ve výchozím nastavení je pořadí ovládacích prvků pořadí, ve kterém se zobrazují v jazyce XAML (Extensible Application Markup Language). Toto pořadí však můžete změnit pomocí tabIndex vlastnost. Další informace najdete v tématu Implementace přístupnosti klávesnice.

Obslužné rutiny událostí klávesnice

Obslužná rutina vstupní události implementuje delegáta, který poskytuje následující informace:

  • Odesílatel události. Odesílatel hlásí objekt, k němuž je připojena obslužná rutina události.
  • Data o události U událostí klávesnice budou tato data instancí KeyRoutedEventArgs. Delegát obslužných rutin je KeyEventHandler. Nejdůležitějšími vlastnostmi KeyRoutedEventArgs pro většinu scénářů obslužné rutiny jsou Key a případně KeyStatus.
  • OriginalSource. Protože události klávesnice jsou směrované události, data události poskytují OriginalSource. Pokud záměrně povolíte, aby události prolétly stromem objektů, OriginalSource je někdy objektem zájmu místo odesílatele. To ale závisí na vašem návrhu. Další informace o tom, jak můžete místo odesílatele použít OriginalSource , najdete v části Události směrované pomocí klávesnice v tomto tématu nebo Přehled událostí a směrovaných událostí.

Připojení obslužné rutiny události klávesnice

Obslužné funkce událostí klávesnice můžete připojit k libovolnému objektu, který má událost jako člena. To zahrnuje všechny UIElement odvozené třídy. Následující příklad XAML ukazuje, jak připojit obslužné rutiny pro událost KeyUp pro Grid.

<Grid KeyUp="Grid_KeyUp">
  ...
</Grid>

V kódu můžete také připojit obslužnou rutinu události. Další informace najdete v tématu Události a přehled směrovaných událostí.

Definování obslužné rutiny události klávesnice

Následující příklad ukazuje neúplnou definici obslužné rutiny události pro obslužnou rutinu události KeyUp , která byla připojena v předchozím příkladu.

void Grid_KeyUp(object sender, KeyRoutedEventArgs e)
{
    //handling code here
}
void MyProject::MainPage::Grid_KeyUp(
  winrt::Windows::Foundation::IInspectable const& sender,
  winrt::Microsoft::UI::Xaml::Input::KeyRoutedEventArgs const& e)
  {
      //handling code here
  }

Použití KeyRoutedEventArgs

Všechny události klávesnice používají KeyRoutedEventArgs pro data událostí a KeyRoutedEventArgs obsahují následující vlastnosti:

Virtuální klíče

Událost KeyDown se vyvolá, pokud je stisknuta klávesa. Podobně se KeyUp vyvolá, pokud se klíč uvolní. Obvykle nasloucháte událostem, abyste zpracovali konkrétní hodnotu klíče. Pokud chcete zjistit, která klávesa se stiskne nebo uvolní, zkontrolujte hodnotu klíče v datech události. Klíč vrátí hodnotu VirtualKey . Výčet VirtualKey zahrnuje všechny podporované klíče.

Modifikační klávesy

Modifikační klávesy jsou například klávesy Ctrl nebo Shift, které uživatelé obvykle stisknou v kombinaci s jinými klávesami. Aplikace může tyto kombinace použít jako vlastní klávesové zkratky k vyvolání příkazů aplikace.

Poznámka:

Předdefinované klávesové zkratky najdete v tématu Přístupové klávesy a akcelerátory klávesnice.

Kombinace klávesových zkratek můžete rozpoznat v obslužných rutinách událostí KeyDown a KeyUp . Když dojde k události klávesnice pro klávesu jinou než modifikační, můžete zkontrolovat, jestli je modifikační klávesa ve stisknutém stavu.

Alternativně můžete ve WinUI 3 použít InputKeyboardSource.GetKeyStateForCurrentThread ke kontrole stavu modifikátoru při stisknutí nemodifikační klávesy.

Následující příklady implementují tuto druhou metodu a zároveň zahrnují kód zástupných procedur pro první implementaci.

Poznámka:

Klávesa Alt je reprezentována hodnotou VirtualKey.Menu .

Příklad klávesových zkratek

Následující příklad ukazuje, jak implementovat sadu vlastních klávesových zkratek. V tomto příkladu můžou uživatelé ovládat přehrávání médií pomocí tlačítek Přehrát, Pozastavit a Zastavit nebo Klávesové zkratky Ctrl+P, Ctrl+A a Ctrl+S. Kód XAML tlačítka zobrazuje klávesové zkratky pomocí popisů a vlastností AutomationProperties v popiscích tlačítek. Tato samoobslužná dokumentace je důležitá pro zvýšení použitelnosti a přístupnosti vaší aplikace. Další informace najdete v tématu Přístupnost pomocí klávesnice.

Všimněte si také, že stránka při načtení nastaví fokus vstupu na sebe. Bez tohoto kroku nemá žádný ovládací prvek počáteční vstupní fokus a aplikace nevyvolá vstupní události, dokud uživatel ručně nenastaví vstupní fokus (například pomocí tabulátoru nebo kliknutím).

<Grid KeyDown="Grid_KeyDown">

  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>

  <MediaElement x:Name="DemoMovie" Source="xbox.wmv"
    Width="500" Height="500" Margin="20" HorizontalAlignment="Center" />

  <StackPanel Grid.Row="1" Margin="10"
    Orientation="Horizontal" HorizontalAlignment="Center">

    <Button x:Name="PlayButton" Click="MediaButton_Click"
      ToolTipService.ToolTip="Shortcut key: Ctrl+P"
      AutomationProperties.AcceleratorKey="Control P">
      <TextBlock>Play</TextBlock>
    </Button>

    <Button x:Name="PauseButton" Click="MediaButton_Click"
      ToolTipService.ToolTip="Shortcut key: Ctrl+A"
      AutomationProperties.AcceleratorKey="Control A">
      <TextBlock>Pause</TextBlock>
    </Button>

    <Button x:Name="StopButton" Click="MediaButton_Click"
      ToolTipService.ToolTip="Shortcut key: Ctrl+S"
      AutomationProperties.AcceleratorKey="Control S">
      <TextBlock>Stop</TextBlock>
    </Button>

  </StackPanel>

</Grid>
// showing implementations but not header definitions
void MainPage::OnNavigatedTo(NavigationEventArgs const& e)
{
    this->Loaded([this](auto&&, auto&&) { ProgrammaticFocus(); });
}
void MainPage::ProgrammaticFocus()
{
    this->Focus(Microsoft::UI::Xaml::FocusState::Programmatic);
}

void MainPage::MediaButton_Click(winrt::Windows::Foundation::IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& e)
{
    auto fe = sender.as<Microsoft::UI::Xaml::FrameworkElement>();
    if (fe.Name() == L"PlayButton") { DemoMovie().Play(); }
    if (fe.Name() == L"PauseButton") { DemoMovie().Pause(); }
    if (fe.Name() == L"StopButton") { DemoMovie().Stop(); }
}


bool MainPage::IsCtrlKeyPressed()
{
    auto ctrlState = Microsoft::UI::Input::InputKeyboardSource::GetKeyStateForCurrentThread(VirtualKey::Control);
    return (ctrlState & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down;
}

void MainPage::Grid_KeyUp(winrt::Windows::Foundation::IInspectable const& sender, Microsoft::UI::Xaml::Input::KeyRoutedEventArgs const& e)
{
    if (IsCtrlKeyPressed())
    {
        if (e.Key() == VirtualKey::P) { DemoMovie().Play(); }
        if (e.Key() == VirtualKey::A) { DemoMovie().Pause(); }
        if (e.Key() == VirtualKey::S) { DemoMovie().Stop(); }
    }
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    // Set the input focus to ensure that keyboard events are raised.
    this.Loaded += delegate { this.Focus(FocusState.Programmatic); };
}

private void MediaButton_Click(object sender, RoutedEventArgs e)
{
    switch ((sender as Button).Name)
    {
        case "PlayButton": DemoMovie.Play(); break;
        case "PauseButton": DemoMovie.Pause(); break;
        case "StopButton": DemoMovie.Stop(); break;
    }
}

private static bool IsCtrlKeyPressed()
{
    var ctrlState = Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Control);
    return (ctrlState & CoreVirtualKeyStates.Down) == CoreVirtualKeyStates.Down;
}

private void Grid_KeyDown(object sender, KeyRoutedEventArgs e)
{
    if (IsCtrlKeyPressed())
    {
        switch (e.Key)
        {
            case VirtualKey.P: DemoMovie.Play(); break;
            case VirtualKey.A: DemoMovie.Pause(); break;
            case VirtualKey.S: DemoMovie.Stop(); break;
        }
    }
}
Private isCtrlKeyPressed As Boolean
Protected Overrides Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)

End Sub

Private Function IsCtrlKeyPressed As Boolean
    Dim ctrlState As CoreVirtualKeyStates = Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Control);
    Return (ctrlState & CoreVirtualKeyStates.Down) == CoreVirtualKeyStates.Down;
End Function

Private Sub Grid_KeyDown(sender As Object, e As KeyRoutedEventArgs)
    If IsCtrlKeyPressed() Then
        Select Case e.Key
            Case Windows.System.VirtualKey.P
                DemoMovie.Play()
            Case Windows.System.VirtualKey.A
                DemoMovie.Pause()
            Case Windows.System.VirtualKey.S
                DemoMovie.Stop()
        End Select
    End If
End Sub

Private Sub MediaButton_Click(sender As Object, e As RoutedEventArgs)
    Dim fe As FrameworkElement = CType(sender, FrameworkElement)
    Select Case fe.Name
        Case "PlayButton"
            DemoMovie.Play()
        Case "PauseButton"
            DemoMovie.Pause()
        Case "StopButton"
            DemoMovie.Stop()
    End Select
End Sub

Poznámka:

Nastavení AutomationProperties.AcceleratorKey nebo AutomationProperties.AccessKey v XAML poskytuje informace o řetězci, které dokumentuje klávesovou zkratku pro vyvolání konkrétní akce. Tyto informace zachytává klient Microsoft model UI Automation, jako je Narrátor, a obvykle jsou uživatelům poskytovány přímo.

Nastavení AutomationProperties.AcceleratorKey nebo AutomationProperties.AccessKey nemá žádnou akci sama. Stále budete muset připojit obslužné rutiny pro události KeyDown nebo KeyUp , aby se ve vaší aplikaci skutečně implementovaly chování klávesových zkratek. Textová dekorace podtržení pro přístupový klíč se také neposkytuje automaticky. Pokud chcete v uživatelském rozhraní zobrazit podtržený text, musíte text odpovídající konkrétní klávese ve své mnemonice explicitně podtrhnout pomocí vloženého formátování Podtržení.

 

Události směrované pomocí klávesnice

Některé události jsou směrované události, včetně KeyDown a také KeyUp. Směrované události používají strategii směrování bublání. Strategie směrování událostí bubláním znamená, že událost vzniká v podřízeném objektu a následně je směrována k nadřazeným objektům ve stromu objektů. To představuje další příležitost ke zpracování stejné události a interakci se stejnými daty událostí.

Podívejte se na následující příklad XAML, který zpracovává události KeyUp pro plátno a dva objekty Button . V tomto případě, pokud uvolníte klávesu, zatímco je fokus přidržován objektem Button, vyvolá se událost KeyUp. Událost se pak bublinuje na nadřazené plátno.

<StackPanel KeyUp="StackPanel_KeyUp">
  <Button Name="ButtonA" Content="Button A"/>
  <Button Name="ButtonB" Content="Button B"/>
  <TextBlock Name="statusTextBlock"/>
</StackPanel>

Následující příklad ukazuje, jak implementovat obslužnou rutinu události KeyUp pro odpovídající obsah XAML v předchozím příkladu.

void StackPanel_KeyUp(object sender, KeyRoutedEventArgs e)
{
    statusTextBlock.Text = String.Format(
        "The key {0} was pressed while focus was on {1}",
        e.Key.ToString(), (e.OriginalSource as FrameworkElement).Name);
}

Všimněte si použití vlastnosti OriginalSource v předchozím obslužném programu. Zde OriginalSource hlásí objekt, který vyvolal událost. Objekt nemůže být StackPanel , protože StackPanel není ovládací prvek a nemůže mít fokus. Možná by událost vyvolala pouze jedna ze dvou tlačítek v objektu StackPanel , ale která z nich? OriginalSource slouží k rozlišení skutečného zdrojového objektu události, pokud zpracováváte událost u nadřazeného objektu.

Vlastnost Handled v datech událostí

V závislosti na strategii zpracování událostí můžete chtít, aby na bublinovou událost reagovala pouze jedna obslužná rutina. Pokud máte například konkrétní obslužnou rutinu KeyUp připojenou k některému z ovládacích prvků Button , bude mít první příležitost zpracovat tuto událost. V takovém případě možná nebudete chtít, aby nadřazený panel také zpracovával událost. V tomto scénáři můžete použít vlastnost Handled v datech události.

Účelem obslužné vlastnosti v datové třídě směrované události je hlásit, že jiná obslužná rutina, kterou jste zaregistrovali dříve na trase události, již fungovala. To ovlivňuje chování směrovaného systému událostí. Když nastavíte Handled na true v obsluze události, tato událost ukončí směrování a neodešle se do po sobě jdoucích nadřazených prvků.

AddHandler a již zpracované události klávesnice

Můžete použít speciální techniku pro připojení obslužných funkcí, které mohou pracovat s událostmi, které jste již označili jako zpracované. Tato technika používá metodu AddHandler k registraci obslužné rutiny místo použití atributů XAML nebo syntaxe specifické pro jazyk pro přidání obslužných rutin, například += v jazyce C#.

Obecné omezení této techniky spočívá v tom, že rozhraní ADDHandler API přebírá parametr typu RoutedEvent identifikující danou směrovanou událost. Ne všechny směrované události poskytují identifikátor RoutedEvent a to má vliv na to, které směrované události lze stále zpracovávat v zpracovávaných případech. Události KeyDown a KeyUp mají směrované identifikátory událostí (KeyDownEvent a KeyUpEvent) v UIElement. Jiné události, jako je TextBox.TextChanged , však nemají směrované identifikátory událostí, a proto nelze použít s technikou AddHandler .

Překonávání událostí a chování klávesnice

Klíčové události pro konkrétní ovládací prvky (například GridView) můžete přepsat, abyste zajistili konzistentní navigaci fokusu pro různá vstupní zařízení, včetně klávesnice a herního panelu.

V následujícím příkladu podtřídíme ovládací prvek a přepíšeme chování KeyDown pro přesunutí fokusu na obsah GridView při stisknutí libovolné klávesy se šipkou.

  public class CustomGridView : GridView
  {
    protected override void OnKeyDown(KeyRoutedEventArgs e)
    {
      // Override arrow key behaviors.
      if (e.Key != Windows.System.VirtualKey.Left && e.Key !=
        Windows.System.VirtualKey.Right && e.Key !=
          Windows.System.VirtualKey.Down && e.Key !=
            Windows.System.VirtualKey.Up)
              base.OnKeyDown(e);
      else
        FocusManager.TryMoveFocus(FocusNavigationDirection.Down);
    }
  }

Poznámka:

Pokud pro rozložení používáte pouze GridView, zvažte použití jiných ovládacích prvků, jako je ItemsControl s ItemsWrapGrid.

Velící

Malý počet prvků uživatelského rozhraní poskytuje integrovanou podporu pro příkazování. Příkazy používají směrované události související se vstupem ve své základní implementaci. Umožňuje zpracování souvisejícího vstupu uživatelského rozhraní, jako je například určitá akce ukazatele nebo konkrétní klávesa akcelerátoru, vyvoláním jedné obslužné rutiny příkazu.

Pokud je k dispozici příkaz pro prvek uživatelského rozhraní, zvažte použití jeho rozhraní API pro příkazy místo samostatných vstupních událostí. Další informace najdete v tématu ButtonBase.Command.

Můžete také implementovat ICommand pro zapouzdření funkcionality příkazů, které voláte z běžných obslužných rutin událostí. To vám umožní používat příkazy i v případě, že není k dispozici žádná vlastnost Command .

Textové zadání a ovládací prvky

Některé ovládací prvky reagují na události klávesnice podle vlastního zpracování. Například TextBox je ovládací prvek, který je navržený k zachycení a vizuální reprezentaci textu, který byl zadán pomocí klávesnice. K zachycení klávesových úhozů ve své vlastní logice používá KeyUp a KeyDown, a poté, pokud se text skutečně změnil, vyvolá také vlastní událost TextChanged.

Obslužné rutiny pro KeyUp a KeyDown můžete dál přidávat do textového pole nebo jakýkoli související ovládací prvek, který je určený ke zpracování textového vstupu. V rámci zamýšleného návrhu ale ovládací prvek nemusí reagovat na všechny klíčové hodnoty, které jsou na něj směrovány prostřednictvím klíčových událostí. Chování je specifické pro každý ovládací prvek.

Například ButtonBase (základní třída pro Button) zpracovává keyUp , aby mohl zkontrolovat mezerník nebo klávesu Enter. ButtonBase považuje KeyUp ekvivalent levého tlačítka myši dolů pro účely vyvolání události Kliknutí . Toto zpracování události se provádí, když ButtonBase přepíše virtuální metodu OnKeyUp. V jeho implementaci nastaví Handled na true. Výsledkem je, že jakýkoli nadřazený prvek tlačítka, který čeká na klíčovou událost, v případě mezerníku, neobdrží událost již zpracovanou jeho vlastními obslužnými procedurami.

Dalším příkladem je TextBox. Některé klávesy, jako jsou například klávesy se šipkami, nejsou v TextBox považovány za text, ale místo toho jsou považovány za specifické pro chování uživatelského rozhraní ovládacího prvku. TextBox označí tyto případy událostí jako vyřešené.

Vlastní ovládací prvky mohou implementovat podobné chování přepisu pro klávesové události přepsáním OnKeyDown / OnKeyUp. Pokud vaše vlastní ovládací prvky zpracovávají specifické akcelerátorové klávesy nebo mají chování ovládání nebo fokusování, které je podobné scénáři popsanému pro TextBox, měli byste tuto logiku umístit do vlastních přepisů metod OnKeyDown / OnKeyUp.

Dotyková klávesnice

Ovládací prvky pro zadávání textu poskytují automatickou podporu dotykové klávesnice. Když uživatel nastaví fokus vstupu na ovládací prvek textu pomocí dotykového vstupu, zobrazí se dotyková klávesnice automaticky. Pokud fokus vstupu není na textovém ovládacím prvku, je dotyková klávesnice skrytá.

Když se zobrazí dotyková klávesnice, automaticky přemísťuje uživatelské rozhraní, aby se zajistilo, že prioritní prvek zůstane viditelný. To může způsobit, že se ostatní důležité oblasti uživatelského rozhraní přesunou mimo obrazovku. Můžete ale zakázat výchozí chování a provést vlastní úpravy uživatelského rozhraní, když se zobrazí dotyková klávesnice. Další informace najdete v ukázce dotykové klávesnice.

Pokud vytvoříte vlastní ovládací prvek, který vyžaduje textové zadání, ale neodvozuje se ze standardního ovládacího prvku pro zadávání textu, můžete přidat podporu dotykové klávesnice implementací správných vzorů ovládacích prvků automatizace uživatelského rozhraní. Další informace najdete v ukázce dotykové klávesnice.

Stisknutí kláves na dotykové klávesnici vyvolává události KeyDown a KeyUp stejně jako klávesy na hardwarových klávesnicích. Dotyková klávesnice ale nevyvolá vstupní události pro Ctrl+A, Ctrl+Z, Ctrl+X, Ctrl+C a Ctrl+V, které jsou vyhrazené pro manipulaci s textem ve vstupním ovládacím prvku.

Uživatelům můžete usnadnit zadávání dat do aplikace nastavením vstupního rozsahu ovládacího prvku textu tak, aby odpovídal druhu dat, která očekáváte, že uživatel zadá. Vstupní obor poskytuje nápovědu k typu textového vstupu očekávaného ovládacím prvkem, aby systém mohl poskytnout specializované rozložení dotykové klávesnice pro typ vstupu. Pokud je například textové pole použito pouze k zadání 4místného PIN kódu, nastavte Vlastnost InputScope na Number. Tím systému sdělíte, že má zobrazit rozložení numerické klávesnice, což uživateli usnadní zadání KÓDU PIN. Další podrobnosti najdete v tématu Použití rozsahu vstupu ke změně dotykové klávesnice.

Developers

Návrháři

Samples

Archivní ukázky