Какой самый быстрый способ определить нажатие клавиши и удержание клавиши в Win32? - PullRequest
11 голосов
/ 27 декабря 2011

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

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

Ответы [ 4 ]

21 голосов
/ 27 декабря 2011

GetAsyncKeyState () - это то, что вы ищете. Он читает физическое состояние клавиатуры независимо от состояния очереди ввода. Если старший бит установлен, то во время вызова клавиша была неактивной.

// Fetch tab key state.
SHORT tabKeyState = GetAsyncKeyState( VK_TAB );

// Test high bit - if set, key was down when GetAsyncKeyState was called.
if( ( 1 << 15 ) & tabKeyState )
{
    // TAB key down... 
}

Кроме того, для справки, Windows не является операционной системой реального времени. Если ваше приложение требует точности в реальном времени, вы можете выбрать другую платформу.

6 голосов
/ 27 декабря 2011

Если вы просто хотите опросить состояние клавиатуры, чтобы определить, какие клавиши находятся вверх / вниз, а также состояние shift / alt / ctrl просто позвоните GetKeyboardState ( MSDN reference ).

Когда я работал в игровой студии, именно так мы получали состояние клавиатуры для каждого кадра.Должно быть применимо к вашему коду симуляции.

3 голосов
/ 19 мая 2015

TL; DR: вы можете использовать GetAsyncKeyState для проверки, не нажата ли клавиша в настоящее время , но для лучшего реагирования приложения на нажатия и отпускание клавиш вы хотите использовать код конвейера Win32 рядом сВнизу моего поста.

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

Это было то, что я пытался:

static const unsigned int NumberOfKeys = 256U;

bool previousKeyboardState[NumberOfKeys];

//Get the current state of each key as the application starts to ensure that keys held down beforehand are not processed as pressed keys.
for (unsigned int keyNum = 0U; keyNum < NumberOfKeys; ++keyNum)
{
    previousKeyboardState[keyNum] = isKeyDown(keyNum);
}

//Works fine.
bool isKeyDown(int key)
{
    return (GetAsyncKeyState(key) & (1 << 16));
}

//Misses key presses when application is bogged down.
bool isKeyFirstPressed(int key)
{
    bool previousState = previousKeyboardState[key];

    previousKeyboardState[key] = isKeyDown(key);

    return (previousKeyboardState[key] && !previousState);
}

//Misses key releases when application is bogged down.
bool isKeyFirstReleased(int key)
{
    bool previousState = previousKeyboardState[key];

    previousKeyboardState[key] = isKeyDown(key);

    return (!previousKeyboardState[key] && previousState);
}


//Example usage:

if (isKeyDown(VK_W))
{
    //W key.
}

if (isKeyFirstReleased(VK_SNAPSHOT))
{
    //Print screen.
}

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

Теперь мой код выше работает прилично хорошо и может подойти многим, но я предпочитаю не пропускать ни одного нажатия клавиши.Я ненавижу , используя приложения, которые не отвечают.Я думаю, что лучшее решение для приложений Win32 - перехватывать в конвейере сообщения WM_KEYDOWN и WM_KEYUP и обрабатывать их.Что приятно, так это то, что WM_KEYDOWN также предоставляет счетчик автоповтора, который может быть полезен для приложений, которые поддерживают ввод текста (например, чат, IDE и т. Д.).Это также добавляет небольшую сложность, о которой упоминается в документации WM_KEYDOWN:

Из-за функции автоповтора может быть отправлено более одного сообщения WM_KEYDOWN до публикации сообщения WM_KEYUP.Предыдущее состояние ключа (бит 30) можно использовать для определения того, указывает ли сообщение WM_KEYDOWN первый нисходящий или повторный нисходящий переход.

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

2 голосов
/ 27 декабря 2011

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

DirectX по-прежнему использует сообщения от клавиатуры Windows, чтобы облегчить программистам DirectX доступ к событиям клавиатуры.

Обновлено

Myзаметка о DirectX заключалась не в том, чтобы использовать его, а в том, что когда Microsoft захотела создать интерфейс для программистов для игр в реальном времени, они по-прежнему писали DirectX поверх очереди сообщений Windows.

Я бы предложил взятьПосмотрите, как написать программу, которая может читать непосредственно из очереди сообщений.Я считаю, что есть хороший пример Код проекта Windows Обработка сообщений - Часть 1 .

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

...