События клавиатуры

События клавиатуры и фокус

Следующие событие клавиатуры могут возникнуть при использовании как аппаратной, так и сенсорной клавиатуры.

Событие Описание
KeyDown Вызывается при нажатии клавиши.
KeyUp Вызывается при отпускании клавиши.

Важно!

Некоторые элементы управления XAML обрабатывают события ввода внутри системы. В этом случае может показаться, что событие ввода не происходит, поскольку прослушиватель событий не вызывает связанный обработчик. Обычно это подмножество клавиш обрабатывается обработчиком классов для обеспечения встроенной поддержки базовых специальных возможностей клавиатуры. Например, класс Button переопределяет события OnKeyDown для клавиш ПРОБЕЛ и ВВОД (а также OnPointerPressed) и перенаправляет их в событие Click элемента управления. Если нажатие клавиши обрабатывается классом элемента управления, события KeyDown и KeyUp не вызываются.
Это предоставляет эквивалентную встроенную клавиатуру для вызова кнопки, что похоже на касание пальцем или щелчок мышью. Клавиши, отличные от клавиш ПРОБЕЛ и ВВОД, вызывают события KeyDown и KeyUp. Дополнительные сведения об обработке событий на базе класса можно найти в статье Общие сведения о событиях и перенаправленных событиях (в частности, в разделе "Обработчики событий ввода в элементах управления").

Элементы пользовательского интерфейса создают события клавиатуры только при наличии у них фокуса ввода. Отдельный элемент управления получает фокус, когда пользователь щелкает этот элемент или касается его непосредственно в макете либо переходит на него с помощью клавиши Tab по последовательности табуляции в пределах области размещения содержимого.

Также можно принудительно установить фокус, вызвав метод Focus элемента управления. Это необходимо при реализации сочетаний клавиш, поскольку по умолчанию фокус клавиатуры не устанавливается при загрузке пользовательского интерфейса. Дополнительные сведения см. в разделе Пример использования сочетания клавиш далее в этой теме.

Для того чтобы элемент управления получил фокус, он должен быть включенным, видимым, а его свойства IsTabStop и HitTestVisible должны иметь значение true. Для большинства элементов управления это состояние по умолчанию. При наличии у элемента управления фокуса ввода он может вызывать события клавиатурного ввода и реагировать на них, как описано далее в этой теме. Также вы можете реагировать на получение или потерю фокуса элементом управления, обрабатывая события GotFocus и LostFocus.

По умолчанию последовательность табуляции для элементов управления аналогична порядку, в котором они указаны в XAML (Extensible Application Markup Language). Однако этот порядок можно изменить с помощью свойства TabIndex. Дополнительные сведения см. в разделе Реализация специальных возможностей клавиатуры.

Обработчики событий клавиатуры

Обработчик событий ввода реализует делегат, который предоставляет следующие сведения:

  • Отправитель события. Отправитель сообщает, к какому объекту присоединен обработчик событий.
  • Данные события. Для событий клавиатуры эти данные представляют собой экземпляр KeyRoutedEventArgs. Делегатом для обработчиков является KeyEventHandler. Наиболее значимыми свойствами KeyRoutedEventArgs в большинстве сценариев использования обработчиков являются Key и, возможно, KeyStatus.
  • OriginalSource. Поскольку события клавиатуры являются перенаправленными событиями, данные события включают OriginalSource. Если вы намеренно разрешаете восходящую маршрутизацию событий в дереве объектов, проблемы более вероятны с OriginalSource, а не с отправителем. Однако это зависит от разработки. Дополнительные сведения о возможности использования OriginalSource вместо отправителя см. в разделе "Перенаправленные события клавиатуры" этой статьи или в статье Общие сведения о событиях и перенаправленных событиях.

Присоединение обработчика событий клавиатуры

Функции обработчика событий клавиатуры можно прикрепить к любому объекту, включающему это событие в качестве члена. К таким объектам относятся и любые производные классы UIElement. В следующем примере XAML показано, как присоединять обработчики для события KeyUp элемента Grid.

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

Кроме того, обработчик событий можно прикрепить и в коде. Дополнительные сведения см. в разделе Общие сведения о событиях и перенаправленных событиях.

Определение обработчика событий клавиатуры

