Каков самый быстрый способ определить нажатие клавиши и удержание клавиши в Win32?

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

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

4 ответов


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 не является операционной системой реального времени. Если ваше приложение требует точности в реальном времени, вы можете выбрать другую платформу.


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

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


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

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

Обновлено

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

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

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


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

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

вот что я попробовал:

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 не годится, так как он не отслеживает количество нажатий клавиш или релизы. Как сказал Эрик Филипс в своем ответе, это unbuffered решения, которые не годятся, если вы, например, пишете игру. Вам придется обрабатывать все нажатия клавиш быстрее, чем они полученный.

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

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

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