다음을 통해 공유


Responding to keyboard interactions (XAML)

Respond to keystroke actions from a hardware or touch keyboard in your apps using both keyboard and class event handlers.

Important  

Some Windows Runtime controls handle input events internally. In these cases, it might appear that an input event doesn't occur because your event listener doesn't invoke the associated handler. Typically, this subset of keys is processed by the class handler to provide built in support of basic keyboard accessibility. For example, the Button class overrides the OnKeyDown events for both the Space key and the Enter key (as well as OnPointerPressed) and routes them to the Click event of the control. When a key press is handled by the control class, the KeyDown and KeyUp events are not raised.

This provides a built-in keyboard equivalent for invoking the button, similar to tapping it with a finger or clicking it with a mouse. Keys other than Space or Enter still fire KeyDown and KeyUp events. See Events and routed events overview for more info on how class-based handling of events works (specifically, Input event handlers in controls).

 

Tip  The info in this topic is specific to developing apps using C++, C#, or Visual Basic.

See Responding to keyboard interactions (HTML) for apps using JavaScript.

 

Prerequisites: Have a look through these topics to get familiar with the technologies discussed here.

Create your first Windows Store app using C# or Visual Basic

Create your first Windows Store app using C++

Roadmap for Windows Store apps using C# or Visual Basic

Roadmap for Windows Store apps using C++

Learn about events with Events and routed events overview

App features, start to finish: Explore this functionality in more depth as part of our App features, start to finish series

User interaction, start to finish (XAML)

User interaction customization, start to finish (XAML)

User experience guidelines:

The platform control libraries (HTML and XAML) provide the full user interaction experience, including standard interactions, animated physics effects, and visual feedback. If you don't need customized interaction support, use these built-in controls.

If the platform controls are not sufficient, these user interaction guidelines can help you provide a compelling and immersive interaction experience that is consistent across input modes. These guidelines are primarily focused on touch input, but they are still relevant for touchpad, mouse, keyboard, and stylus input.

Samples: See this functionality in action in our app samples.

Input sample

Input: Device capabilities sample

Input: Touch keyboard sample

Responding to the appearance of the on-screen keyboard sample

Overview

Keyboard input is an important part of the overall user interaction experience for apps. The keyboard is indispensable to people with certain disabilities or users who just consider it a more efficient way to interact with an app. For example, users should be able to navigate your app by using Tab and arrow keys, activate UI elements by using Spacebar and Enter, and access commands by using keyboard shortcuts.

A well-designed keyboard UI is an important aspect of software accessibility. It enables users with vision impairments or who have certain motor disabilities to navigate an app and interact with its features. Such users might be unable to operate a mouse and instead rely on various assistive technologies such as keyboard enhancement tools, on-screen keyboards, screen enlargers, screen readers, and voice input utilities.