В следующем примере показано неполное определение обработчика событий KeyUp, прикрепленного в предыдущем примере.

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
  }

Использование KeyRoutedEventArgs

Все события клавиатуры используют KeyRoutedEventArgs для указания данных события. Объект KeyRoutedEventArgs содержит следующие свойства.

Виртуальные ключи

Событие KeyDown создается, когда нажата клавиша. Подобным образом событие KeyUp создается, когда клавиша отпущена. Обычно прослушивание событий выполняется для обработки определенного значения клавиши. Чтобы определить, какая клавиша нажата или отпущена, проверьте значение Key в данных события. Key возвращает значение VirtualKey value. Перечисление VirtualKey содержит все поддерживаемые клавиши.

Клавиши-модификаторы

Клавиши-модификаторы — это такие клавиши, как CTRL или SHIFT, которые пользователи обычно нажимают в сочетании с другими клавишами. Приложение может использовать эти сочетания в качестве настраиваемых сочетаний клавиш для вызова команд приложения.

Примечание

Встроенные сочетания клавиш см. в разделе Клавиши доступа и сочетания клавиш.

Сочетания сочетаний клавиш можно обнаружить в обработчиках событий KeyDown и KeyUp . При возникновении события клавиатуры для клавиши, не являющейся модификатором, можно проверка, находится ли клавиша-модификатор в состоянии нажатия.

Кроме того, функция GetKeyState()объекта CoreWindow (полученная с помощью CoreWindow.GetForCurrentThread()) также может использоваться для проверка состояния модификатора при нажатии клавиши, не являющейся модификатором.

В следующих примерах реализуется этот второй метод, а также включается код заглушки для первой реализации.

Примечание

Клавиша ALT представлена значением VirtualKey.Menu.

Пример использования сочетаний клавиш

В следующем примере показано, как реализовать набор пользовательских сочетаний клавиш. В этом примере пользователь может управлять воспроизведением мультимедиа с помощью кнопок "Воспроизведение", "Пауза" или "Остановка" либо клавиш Ctrl+P, Ctrl+A и Ctrl+S. XAML-код кнопки отображает сочетания клавиш с помощью всплывающих подсказок и свойств AutomationProperties в подписях кнопок. Такое самодокументирование важно для увеличения удобства вашего приложения и его доступности для людей с ограниченными возможностями. Дополнительную информацию см. в статье Специальные возможности клавиатуры.

Обратите также внимание, что страница при загрузке устанавливает фокус ввода на себя. Без этого действия никакой элемент управления не получает первоначальный фокус ввода, и приложение не вызывает событие ввода до тех пор, пока пользователь вручную не установит фокус ввода (например, перейдя с помощью клавиши TAB или щелкнув элемент управления).

<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,&amp;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();}
}


