Прохождение сообщений в системе
Рассмотрим ситуацию, когда пользователь приложения нажимает клавишу, а система вырабатывает сообщение об этом событии. Вы знаете, что Windows обеспечивает поддержку клавиатуры, не зависящую от типа устройства (device-independent support). Для каждого типа клавиатуры она устанавливает соответствующий драйвер, то есть специальную программу, которая служит посредником между клавиатурой и операционной системой. Клавиатурная поддержка Windows не зависит от языка общения с системой. Это достигается использованием специальной клавиатурной раскладки (layout), которую пользователь выбрал в данный момент. Каждой клавише на уровне аппаратуры присвоено уникальное значение – идентификатор клавиши, зависящий от типа устройства и называемый скан-кодом.
Примечание
На самом деле, когда пользователь вводит символ, то клавиатура генерирует два события и два скан-кода – один, когда он нажимает клавишу, и другой, когда отпускает. Скан-коды с клавиатуры поступают в клавиатурный драйвер, который, используя текущую раскладку, транслирует их и преобразовывает в сообщения.
Клавиатурный драйвер интерпретирует скан-код и преобразует его в определяемый Windows код виртуальной клавиши (virtual-key code), не зависящий от типа устройства и идентифицирующий функциональный смысл клавиши. После этого преобразования скан-кода драйвер создает сообщение, в которое включает: скан-код, виртуальный код и другую сопутствующую информацию. Затем он помещает сообщение в специальную очередь системных сообщений.
Windows выбирает сообщение из этой очереди и посылает в очередь сообщений соответствующего потока (thread). В конце концов, цикл выборки сообщений данного потока передает его соответствующей оконной процедуре для обработки. Модель ввода с клавиатуры в системе Windows представлена на рис. 3.1.
Рис. 3.1. Путь прохождения сообщений от клавиатуры
Здесь буфер клавиатуры служит связующим звеном между прикладной программой и одним из сервисов ОС. Точно так же формируют (или могут формировать) свои специфические данные обработчики других событий. При этом используется универсальная структура данных MSG (сообщение), описывающая любое событие. Она содержит сопровождающую информацию, достаточную для того, чтобы сообщением можно было воспользоваться. Например, для сообщения от клавиатуры это должен быть код нажатой клавиши, для сообщения от мыши – координаты ее указателя, для сообщения WM_SIZE – размеры окна. Тип структур MSG определен в одном из файлов заголовков следующим образом:
//======= Ярлык типа typedef struct tagMSG { //===== Описатель окна, чья оконная процедура //===== получает сообщение HWND hwnd; UINT message; // Код сообщения // Дополнительная информация, зависящая от сообщения WPARAM wParam; LPARAM iParam; // Тоже DWORD time; // Время посылки сообщения //==== Точка экрана, где был курсор //==== в момент посылки сообщения POINT pt; } MSG; //===== Тип структур, эквивалентный ярлыку