The most common type of keyboard is the external, hardware keyboard that is physically connected to a device. In addition to a hardware keyboard, Windows 8 provides two software keyboards:

  • Note  Windows:

    The On-Screen Keyboard is a visual, software keyboard that you can use instead of the physical keyboard to type and enter data using touch, mouse, pen/stylus or other pointing device (a touch screen is not required). The On-Screen Keyboard is provided for systems that don't have a physical keyboard, or for users whose mobility impairments prevent them from using traditional physical input devices. The On-Screen Keyboard emulates most, if not all, the functionality of a hardware keyboard.

  • Note  Windows:

    The touch keyboard is a visual, software keyboard used for text entry with touch input. The touch keyboard is not a replacement for the On-Screen Keyboard as it is used for text input only (it doesn't emulate the hardware keyboard) and appears only when a text field or other editable text control gets focus.

    Note  the On-Screen Keyboard has priority over the touch keyboard, which won't be shown if the On-Screen Keyboard is present.

     

    Here are examples of the touch keyboard. The first image is the default layout, the second is the thumb layout (which might not be available in all languages).

Keyboard events

The following keyboard events can occur for both hardware and touch keyboards.

Event Description
KeyDown Occurs when a key is pressed.
KeyUp Occurs when a key is released.

 

Keyboard events and focus

Controls in your UI generate keyboard events only when they have input focus. An individual control gains focus when the user clicks or taps directly on that control in the layout, or uses the Tab key to step into a tab sequence within the content area.

You can also call a control's Focus method to force focus. This is necessary when you implement shortcut keys, because keyboard focus is not set by default when your UI loads. For more info, see the Shortcut keys example later in this topic.

For a control to receive input focus, it must be enabled, visible, and have IsTabStop and HitTestVisible property values of true. This is the default state for most controls. When a control has input focus, it can raise and respond to keyboard input events as described later in this topic. You can also respond to a control that is receiving or losing focus by handling the GotFocus and LostFocus events.

By default, the tab sequence of controls is the order in which they appear in the XAML. However, you can modify this order by using the TabIndex property. For more info, see Implementing keyboard accessibility.

Keyboard event handlers

An input event handler implements a delegate that provides the following information:

  • The sender of the event. The sender reports the object where the event handler is attached.
  • Event data. For keyboard events, that data will be an instance of KeyRoutedEventArgs. The delegate for handlers is KeyEventHandler. The most relevant properties of KeyRoutedEventArgs for most handler scenarios are Key and possibly KeyStatus.
  • OriginalSource. Because the keyboard events are routed events, the event data provides OriginalSource. If you deliberately allow events to bubble up through an object tree, OriginalSource is sometimes the object of concern rather than sender. However, that depends on your design. For more information on how you might use OriginalSource rather than sender, see the "Keyboard Routed Events" section of this topic, or Events and routed events overview.

Attaching a keyboard event handler

You can attach keyboard event-handler functions for any object that includes the event as a member. This includes any UIElement derived class. The following XAML example shows how to attach handlers for the KeyUp event for a Grid.

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

You can also attach an event handler in code. For more info, see Events and routed events overview.

Defining a keyboard event handler

The following example shows the incomplete event handler definition for the KeyUp event handler that was attached in the preceding example.

void Grid_KeyUp(object sender, KeyRoutedEventArgs e)
{
    //handling code here
}
Private Sub Grid_KeyUp(ByVal sender As Object, ByVal e As KeyRoutedEventArgs)
    'handling code here
End Sub
void MyProject::MainPage::Grid_KeyUp(
  Platform::Object^ sender,
  Windows::UI::Xaml::Input::KeyRoutedEventArgs^ e)
{//handling code here}

Using KeyRoutedEventArgs

All keyboard events use KeyRoutedEventArgs for event data, and KeyRoutedEventArgs contains the following properties:

Key

The KeyDown event is raised if a key is pressed. Likewise, KeyUp is raised if a key is released. Usually you listen to the events to process a specific key value. To determine which key is pressed or released, check the Key value in the event data. Key returns a VirtualKey value. The VirtualKey enumeration includes all the supported keys.

Modifier keys

Note  Windows:

Modifier keys are keys such as Ctrl or Shift that users typically press in combination with other keys. Your app can use these combinations as keyboard shortcuts to invoke app commands.

You detect shortcut key combinations by using code in your KeyDown and KeyUp event handlers. You can then track the pressed state of the modifier keys you are interested in. When a keyboard event occurs for a non-modifier key, you can check whether a modifier key is in the pressed state at the same time.

Note  The Alt key is represented by the VirtualKey.Menu value.

 

Shortcut keys example

Note  Windows:

The following example demonstrates how to implement shortcut keys. In this example, users can control media playback using Play, Pause, and Stop buttons or Ctrl+P, Ctrl+A, and Ctrl+S keyboard shortcuts. The button XAML shows the shortcuts by using tooltips and AutomationProperties properties in the button labels. This self-documentation is important to increase the usability and accessibility of your app. For more info, see Implementing keyboard accessibility.

Note also that the page sets input focus to itself when it is loaded. Without this step, no control has initial input focus, and the app does not raise input events until the user sets the input focus manually (for example, by tabbing to or clicking a control).

<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^ e)
{
    (void) e;    // Unused parameter
    this->Loaded+=ref new RoutedEventHandler(this,&MainPage::ProgrammaticFocus);
}
void MainPage::ProgrammaticFocus(Object^ sender, RoutedEventArgs^ e) {
    this->Focus(Windows::UI::Xaml::FocusState::Programmatic);
}

void KeyboardSupport::MainPage::MediaButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
    FrameworkElement^ fe = safe_cast<FrameworkElement^>(sender);
    if (fe->Name == "PlayButton") {DemoMovie->Play();}
    if (fe->Name == "PauseButton") {DemoMovie->Pause();}
    if (fe->Name == "StopButton") {DemoMovie->Stop();}
}


void KeyboardSupport::MainPage::Grid_KeyDown(Platform::Object^ sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs^ e)
{
    if (e->Key == VirtualKey::Control) isCtrlKeyPressed = true;
}


void KeyboardSupport::MainPage::Grid_KeyUp(Platform::Object^ sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs^ e)
{
    if (e->Key == VirtualKey::Control) isCtrlKeyPressed = true;
    else 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 Grid_KeyUp(object sender, KeyRoutedEventArgs e)
{
    if (e.Key == VirtualKey.Control) isCtrlKeyPressed = false;
}

private void Grid_KeyDown(object sender, KeyRoutedEventArgs e)
{
    if (e.Key == VirtualKey.Control) isCtrlKeyPressed = true;
    else if (isCtrlKeyPressed)
    {
        switch (e.Key)
        {
            case VirtualKey.P: DemoMovie.Play(); break;
            case VirtualKey.A: DemoMovie.Pause(); break;
            case VirtualKey.S: DemoMovie.Stop(); break;
        }
    }
}

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 isCtrlKeyPressed As Boolean
Protected Overrides Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)