bool KeyboardSupport::MainPage::IsCtrlKeyPressed()
{
    auto ctrlState = CoreWindow::GetForCurrentThread()->GetKeyState(VirtualKey::Control);
    return (ctrlState & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down;
}

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 (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 = CoreWindow.GetForCurrentThread().GetKeyState(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 = CoreWindow.GetForCurrentThread().GetKeyState(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

Примечание

Параметр AutomationProperties.AcceleratorKey или AutomationProperties.AccessKey в XAML предоставляет строковые сведения, которые регистрируют сочетание клавиш для вызова определенного действия. Эти сведения записываются клиентами автоматизации пользовательского интерфейса Майкрософт, например экранным диктором, и, как правило, предоставляются пользователю напрямую.

Параметр AutomationProperties.AcceleratorKey или AutomationProperties.AccessKey не имеет собственных действий. Но вам все равно нужно подключить обработчики для событий KeyDown или KeyUp, чтобы фактически реализовать применение сочетания клавиш в вашем приложении. Подчеркивание клавиши доступа не предоставляется автоматически. Вы должны явным образом подчеркнуть текст, относящийся к определенной назначенной клавише в качестве встроенного форматирования Underline, если вы хотите, чтобы подчеркнутый текст отображался в пользовательском интерфейсе.

 

Перенаправленные события клавиатуры

Некоторые события являются перенаправленными, включая KeyDown и KeyUp. Перенаправленные события используют стратегию восходящей маршрутизации. Стратегия восходящего перенаправления означает, что событие происходит из дочернего объекта, а затем направляется по последующим родительским объектам в дереве объектов. Это предоставляет еще одну возможность обработки того же события и взаимодействия с его данными.

Рассмотрим следующий пример кода XAML, в котором обрабатываются события KeyUp для объекта Canvas и двух объектов Button. В этом случае, если отпустить клавишу во время удержания фокуса любым из объектов Button, будет вызвано событие KeyUp. Затем событие передается родительскому объекту Canvas.

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

В следующем примере показана реализация обработчика событий KeyUp для соответствующего содержимого XAML из предыдущего примера.

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

Обратите внимание на использование свойства OriginalSource в предыдущем обработчике. Здесь OriginalSource сообщает об объекте, вызвавшем событие. Этим объектом не может быть StackPanel, поскольку StackPanel не является элементом управления и не может содержать фокус. Событие могло быть вызвано только одной из двух кнопок внутри StackPanel, но какой именно? Определить исходный объект текущего события, если оно обрабатывается на уровне родительского объекта, позволяет свойство OriginalSource.

Свойство Handled в данных события

В зависимости от выбранной стратегии обработки событий для реакции на восходящее событие можно использовать только один обработчик событий. Например, если имеется особый обработчик KeyUp, прикрепленный к одному из элементов управления Button, у него в первую очередь будет возможность обработать данное событие. В этом случае не нужно, чтобы событие было также обработано родительской панелью. Для данного сценария можно воспользоваться свойством Handled в данных события.

Цель свойства Handled в классе данных перенаправленного события – сообщить о том, что другой ранее зарегистрированный обработчик на маршруте события уже был задействован. Это влияет на поведение системы перенаправленных событий. При установке для Handled значения true в обработчике событий перенаправление этого события прекращается и оно не передается последующим родительским элементам.

AddHandler и уже обработанные события клавиатуры

Для присоединения обработчиков, которые могут реагировать на события, уже отмеченные как обработанные, можно использовать специальную методику. В этом методе для регистрации обработчика используется метод AddHandler , а не атрибуты XAML или синтаксис языка для добавления обработчиков, например += в C#.

Обычным ограничением для этой методики является то, что API AddHandler принимает параметр типа RoutedEvent, который идентифицирует рассматриваемое перенаправленное событие. Идентификатор RoutedEvent предоставляется не всеми перенаправленными событиями, и это соображение влияет на то, какие перенаправленные события все же могут быть обработаны в случае Handled. События KeyDown и KeyUp имеют идентификаторы перенаправленных событий (KeyDownEvent и KeyUpEvent) в UIElement. Однако другие события, например TextBox.TextChanged, не имеют идентификаторов перенаправленных событий, и поэтому для них нельзя использовать методику AddHandler.

Переопределение событий и поведения клавиатуры

Вы можете переопределить основные события для определенных элементов управления (таких как GridView) для обеспечения согласованного перемещения фокуса для различных устройств ввода, в том числе клавиатуры и игрового контроллера.

В следующем примере мы подклассируем элемент управления и переопределим поведение KeyDown, чтобы переместить фокус на содержимое GridView при нажатии любой клавиши со стрелкой.

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

Примечание

Если GridView используется только для макета, рассмотрите возможность использования других элементов управления, таких как ItemsControl с ItemsWrapGrid.

Система команд

Небольшое количество элементов пользовательского интерфейса предоставляет встроенную поддержку команд. В командах используются связанные с вводом перенаправленные события в базовой реализации. Это позволяет обрабатывать соответствующий ввод в пользовательском интерфейсе, например определенное действие указателя или нажатие определенного сочетания клавиш, путем вызова единого обработчика команды.

Если для элемента пользовательского интерфейса доступен командный интерфейс, обдумайте использование соответствующих API командного интерфейса вместо любых дискретных событий ввода. Подробнее: ButtonBase.Command.

Также можно реализовать ICommand для инкапсуляции функциональных возможностей команд, вызываемых из обычных обработчиков событий. Это позволяет использовать команды даже при отсутствии свойства Command.

Ввод текста и элементы управления

Некоторые элементы управления реагируют на события клавиатуры собственной обработкой. Например, TextBox – элемент управления, предназначенный для захвата и дальнейшего визуального представления текста, введенного с помощью клавиатуры. В нем используются KeyUp и KeyDown с собственной логикой перехвата нажатий клавиш, а затем инициируется собственное событие TextChanged, если текст был изменен.

Вы по-прежнему можете добавлять обработчики для KeyUp и KeyDown в TextBox или любой связанный элемент управления, предназначенный для обработки текстового ввода. Однако элемент управления может быть разработан так, что будет отвечать не на все значения клавиш, направляемые ему через события клавиш. Для каждого элемента управления задается своя реакция.

Например, ButtonBase (базовый класс для Button) обрабатывает KeyUp таким образом, что он может проверять клавиши ПРОБЕЛ или ВВОД. ButtonBase считает KeyUp эквивалентом нажатия левой кнопки мыши в целях инициации события Click. Эта обработка события выполняется, когда ButtonBase переопределяет виртуальный метод OnKeyUp. При реализации он устанавливает Handled на true. В результате получается, что любой родительский элемент кнопки, прослушивающий событие клавиши, при нажатии клавиши ПРОБЕЛ не получит уже обработанное событие для своих обработчиков.

Еще один пример – TextBox. Некоторые клавиши, например клавиши со стрелками, не считаются текстом в TextBox и вместо этого считаются специфическими для пользовательского интерфейса элемента управления. TextBox отмечает эти случаи событий как обработанные.

Пользовательские элементы управления могут реализовывать собственное поведение переопределения для ключевых событий, переопределяя OnKeyDown / OnKeyUp. Если пользовательский элемент управления обрабатывает определенные сочетания клавиш либо реагирует как элемент управления или фокус аналогично сценарию, описанному для TextBox, следует применить эту логику к собственным переопределениям OnKeyDown / OnKeyUp.

Сенсорная клавиатура

Элементы управления вводом текста обеспечивают автоматическую поддержку сенсорной клавиатуры. Когда пользователь устанавливает фокус ввода на текстовый элемент управления посредством сенсорного ввода, сенсорная клавиатура автоматически активируется. Когда фокус ввода не находится на текстовом элементе управления, сенсорная клавиатура скрыта.

При появлении сенсорной клавиатуры она автоматически изменяет положение пользовательского интерфейса так, чтобы содержащий фокус элемент оставался видимым. Это может вызвать отдаление других важных областей пользовательского интерфейса за пределы экрана. Однако можно отключить поведение по умолчанию и вносить собственные изменения в пользовательский интерфейс при появлении сенсорной клавиатуры. Подробнее см. в разделе Пример сенсорной клавиатуры.

При создании пользовательского элемента управления текстовым вводом, не происходящего от стандартного элемента управления текстовым вводом, можно добавить поддержку сенсорной клавиатуры, реализовав нужные шаблоны элементов управления автоматизацией пользовательского интерфейса. Подробнее см. в разделе Пример сенсорной клавиатуры.

Нажатия клавиш на сенсорной клавиатуре вызывают события KeyDown и KeyUp так же, как и нажатия клавиш на аппаратной клавиатуре. Однако сенсорная клавиатура не вызывает событий ввода для сочетаний клавиш Ctrl+A, Ctrl+Z, Ctrl+X, Ctrl+C и Ctrl+V, которые зарезервированы для обработки текста в элементе управления вводом.

Пользователи смогут вводить данные в вашем приложении гораздо быстрее и с меньшими усилиями, если вы настроите тип вводимых данных элемента управления текстом в соответствии с типом вводимых данных. Тип вводимых данных предоставляет подсказку о типе ожидаемого текстового ввода с помощью элемента управления, таким образом система может предоставить специальную раскладку сенсорной клавиатуры в соответствии с типом ввода. Например, если текстовое поле используется только для ввода 4-значного ПИН-кода, задайте для свойства InputScopeзначение Number. Это сообщает системе, что нужно отобразить раскладку цифровой клавиатуры, благодаря чему пользователю будет проще вводить ПИН-код. Дополнительную информацию можно найти в статье Использование типа вводимых данных для изменения сенсорной клавиатуры.

Разработчикам

Конструкторы

Примеры

Примеры архивов