Опрос ввода с клавиатуры в программе


В ряде ситуаций при построении программы возникает необходимость получать информацию о том, нажимались ли клавиши клавиатуры во время выполнения данной программы или, иначе говоря, есть ли сообщения от клавиатуры, которые предполагается использовать несколько позже. В архаичной MS DOS для этих целей использовалась библиотека системных функций системно-зависимой версии языка Си, которая содержала функцию kbhit (в ориентированном на MS DOS Турбо Паскале аналогичная функция называлась keypressed).

В операционной системе OS/2 соответствующая функция (ожидания нажатия на любую клавишу клавиатуры) носила название KbdPeek и имела прототип

APIRET16 KbdPeek(KBDKEYINFO *pkbdi, HKBD hkbd),

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

В операционных системах Windows проверка нажатия, точнее в более конкретных для этой ОС терминах, проверка наличия сообщений для функции ReadConsoleInput, может проводиться функцией PeekConsoleInput, имеющей прототип

BOOL PeekConsoleInput(HANDLE hConsInput,

INPUT_RECORD* buffer, DWORD len, DWORD* actlen).

Строение обращения этой функции практически полностью совпадает со строением обращения к функции ReadConsoleInput, и возвращают эти функции практически одно и то же. Различие между ними в том, что функция чтения ReadConsoleInput извлекает (из специальной очереди) очередное сообщение, поэтому следующее по выполнению обращение к этой же функции извлеченное сообщение не найдет (может быть извлечено только следующее сообщение, когда оно появится). Функция же PeekConsoleInput хотя и копирует информацию о событии в свой буфер, но не извлекает ее из очереди. Поэтому повторное выполнение той же функции найдет и извлечет уже использованное значение сообщения. В частном случае, когда сообщения от клавиатуры на момент выполнения функции PeekConsoleInput нет, она возвращает (без ожидания и приостановки процесса выполнения программы) с помощью последнего параметра, что присутствует нулевое число сообщений ввода.

В Windows есть еще одна функция, которую можно использовать для опроса наличия сообщений, но уже без детализации, что это сообщение содержит. Это функция GetNumberOfConsoleInputEvents с прототипом

BOOL GetNumberOfConsoleInputEvents(HANDLE hConsInput, DWORD* number).

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

В операционной системе Unix нет непосредственных аналогов рассмотренных функций опроса нажатия клавиши. Аналогичную содержательную проблему такого специального получения символа из потока данных, чтобы он по-прежнему как бы оставался невостребованным и извлекаемым по следующей операции ввода, разработчики Unix решили очень оригинальным и своеобразным способом. Набор функций посимвольного ввода содержит функцию ungetc(int char, FILE *stream), которая возвращает прочитанный символ обратно в буфер ввода. Таким образом рассмотренные функции опроса ввода моделируются в Unix парой последовательных функций getc(FILE *stream) и ungetc(), между которыми или после которых можно поставить анализ введенного символа. Все же надо отметить, что описанная замена не обеспечивает полной аналогии. В частности, указанные функции относятся к произвольным потокам файловых данных, а не только к консоли.

Иногда, прежде чем опрашивать клавиатуру на предмет нажатия клавиш, нужно отбросить хранящиеся во входном буфере ненужные коды клавиш. Для этих целей служит функция очистки буфера клавиатуры. Она бывает нужна, когда программа начинает выполняться, а во внутреннем буфере, может быть, осталась какая-то символьная информация от клавиатуры, попавшая туда в конце выполнения предыдущей программы.

В операционной системе Windows такая функция имеет прототип

BOOL FlushConsoleInputBuffer(HANDLE hConsInput).

Целесообразно использовать эту функцию в начале программы работы с консолью, чтобы символы введенные до запуска программы в текстовом окне, не повлияли на ее нормальную работу.