End Sub

Private Sub Grid_KeyUp(sender As Object, e As KeyRoutedEventArgs)
    If e.Key = Windows.System.VirtualKey.Control Then
        isCtrlKeyPressed = False
    End If
End Sub

Private Sub Grid_KeyDown(sender As Object, e As KeyRoutedEventArgs)
    If e.Key = Windows.System.VirtualKey.Control Then isCtrlKeyPressed = True
    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

Note  Setting AutomationProperties.AcceleratorKey or AutomationProperties.AccessKey in XAML provides string information, which documents the shortcut key for invoking that particular action. The information is captured by Microsoft UI Automation clients such as Narrator, and is typically provided directly to the user. Setting AutomationProperties.AcceleratorKey or AutomationProperties.AccessKey does not have any action on its own. You will still need to attach handlers for KeyDown or KeyUp events in order to actually implement the keyboard shortcut behavior in your app. Also, the underline text decoration for an access key is not provided automatically. You must explicitly underline the text for the specific key in your mnemonic as inline Underline formatting if you wish to show underlined text in the UI.

 

Keyboard routed events

Certain events are routed events, including KeyDown and KeyUp. Routed events use the bubbling routing strategy. The bubbling routing strategy means that an event originates from a child object and is then routed up to successive parent objects in the object tree. This presents another opportunity to handle the same event and interact with the same event data.

Consider the following XAML example, which handles KeyUp events for a Canvas and two Button objects. In this case, if you release a key while focus is held by either Button object, it raises the KeyUp event. The event is then bubbled up to the parent Canvas.

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

The following example shows how to implement the KeyUp event handler for the corresponding XAML content in the preceding example.

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);
}

Notice the use of the OriginalSource property in the preceding handler. Here, OriginalSource reports the object that raised the event. The object could not be the StackPanel because the StackPanel is not a control and cannot have focus. Only one of the two buttons within the StackPanel could possibly have raised the event, but which one? You use OriginalSource to distinguish the actual event source object, if you are handling the event on a parent object.

The Handled property in event data

Depending on your event handling strategy, you might want only one event handler to react to a bubbling event. For instance, if you have a specific KeyUp handler attached to one of the Button controls, it would have the first opportunity to handle that event. In this case, you might not want the parent panel to also handle the event. For this scenario, you can use the Handled property in the event data.

The purpose of the Handled property in a routed event data class is to report that another handler you registered earlier on the event route has already acted. This influences the behavior of the routed event system. When you set Handled to true in an event handler, that event stops routing and is not sent to successive parent elements.

AddHandler and already-handled keyboard events

You can use a special technique for attaching handlers that can act on events that you already marked as handled. This technique uses the AddHandler method to register a handler, rather than using XAML attributes or language-specific syntax for adding handlers, such as += in C#. A limitation of this technique in general is that the AddHandler API takes a parameter of type RoutedEvent that identifies the routed event in question. Not all routed events provide a RoutedEvent identifier, and this consideration thus affects which routed events can still be handled in the Handled case. The KeyDown and KeyUp events have routed event identifiers (KeyDownEvent and KeyUpEvent) on UIElement. However, other events such as TextBox.TextChanged do not have routed event identifiers and thus cannot be used with the AddHandler technique.

Commanding

A small number of UI elements provide built-in support for commanding. Commanding uses input-related routed events in its underlying implementation. It enables processing of related UI input, such as a certain pointer action or a specific accelerator key, by invoking a single command handler.

If commanding is available for a UI element, consider using its commanding APIs instead of any discrete input events. For more info, see ButtonBase.Command.

You can also implement ICommand to encapsulate command functionality that you invoke from ordinary event handlers. This enables you to use commanding even when there is no Command property available.

Text input and controls

Certain controls react to keyboard events with their own handling. For instance, TextBox is a control that is designed to capture and then visually represent text that was entered by using the keyboard. It uses KeyUp and KeyDown in its own logic to capture keystrokes, then also raises its own TextChanged event if the text actually changed.

You can still generally add handlers for KeyUp and KeyDown to a TextBox, or any related control that is intended to process text input. However, as part of its intended design, a control might not respond to all key values that are directed to it through key events. Behavior is specific to each control.

As an example, ButtonBase (the base class for Button) processes KeyUp so that it can check for the Spacebar or Enter key. ButtonBase considers KeyUp equivalent to a mouse left button down for purposes of raising a Click event. This processing of the event is accomplished when ButtonBase overrides the virtual method OnKeyUp. In its implementation, it sets Handled to true. The result is that any parent of a button that is listening for a key event, in the case of a Spacebar, would not receive the already-handled event for its own handlers.

