需要帮助在UWP中捕获全局键盘事件

时间:2018-06-08 06:06:20

标签: c# xaml uwp

编辑4:似乎只有在通过调试器运行应用程序时才会发生这种情况。所以这不是一个主要问题。

我有很多自定义键盘控件,无论控件有什么焦点,都需要触发很多。所以我在我的MainPage构造函数中使用以下代码:

public MainPage()
{
    Window.Current.CoreWindow.KeyDown += CoreWindow_KeyDown;
    Window.Current.CoreWindow.KeyUp += CoreWindow_KeyUp;
}

public void public async void CoreWindow_KeyDown(CoreWindow sender, KeyEventArgs args)
{
    // Handle here
}

但我遇到了最糟糕的问题。每当UI线程上发生事情时,它似乎严重干扰键盘输入。它好像存储了某种积压。

例如,如果我转到AutoSuggestBox,每个按键执行大量逻辑操作,并使用从服务器等加载的图形填充结果,并输入' abcd'它经常是' d'没有注册。然后,当我输入' e'几秒钟后,' d'将会通过,但不是'。它与硬件无关,只能在我正在使用的UWP应用中执行此操作。

在调试器中,我已经确认在事件被触发之前发生了这种不必要的行为。 args.VirtualKey正在解雇一个' d'当我输入' e'

此外,keyup事件仅在95%的时间内触发。 CoreWindow.PointerWheelChanged没有出现此问题。使用与键盘相同的处理程序的游戏手柄输入也没有这个问题。

UI线程上的活动越多似乎会增加问题的严重性。

有谁知道如何解决这种情况?任何形式的解决方案或替代解决方案,或至少解释可能发生的事情?

编辑: 我尝试为Window.Current.CoreWindow.Dispatcher.ProcessEvents()设置所有4个选项,没有任何改进。

编辑2: 似乎我在全球事件中捕获CoreWindow.Keydown这一事实并非如此。任何聚焦控件上的任何常规KeyDown事件也会发生此问题。

编辑3: 我相信我意识到发生了什么,我认为这是一个错误。我粗略的理解是,UWP键盘输入是沙箱,以防止键盘记录器恶意软件或其他东西,因此在原始键输入和CoreWindow处理的VirtualKey之间有一些较低级别的转换。这很好,但似乎在某些条件下它不能正常工作。

当在快速键盘输入(如输入)期间UI线程上有负载时,它有时不会检测到密钥释放。这就是为什么KeyUp不会像我提到的那样偶尔发射。这也搞砸了KeyDown,因为键处于锁定状态,它认为键被按下,而实际上键不是。然后,当下一个密钥释放注册时,CoreWindow调度程序刷新其队列,结果是它触发前一个键输入和新键输入的事件。所以输入' abcd'并且没有开火。等待10秒钟,然后按“'”。突然间,两个人都在'并且' e'会出现。或者更喜欢按下' d'再次,因为它没有第一次注册,并且双倍'会显示。任何标准都绝对是不可接受的行为。

您可以尝试自己重现它的最佳方法是使用AutoSuggestBox来阻止查询,并在键入时在结果中加载图像缩略图。请记住,即使一小部分UI负载似乎也会导致它。即使我异步地将图像预加载为流或字节数组,当设置BitmapImage源时,它仍然会阻塞UI线程1-2ms。比视频帧少1-2毫秒,因此在视觉上难以察觉,但似乎有时候不会检测到键盘键何时被释放。

这可能是硬件特定的。我测试了不同的键盘但没有测试不同的计算机。

2 个答案:

答案 0 :(得分:1)

你可以试试这个:

callback.onResult(it.items, params.key + 1)

您可以将键码用于其他键盘字符。

答案 1 :(得分:0)

快速键盘输入期间UI线程上的活动可防止CoreWindow检测到密钥发布,至少在某些硬件上,目标是1803 Spring Creators Update。希望有人知道更好的解决方案,但现在这是一个 部分 解决方案解决方案:

public void CoreWindow_KeyDown(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.KeyEventArgs args)
{
    CoreVirtualKeyStates keyState = sender.GetAsyncKeyState(args.VirtualKey);
    if ((int)keyState == 3)
    {
        // KeyState is locked and pressed.
        // Whenever this happens it means the event fired when I actaually pressed this key.
        // Handle event.
    }
    else if ((int)keyState == 2)
    {
        // KeyState is locked but not pressed. How if it's not caps lock?
        // When this happens it's an unwanted duplicate of the last keystroke.
        // Do not handle event.
    }
    else if ((int)keyState == 0)
    {
        // Key state is None?!? How can a key that isn't currently down fire a KeyDown event?
        // This is a phantom delayed rection of a missed event from two keystrokes ago.
        // Do not handle event.
    }
}

这可以防止延迟反应问题,但结果仍然会丢失按键。不理想但是有了很大的改进。

这是枚举: https://docs.microsoft.com/en-us/uwp/api/windows.ui.core.corevirtualkeystates

奇怪的状态3(“按下|锁定”)始终代表正确的键输入不在文档中。

另请注意,'CoreVirtualKeyStates == 0'表明这是一个错误,至少在我的硬件上。具有“无”状态的键如何触发KeyDown事件?没有人的手指那么快。我认为这是CoreWindow调度程序刷新其队列,因为它错过了一个KeyUp事件。