(转)响应键盘输入

(使用 C#/VB/C++ 和 XAML 的 Windows 应用商店应用)

可以通过使用 C++、C# 或 Visual Basic 为 Windows 构建的 Windows 应用商店应用中的硬件或触摸键盘来响应击键操作。为此,请使用 Windows 8 中提供的键盘事件。

键盘支持对于辅助功能非常重要,并且能够在没有触摸屏时启用该功能。此外,有了键盘支持,对于那些经常使用键盘的用户来说,你的应用更实用。用户应可以使用 Tab 和箭头键导航应用,使用空格键和 Enter 键激活 UI 元素,并使用键盘快捷方式访问命令。

有关文本输入的详细信息,请参阅 显示和编辑文本

路线图: 本主题与其他主题有何关联?请参阅:

 

键盘事件

使用 C++、C# 或 Visual Basic 的 Windows 应用商店应用提供以下键盘事件,硬件和触摸键盘都可能会发生这些事件。

事件描述
KeyDown 按下某个键时发生。
KeyUp 释放某个键时发生。

 

键盘事件和焦点

仅当 UI 中的控件具有输入焦点时才会生成键盘事件。当用户直接单击或点击布局中的一个控件时该控件获得焦点,或者使用 Tab 键进入内容区域内的 Tab 序列。

也可以调用控件的 Focus 方法来强制使用焦点。当实现快捷键时需要此操作,因为 UI 加载时默认情况下不设置键盘焦点。有关详细信息,请参阅本主题后面部分的快捷键示例

若要使某个控件接收输入焦点,则必须启用该控件,该控件必须可见并且 IsTabStopHitTestVisible 的属性值必须为 true。这是大多数控件的默认状态。当某个控件具有输入焦点时,该控件可能引发并响应键盘输入事件,如本主题后面部分所述。你也可以通过处理 GotFocusLostFocus 事件来响应接收或丢失焦点的控件。

默认情况下,控件的 Tab 序列顺序为它们在 XAML 中的顺序。但是,可以使用 TabIndex 属性修改此顺序。有关详细信息,请参阅 实现键盘辅助功能

键盘事件处理程序

输入事件处理程序实现提供以下信息的委派:

  • 事件的发送者。发送者报告附加事件处理程序的对象。
  • 事件数据。对于键盘事件,该数据将是 KeyRoutedEventArgs 的一个实例。处理程序的委派为 KeyEventHandler。对于大多数处理程序方案而言,KeyRoutedEventArgs 的最为相关的属性是 Key,并且可能为 KeyStatus
  • OriginalSource。由于键盘事件是路由的事件,因此事件数据提供 OriginalSource。如果有意允许事件通过对象树向上浮生,则 OriginalSource 有时是所涉及的对象而不是发送者。但是,这取决于你的设计。有关如何使用 OriginalSource 而不是发送者的详细信息,请参阅本主题中的“键盘路由事件”部分或 事件和路由事件概述

附加键盘事件处理程序

可以为将事件作为成员包含的任何对象附加键盘事件处理程序功能。这包括任何 UIElement 派生类。以下 XAML 示例显示了如何为 GridKeyUp 事件附加处理程序。

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

也可以在代码中附加事件处理程序。有关详细信息,请参阅 事件和路由事件概述

定义键盘事件处理程序

以下示例显示了在上一示例中附加的 KeyUp 事件处理程序的不完整事件处理程序定义。

  1. void Grid_KeyUp(object sender, KeyRoutedEventArgs e)
  2. {
  3.     //handling code here
  4. }
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

所有键盘事件对事件数据均使用 KeyRoutedEventArgsKeyRoutedEventArgs 包含以下属性:

如果按下某个键,则引发 KeyDown 事件。同样,如果释放某个键,则引发 KeyUp。通常会侦听这些事件以处理特定键值。若要确定按下或释放了哪个键,请检查事件数据中的 Key 值。Key 返回 VirtualKey 值。VirtualKey 枚举包括使用 C++、C# 或 Visual Basic 的 Windows 应用商店应用支持的所有键。

修改键

修改键是用户通常与其他键组合而按下的键,如 Ctrl 或 Shift。你的应用可以使用这些组合作为键盘快捷方式来调用应用命令。

在使用 C++、C# 或 Visual Basic 的 Windows 应用商店应用中,你可以在 KeyDownKeyUp 事件处理程序中使用代码来检测快捷键组合。然后,你可以跟踪感兴趣的修改键的按下状态。当非修改键发生键盘事件时,可以同时检查修改键是否处于按下状态。

注意  Alt 键由 VirtualKey.Menu 值表示。

快捷键示例

以下示例演示如何实现快捷键。在此示例中,用户可以使用 Play、Pause 和 Stop 按钮或 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,&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

注意  在 XAML 中设置 AutomationProperties.AcceleratorKeyAutomationProperties.AccessKey 会提供字符串信息,这可记录用于调用该特定操作的快捷键。该信息由 Microsoft UI 自动化客户端(如讲述人)捕获,且通常直接提供给用户。设置 AutomationProperties.AcceleratorKeyAutomationProperties.AccessKey 不会自行执行任何操作。你将仍需要附加 KeyDownKeyUp 事件的处理程序,以便在你的应用中真正实现键盘快捷键行为。此外,不会自动为访问键提供带下划线的文本效果。如果你希望在 UI 中显示带下划线的文本,则必须明确对助记键中特定键的文本标注下划线,作为嵌入式 Underline 格式。

键盘路由事件

有些事件为路由事件,这些事件包括 KeyDownKeyUp。路由事件使用浮升路由策略。浮升路由策略意味着某个事件从子对象开始,然后向上路由到对象树中的连续父对象。这样便提供了处理相同事件以及与相同数据数据交互的另一个机会。

请考虑以下 XAML 示例,该示例处理一个 Canvas 和两个 Button 对象的 KeyUp 事件。这种情况下,如果在任一 Button 对象拥有焦点的同时释放键,则会引发 KeyUp 事件。然后,该事件向上浮升到父 Canvas

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

以下示例显示如何为前面示例中对应的 XAML 内容实现 KeyUp 事件处理程序。

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

请注意前面的处理程序中的 OriginalSource 属性的用法。此处,OriginalSource 报告引发此事件的对象。该对象不可能是 StackPanel,因为 StackPanel 不是控件,因此无法拥有焦点。只有 StackPanel 中的两个按钮之一可能引发此事件,但是是哪一个按钮呢?如果在父对象上处理此事件,则会使用 OriginalSource 来辨别实际的事件源对象。

事件数据中的 Handled 属性

根据你的事件处理策略,你可能希望只有一个事件处理程序对浮升事件进行响应。例如,如果已将特定的 KeyUp 处理程序附加到其中一个 Button 控件,则这是处理该事件的第一次机会。这种情况下,你可能不希望父面板也处理该事件。对于此方案,可以使用事件数据中的 Handled 属性。

路由事件数据类中的 Handled 属性用于报告之前在事件路由上注册的另一个处理程序已进行操作。这会影响路由事件系统的行为。在事件处理程序中将 Handled 设置为 true 时,该事件停止路由,但不会发送到连续的父元素。

AddHandler 和 already-handled 键盘事件

可以使用特殊技术来附加处理程序,该技术对已标记为已处理的事件进行操作。此技术使用 AddHandler 方法来注册处理程序,而不是使用 XAML 属性或特定语言的添加处理程序语法,如在 C# 中的“+=”。此技术的局限性通常是 AddHandler API 带有一个类型为 RoutedEvent 的参数,该参数标识有问题的路由事件。并非所有路由事件都提供 RoutedEvent 标识符,因此此注意事项会影响在 Handled 情况下仍然可以处理哪些路由事件。 KeyDownKeyUp 事件在 UIElement 上拥有路由事件标识符( KeyDownEventKeyUpEvent)。但是,其他事件(如 TextBox.TextChanged)没有路由事件标识符,因此不能使用 AddHandler 技术。

命令处理

少量 UI 元素提供对命令的内置支持。命令在其基础实现中使用与输入相关的路由事件。它能够通过调用一个命令处理程序来处理相关的 UI 输入,如某个指针操作或特定加速器键。

如果命令处理可用于 UI 元素,可以考虑使用它的命令处理 API 代替任何具体的输入事件。有关详细信息,请参阅 ButtonBase.Command

还可以实现 ICommand 来封装从普通事件处理程序中调用的命令功能。这样即使没有可用的 Command 属性,也能够使用命令。

文本输入和控件

某些控件通过自身的处理来对键盘事件作出响应。例如, TextBox 是一个控件,设计用于捕获然后在视觉上显示使用键盘输入的文本。它以自己的逻辑使用 KeyUpKeyDown 来捕获击键,然后,即使在文本实际上已更改的情况下,也还是会引发自己的 TextChanged 事件。

通常,仍然可以将 KeyUpKeyDown 的处理程序添加到 TextBox 或计划处理文本输入的任何相关控件中。但是,作为其预期设计,一个控件可能并不会对通过键事件指向它的所有键值作出响应。行为特定于每个控件。

例如, ButtonBaseButton 的基类)处理 KeyUp 以便可以检查空格键或 Enter 键。ButtonBase 认为 KeyUp 等同于按下鼠标左键以引发 Click 事件。事件的这一处理是在 ButtonBase 覆盖虚拟方法 OnKeyUp 时完成的。其实施过程中会将 Handled 设置为 true。如果空格键未接收到自己处理程序的 already-handled 事件,则结果为某个按钮的任意父按钮侦听键事件。