Another example is TextBox. Some keys, such as the ARROW keys, are not considered text by TextBox and are instead considered specific to the control UI behavior. The TextBox marks these event cases as handled.

Custom controls can implement their own similar override behavior for key events by overriding OnKeyDown / OnKeyUp. If your custom control processes specific accelerator keys, or has control or focus behavior that is similar to the scenario described for TextBox, you should place this logic in your own OnKeyDown / OnKeyUp overrides.

The touch keyboard

Text input controls provide automatic support for the touch keyboard. When the user sets the input focus to a text control by using touch input, the touch keyboard appears automatically. When the input focus is not on a text control, the touch keyboard is hidden.

When the touch keyboard appears, it automatically repositions your UI to ensure that the focused element remains visible. This can cause other important areas of your UI to move off screen. However, you can disable the default behavior and make your own UI adjustments when the touch keyboard appears. For more info, see Responding to the appearance of the on-screen keyboard sample.

If you create a custom control that requires text input, but does not derive from a standard text input control, you can add touch keyboard support by implementing the correct UI Automation control patterns. For more info, see the Touch keyboard sample.

Key presses on the touch keyboard raise KeyDown and KeyUp events just like key presses on hardware keyboards. However, the touch keyboard will not raise input events for Ctrl+A, Ctrl+Z, Ctrl+X, Ctrl+C, and Ctrl+V, which are reserved for text manipulation in the input control.

User experience guidelines for supporting keyboard interactions

Here are some guidelines for supporting keyboard interactions.

General

  • Note  Windows:

    Users should be able to accomplish all tasks supported by your app using only the hardware keyboard or the On-Screen Keyboard.

    Note  The touch keyboard is used for text input only, not for app or system commands.

     

  • When your app starts, set initial keyboard focus on the element that users will intuitively (or most likely) interact with first. Typically, the most appropriate location is the main content view of the app so that a user can immediately scroll the content using the arrow keys. For more info on setting focus to specific controls, see Focus.

  • Note  Windows:

    Make sure the Tab and arrows keys move through content in a logical order.

  • Set the TabIndex property to a value that is greater than or equal to 0 for all interactive UI elements that are not in the tab order by default. Setting the TabIndex property is important because screen reader users navigate among interactive UI elements by using the Tab key.

  • Note  Windows:

    Use the arrow keys as keyboard shortcuts for proper inner navigation among child elements of composite elements. If tree view nodes have separate child elements for handling expand–collapse and node activation, use the left and right arrow keys to provide keyboard expand–collapse functionality.

  • Ensure that each UI element that can be clicked can also be invoked with the keyboard.

  • Note  Windows:

    Implement keyboard shortcuts for key app functionality. (A shortcut is a key combination that enhances productivity by providing an efficient way for the user to access app functionality.)

    An access key is a shortcut to a UI element in your app. It consists of the Alt key and a letter key.

    An accelerator key is a shortcut to an app command. Your app can have UI that corresponds exactly to the command. Accelerator keys consist of the Ctrl key and a letter key.

    You must provide an easy way for users who rely on screen readers and other assistive technology to discover your app's shortcut keys. Declare your shortcut keys in your app's HTML markup by using the AccessKey property, and communicate shortcut keys by using tooltips, accessible names, accessible descriptions, or some other form of on-screen communication. Remember to document shortcut keys well in your app's help content.

    For more guidance about implementing shortcut keys, see Shortcut keys in the Windows User Experience Guidelines.

    Do not redefine the default keyboard shortcuts users expect from within every Windows Store app. See Keyboard shortcuts for a comprehensive list.

Hardware

Query the keyboard device capabilities (KeyboardCapabilities) to determine if a keyboard is attached and to identify what aspects of your app UI the keyboard hardware can access directly. For more info on querying device capabilities, see Quickstart: Identifying pointer devices.

Associate keyboard buttons with appropriate UI (back and forward buttons) in your app.

Visual feedback

  • Use focus rectangles only with keyboard interactions. If the user initiates a touch interaction, make the keyboard UI gradually fade away. This keeps the UI clean and uncluttered.
  • Don't display visual feedback if an element doesn't support interaction (such as static text).
  • Display visual feedback concurrently for all elements that represent the same input target.
  • Provide on-screen buttons (such as + and -) as hints for emulating touch-based manipulations such as panning, rotating, zooming, and so on.

For more general guidance on visual feedback, see Guidelines for visual feedback.

Conceptual

Responding to user interaction

Quickstart: adding HTML controls and handling events

Implementing keyboard accessibility

Accessibility in Windows Store apps using C++, C#, or Visual Basic

Displaying and editing text

Input hosting manager and the touch keyboard