Нужна помощь в захвате глобальных событий клавиатуры в UWP - PullRequest
0 голосов
/ 08 июня 2018

РЕДАКТИРОВАТЬ 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
}

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

Например, если я иду на AutoSuggestBox, который выполняет много логики при каждом нажатии клавиши и заполняет результаты графикой, загруженной с сервера и тому подобное, и я набираю 'abcd'довольно часто' d 'не регистрируется.Затем, когда я наберу 'e' через несколько секунд, будет проходить 'd', но не 'e'.Это не связано с аппаратным обеспечением, оно выполняется только в моем приложении UWP, над которым я работаю.

В отладчике я подтвердил, что все это нежелательное поведение происходит до того, как событие будет запущено.args.VirtualKey запускает 'd', когда я набираю 'e'.

Кроме того, события keyup запускаются только в 95% случаев.CoreWindow.PointerWheelChanged не имеет этой проблемы.У ввода с геймпада, использующего тот же обработчик, что и у клавиатуры, этой проблемы также нет.

Чем больше активность в потоке пользовательского интерфейса увеличивает серьезность проблемы.

Кто-нибудь знает, как исправить ситуацию?эта ситуация?Любое решение или альтернативное решение, или хотя бы объяснение того, что может происходить?

РЕДАКТИРОВАТЬ: я попытался установить все 4 варианта для Window.Current.CoreWindow.Dispatcher.ProcessEvents (), без улучшений.

РЕДАКТИРОВАТЬ 2: Кажется, тот факт, что я захватил CoreWindow.Keydown для глобальных событий, не является следствием.Проблема также возникает с любым обычным событием KeyDown на любом сфокусированном элементе управления.

РЕДАКТИРОВАТЬ 3: Я считаю, что я понимаю, что происходит, и я думаю, что это ошибка.Мое беглое понимание состоит в том, что ввод с клавиатуры UWP находится в «песочнице», чтобы предотвратить проникновение вредоносных программ и других вредоносных программ, поэтому существует некоторый низкоуровневый перевод между вводом необработанных клавиш и VirtualKey, который обрабатывает CoreWindow.Это нормально, но кажется, что при определенных условиях это работает неправильно.

Когда во время быстрого ввода с клавиатуры (например, при наборе текста) загружается поток пользовательского интерфейса, он иногда не обнаруживает нажатия клавиш.Вот почему KeyUp не срабатывает время от времени, как я уже упоминал.Это также портит KeyDown, потому что ключи находятся в состоянии блокировки, он думает, что ключ удерживается, когда в действительности это не так.Затем, когда регистрируется следующий выпуск ключа, диспетчер CoreWindow сбрасывает свою очередь, и в результате он генерирует событие как для предыдущего ввода ключа, так и для нового.Так что наберите «abcd» и «d не сработает».Подождите 10 секунд, а затем нажмите «е».Внезапно появятся и «д», и «е».Или, более того, снова нажмите «d», потому что он не был зарегистрирован в первый раз, и отобразится двойной «dd».Абсолютно недопустимое поведение по любому стандарту.

Лучший способ попытаться воспроизвести его самостоятельно - это использовать AutoSuggestBox, который выполняет блокировку, например запросы, и загружать миниатюры изображений в результаты при вводе.И имейте в виду, что даже небольшая загрузка пользовательского интерфейса, кажется, вызывает этоДаже если я асинхронно предварительно загружаю изображение в виде потока или байтового массива, он все равно блокирует поток пользовательского интерфейса на 1-2 мс, когда установлен источник BitmapImage.На 1-2 мс меньше, чем кадр видео, и, следовательно, визуально незаметно, но иногда кажется, что иногда не удается обнаружить, когда отпущена клавиша на клавиатуре.

Это может быть что-то аппаратное.Я тестировал разные клавиатуры, но не другой компьютер.

Ответы [ 2 ]

0 голосов
/ 16 июня 2018

Активность в потоке пользовательского интерфейса при быстром вводе с клавиатуры не позволяет 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.

0 голосов
/ 08 июня 2018

Вы можете попробовать это:

public MainPage()
{
    InitializeComponent();
    Window.Current.CoreWindow.CharacterReceived += CoreWindow_CharacterReceived;
}

private async void CoreWindow_CharacterReceived(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.CharacterReceivedEventArgs args)
{
    if (args.KeyCode == 27 ) //Escape
    {
         // your code here fore Escape key
    }
    if (args.KeyCode == 13) //Enter
    {
         // your code here fore Enter key
    }
}

Вы можете использовать коды клавиш для других символов клавиатуры.

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