另一个示例是 TextBoxTextBox 不会将某些键(如箭头键)视为文本,而是视为特定于控件 UI 的行为。TextBox 将这些事件案例标记为已处理。

自定义控件可以通过重写 OnKeyDown/ OnKeyUp 来为键事件实现自己的相似重写行为。如果你的自定义控件处理特定加速器键或者具有类似于为 TextBox 描述的方案的控件或焦点行为,则应该将该逻辑放置在自己的 OnKeyDown/OnKeyUp 重写中。

触摸键盘

文本输入控件提供对触摸键盘的自动支持。当用户将输入焦点设置为使用触摸输入的文本控件时,触摸键盘会自动出现。当输入焦点不在文本控件上时,隐藏触摸键盘。

当出现触摸键盘时,会自动重新定位你的 UI 以确保可以看见具有焦点的元素。这可能会导致 UI 的其他重要区域移出屏幕。但是,你可以禁用默认行为并在出现触摸键盘时对自己的 UI 进行调整。有关详细信息,请参阅 响应出现屏幕键盘的示例

如果创建需要文本输入,但并非从标准文本输入控件派生的自定义控件,则可以通过实现正确的 UI 自动化控件模式来添加触摸键盘支持。有关详细信息,请参阅 触摸键盘示例

按下触摸键盘上的键引发 KeyDownKeyUp 事件,就像在硬件键盘上按下键一样。但是,触摸键盘不会引发 Ctrl+A、Ctrl+Z、Ctrl+X、Ctrl+C 和 Ctrl+V 的输入事件,这些是输入控件中保留的文本操作。

 

原文地址:http://technet.microsoft.com/zh-cn/ie/hh868246

posted on 2012-11-23 11:48  憨熊之家  阅读(1813)  评论(0编辑  收藏  举报

导航