屏幕阅读器和硬件系统按钮
屏幕阅读器(例如讲述人)必须能够识别和处理硬件系统按钮事件并将其状态传达给用户。 在某些情况下,屏幕阅读器可能需要专门处理这些硬件按钮事件,而不是让它们冒泡到其他处理程序。
从 Windows 10 版本 2004 开始,UWP 应用程序可以像其他硬件按钮一样侦听和处理 Fn 硬件系统按钮事件。 以前,此系统按钮仅充当其他硬件按钮报告其事件和状态的修饰符。
注意
Fn 按钮支持特定于 OEM,可以包括功能(与按下和按住键组合)以及相应的锁指示器灯(这对失明或有视力障碍的用户没有帮助)。
Fn 按钮事件通过 Windows.UI.Input 命名空间中的新 SystemButtonEventController 类公开。 SystemButtonEventController 对象支持以下事件:
- SystemFunctionButtonPressed
- SystemFunctionButtonReleased
- SystemFunctionLockChanged
- SystemFunctionLockIndicatorChanged
重要
如果这些事件已由更高优先级的处理程序处理,则 SystemButtonEventController 无法接收这些事件。
示例
在下面的示例中,我们展示了如何基于 DispatcherQueue 创建一个 SystemButtonEventController 并处理该对象支持的四个事件。
当按下 Fn 按钮时,通常要启动多个受支持的事件。 例如,按下 Surface 键盘上的 Fn 按钮会同时触发 SystemFunctionButtonPressed、SystemFunctionLockChanged 和 SystemFunctionLockIndicatorChanged。
在第一个片段中,我们简单地包含所需的命名空间并指定一些全局对象,包括用于管理 SystemButtonEventController 线程的 DispatcherQueue 和 DispatcherQueueController 对象。
然后,我们指定注册 SystemButtonEventController 事件处理委托时返回的事件令牌。
namespace winrt { using namespace Windows::System; using namespace Windows::UI::Input; } ... // Declare related members winrt::DispatcherQueueController _queueController; winrt::DispatcherQueue _queue; winrt::SystemButtonEventController _controller; winrt::event_token _fnKeyDownToken; winrt::event_token _fnKeyUpToken; winrt::event_token _fnLockToken;
我们还为 SystemFunctionLockIndicatorChanged 事件指定了一个事件标记以及一个布尔值,以指示应用程序是否处于“学习模式”(用户只是试图探索键盘而不执行任何功能)。
winrt::event_token _fnLockIndicatorToken; bool _isLearningMode = false;
第三个片段包括 SystemButtonEventController 对象支持的每个事件的相应事件处理程序委托。
每个事件处理程序都会宣布已发生的事件。 此外,FunctionLockIndicatorChanged 处理程序还控制应用是否处于“学习”模式 (
_isLearningMode
=true),这可以防止事件冒泡到其他处理程序,并让用户在不实际执行操作的情况下探索键盘功能。void SetupSystemButtonEventController() { // Create dispatcher queue controller and dispatcher queue _queueController = winrt::DispatcherQueueController::CreateOnDedicatedThread(); _queue = _queueController.DispatcherQueue(); // Create controller based on new created dispatcher queue _controller = winrt::SystemButtonEventController::CreateForDispatcherQueue(_queue); // Add Event Handler for each different event _fnKeyDownToken = _controller->FunctionButtonPressed( [](const winrt::SystemButtonEventController& /*sender*/, const winrt:: FunctionButtonEventArgs& args) { // Mock function to read the sentence "Fn button is pressed" PronounceFunctionButtonPressedMock(); // Set Handled as true means this event is consumed by this controller // no more targets will receive this event args.Handled(true); }); _fnKeyUpToken = _controller->FunctionButtonReleased( [](const winrt::SystemButtonEventController& /*sender*/, const winrt:: FunctionButtonEventArgs& args) { // Mock function to read the sentence "Fn button is up" PronounceFunctionButtonReleasedMock(); // Set Handled as true means this event is consumed by this controller // no more targets will receive this event args.Handled(true); }); _fnLockToken = _controller->FunctionLockChanged( [](const winrt::SystemButtonEventController& /*sender*/, const winrt:: FunctionLockChangedEventArgs& args) { // Mock function to read the sentence "Fn shift is locked/unlocked" PronounceFunctionLockMock(args.IsLocked()); // Set Handled as true means this event is consumed by this controller // no more targets will receive this event args.Handled(true); }); _fnLockIndicatorToken = _controller->FunctionLockIndicatorChanged( [](const winrt::SystemButtonEventController& /*sender*/, const winrt:: FunctionLockIndicatorChangedEventArgs& args) { // Mock function to read the sentence "Fn lock indicator is on/off" PronounceFunctionLockIndicatorMock(args.IsIndicatorOn()); // In learning mode, the user is exploring the keyboard. They expect the program // to announce what the key they just pressed WOULD HAVE DONE, without actually // doing it. Therefore, handle the event when in learning mode so the key is ignored // by the system. args.Handled(_isLearningMode); }); }