При разработке программ текстового режима часто требуется информация о состоянии управляющих клавиш, о факте опускания и подъема клавиши и т.д. Получить сведения об этих событиях клавиатуры возможно посредством описанной выше функции низкого уровня ReadConsolelnput.
Процесс обработки аналогичен обработке событий мыши, однако при этом переменная, в которую записывается информация о событии клавиатуры, имеет иную структуру. Эта структура может быть описана следующим образом:
INPUT_REC struct
EventType dw 0
dw 0
bKeyDown dd 0
wRepeatCount dw 0
wVirtualKeyCode dw 0
wVirtualScanCode dw 0
AsciiChar db 0
db 0
dwControlKeyState dd 0
INPUT_REC EndS
Поля этой структуры имеют следующее значение:
EventType - слово (16 разрядов), которое содержит тип события. При вызове функции ReadConsoleInput для событий, связанных с использованием клавиатуры, значение этого элемента структуры будет равно 1 (это значение присвоено константе KEY_EVENT в подключаемом файле WINDOWS.INC).
далее в структуре следует неиспользуемое слово - dw 0
bKeyDown - двойное слово. Если младший байт этого поля равен 1, то произошло опускание клавиши, а если 0 – подъем клавиши;
wRepeatCount – слово (16 бит) - содержит количество повторов при удержании клавиши в нажатом состоянии (то есть одно опускание клавиши без подъема рассматривается как несколько последовательных нажатий); если клавиша нажата и удерживается, то во входном буфере консоли появляется несколько идентичных записей, на экране появляется несколько символов, соответствующих этой клавише.
wVirtualKeyCode - слово (16 бит) - содержит виртуальный код клавиши, который идентифицирует данную клавишу не зависящим от устройства способом;
wVirtualScanCode - слово (16 бит) - содержит виртуальный скан-код данной клавиши, который представляет собой аппаратно-зависимое значение, сгенерированное аппаратными средствами клавиатуры;
AsciiChar — байт, который содержит 8-разрядный код символа, соответствующий нажатой клавише;
далее в структуре следует неиспользуемый байт - db 0
dwControlKeyState - поле описывает состояние управляющих клавиш клавиатуры в момент наступления события клавиатуры (принимаемые этим полем значения аналогичны значениям одноименного поля, используемого в структуре, описывающей событие мыши) – с помощью этого поля можно определить нажатие клавиш CTRL, ALT, SHIFT и т.д. Оценить нажатие на клавиатуре указанных клавиш возможно по младшему байту этого поля.
Как видно, в структуре для события клавиатуры присутствует сходная со структурой события мыши часть – это первые 32 бита, описываемые директивами EventType dw 0 и dw 0. Следующие части структур, описывающих события мыши и клавиатуры, существенно различаются. Поскольку в программе очень часто требуется отслеживать как события мыши, так и события клавиатуры, а также учитывая, что для получения информации о событиях мыши и клавиатуры используется одна и та же функция ReadConsoleInput, то логично было бы помещать результат работы этой функции (то есть структурированную запись о событии) в некоторую переменную (область оперативной памяти), которая могла бы совмещать эти две структуры. Для этого при описании такой совмещенной структуры необходимо использовать объединение.
Объединение – это тип данных, позволяющий трактовать одну и ту же область оперативной памяти как данные, имеющие разные типы и имена. Описание объединения выглядит следующим образом:
имя_объединения UNION
<описание_полей>
имя_объединения ENDS
Отличие объединений от структур состоит в том, что при определении переменной типа объединения память выделяется в соответствии с размером максимального элемента. При использовании объединений внутри структуры имя объединения можно опустить.
Для нашего случая, когда необходимо описать структуру для совмещенного события клавиатуры и мыши, мы сначала опишем две структуры, содержащие специфические поля, соответствующие событиям клавиатуры и мыши. А затем уже объединим эти структуры в общей структуре, добавив к ним общую часть (первые 32 бита и директивы их описания).
Структура, описывающая специфические поля события мыши будет иметь следующий вид:
MOUSE_EVENT_REC STRUCT
dwMousePosition coord<>
dwButtonState dd 0
dwControlKeyState dd 0
dwEventFlags dd 0
MOUSE_EVENT_REC EndS
Структура, описывающая специфические поля события клавиатуры будет иметь следующий вид:
KEY_EVENT_REC STRUCT
bKeyDown dd 0
wRepeatCount dw 0
wVirtualKeyCode dw 0
wVirtualScanCode dw 0
AsciiChar db 0
db 0
dwControlKeyState dd 0
KEY_EVENT_REC ENDS
Общая структура для событий мыши и клавиатуры будет получена в результате объединения структур MOUSE_EVENT_REC и KEY_EVENT_REC и добавления перед ними директив EventType dw 0 и dw 0. В результате получим общую структуру, описывающую запись, получаемую из входного буфера консоли с помощью функции ReadConsoleInput. Эта структура будет иметь следующий вид:
INPUT_REC struct
EventType dw 0
dw 0
UNION
KeyEvent KEY_EVENT_REC <>
MouseEvent MOUSE_EVENT_REC <>
ENDS
INPUT_REC EndS
В случае объявления переменной с указанной структурой (например, с использованием директивы INPUT_RECORD_buf INPUT_REC <>), обращение к полю EventType будет выглядеть обычно, то есть:
INPUT_RECORD_buf. EventType
А обращение к специфическим полям, относящимся только к событиям мыши или только к событиям клавиатуры, будет происходить путем написания трехуровневой конструкции, например:
INPUT_RECORD_buf. MouseEvent. dwEventFlags
INPUT_RECORD_buf. KeyEvent. AsciiChar
При этом как поля, относящиеся к событию мыши, так и поля, относящиеся к событию клавиатуры, будут ссылаться на одну и туже область памяти.