пользователей: 30398
предметов: 12406
вопросов: 234839
Конспект-online
РЕГИСТРАЦИЯ ЭКСКУРСИЯ


Оконные сообщения. Обработка сообщений. Алгоритм выборки сообщений из очереди потока. Оконные сообщения и разупорядоченный ввод. Ввод с клавиатуры и фокус ввода

Для обработки сообщений процесс в цикле вызывает функции GetMessage или PeekMessage, а также ожидает появления сообщения в очереди с помощью WaitMessage. Когда сообщений в очереди нет, система приостанавливает выполнения потока, но как только потоку будет отправлено синхронное или асинхронное сообщение система пробуждает поток с помощью флагов пробуждения(wake flags).
Во время выполнения поток может опросить состояние своих очередей вызовом GetQueueStatus:

DWORD GetQueueStatus(UINT fuFlags);

Параметр fuFlags — флаг или группа флагов, объединенных побитовой операцией OR, он позволяет проверить значения отдельных битов пробуждения (wake bits) Допустимые значения флагов и их смысл описаны в следующей таблице.

Флаг

Сообщение в очереди

QS_KEY

WM_KEYUP,WM_KEYDOWN, WM_SYSKEYUP или WM_SYSKEYDOWN

QS_MOUSEMOVE

WM_MOUSEMOVE

QS_MOUSEBUTTON

WM_?BUTTON* (где знак вопроса заменяет букву L, М или R, а звездочка — DOWN, UP или DBLCLK)

QS_MOUSE

То же, что QS_MOUSEMOVE | QS_MOUSEBUTTON

QS_INPUT

То же, что QS_MOUSE | QS_KEY

QS_PAINT

WM_PAINT

QS_TIMER

WM_TIMER

QS_HOTKEY

WM_HOTKEY

QS_POSTMESSAGE

Асинхронное сообщение (отличное от события аппаратного ввода), этот флаг идентичен QS_ALLPOSTMESSAGE с тем исключением, что сбрасывается при отсутствии асинхронных сообщений в диапазоне действия фильтра сообщений

QS_ALLPOSTMESSAGE

Асинхронное сообщение (отличное от события аппаратного ввода); этот флаг идентичен QS_POSTMESSAGE с тем исключением, что сбрасывается лишь при полном отсутствии каких-либо асинхронных сообщений (вне зависимости от фильтра сообщений)

QS ALLEVENTS

Тоже, что QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY

QS_QUIT

Сообщает о вызове PostQuitMessage, этот флаг не задокументирован, его нет в WinUser.h, и он используется самой системой

QS_SENUMESSAGE

Синхронное сообщение, посланное другим потоком

QS_ALLINPUT

То же, что QS_ALLEVENTS | QS_SENDMESSAGE

Не все флаги обрабатываются одинаково. Например:

Флаги QS_MOUSE и QS_KEY устанавливаются, если в очереди есть хотя бы одно соответствующее сообщение. Когда GetMessage или PeekMessage извлекает последнее сообщение из очереди, соответствующие флаги сбрасываются.

Флаг QS_MOUSEMOVE устанавливается, если в очереди есть необработанное сообщение WM_MOUSE.

Флаг QS_PAINT обрабатывается иначе. Если существует хотя бы один недействительный регион (требующий перерисовки), флаг не сбрасывается. Флаг сбрасывается в случае окончательной перерисовки.

Есть еще один (недокументированный) флаг состояния очереди – QS_QUIT. Он устанавливается при вызове потоком PostQuitMessage. Сообщение WM_QUIT при этом не добавляется к очереди сообщений. GetQueueStatus не возвращает состояние этого флага.

Алгоритм выборки сообщений из очереди потока:

Когда поток вызывает GetMessage или PeekMessage, система проверяет флаги состояния очередей потока и определяет, какое сообщение надо обработать:

1.Если флаг QS_SENDMESSAGE установлен, система отправляет сообщение соответствующей оконной процедуре. Функции контролируют процесс обработки и не передают управление потоку сразу после того, как оконная процедура обработает сообщение, вместо этого обе функции ждут следующего сообщения.
2.Если очередь асинхронных сообщений потока не пуста, Функции заполняют переданную им структуру MSG и возвращают управление. Цикл выборки сообщений (расположенный в потоке) в этот момент обычно обращается к DispatchMessage, чтобы соответствующая оконная процедура обработала сообщение. 
3.Если флаг QS_QUIT установлен, Функции возвращают сообщение WM_QUIT (параметр wParam которого содержит указанный код завершения) и сбрасывают этот флаг.
4.Если в очереди виртуального ввода потока есть какие-то сообщения, Функции возвращают сообщение, связанное с аппаратным вводом.
5.Если флаг QS_PAINT установлен, Функции возвращают сообщение WM_PAINT для соответствующего окна
6.Если флаг QS_TIMER установлен, Функции возвращают сообщение WM_TIMER.

До появления Win32 API в ОС использовался упорядоченный ввод (serialized input), т.е. система обрабатывала события от клавиатуры и мыши в том порядке, в каком они инициируются пользователем.

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

В Win32 API используется разупорядоченный ввод (deserialized input). В этом случае аппаратные события не обязательно обрабатываются в порядке их поступления.

Поток принимает события в том порядке, в каком пользователь их формирует, но обрабатывает на уровне потока, а не на уровне ОС. При запуске ОС создает особый поток необработанного ввода (raw input thread, RIT).

Чтобы система могла переключаться между задачами, вне зависимости от того занят ли поток в данный момент обработкой ввода, RIT особым образом реагирует на специальные комбинации клавиш (например, Alt+Ctrl+Del или Alt+Tab).

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

В результате поток RIT пробуждается и транслирует его в событие WM_*.

После этого RIT отправляет событие в виртуальную очередь ввода потока.

Прежде чем отправить событие, RIT должен определить поток в чью виртуальную очередь ввода необходимо отправить событие.

В случае сигнала от мыши RIT определяет, поверх какого окна находится курсор мыши, после чего отправляет событие потоку, создавшему это окно.

Если событие поступило от клавиатуры, RIT определяет, какое окно активно(находится в фокусе ввода) и все повторяется.

В Win32 API существует ряд функций, которые позволяют объединять и разъединять виртуальные очереди ввода.

Можно заставить два и более потока совместно использовать одну и ту же очередь виртуального ввода и переменные локального состояния ввода с помощью функции:

BOOL AttachThreadInput(DWORD idAttach,

DWORD idAttachTo, BOOL fAttach);

Параметр idAttach задаст идентификатор потока, чьи переменные локального со стояния ввода и очередь виртуального ввода больше не нужны, а параметр idAttachTo – идентификатор потока, чьи переменные локального состояния ввода и виртуальная очередь ввода должны совместно использоваться потоками

Параметр fAttach должен быть или TRUE, чтобы инициировать совместное использование одной очереди, или FALSE – тогда каждый поток будет вновь использовать свои переменные состояния ввода и очередь.

При вводе с клавиатуры RIT отправляет событие в виртуальную очередь ввода потока, безотносительно  конкретному окну. Когда поток получает событие функцией GetMessage, клавиатурное событие извлекается и связывается с окном, которое находится в фокусе.

Функция 

HWND WINAPI SetFocus(HWND hWnd);

назначает фокус ввода окну hWnd. Функция возвращает описатель окна, которое находилось в фокусе. Если фокус не был передан, функция возвращает NULL.

Изменение фокуса ввода приводит к тому, что окну теряющему фокус отправляется сообщение WM_KILLFOCUS, а окну, которое принимает фокус ввода – WM_SETFOCUS.

Данная функция не переключает виртуальные очереди ввода, поэтому если поток 1, будучи подключенным к RIT, вызовет SetFocus для окна E, то не произойдет никаких изменений. Кроме того, если поток 2 вызовет SetFocus для окна E, то при следующем подключении к RIT именно это окно будет в фокусе ввода.

В Win32 API появились две новые функции, которые управляют фокусом ввода.

BOOL WINAPI SetForegroundWindow(HWND hWnd);

Функция активизирует окно hWnd и переключает виртуальную очередь ввода на поток, который создал это окно.

HWND WINAPI GetForegroundWindow();

Функция возвращает активное окно, вне зависимости от того, какой поток его создал. 

 


28.12.2015; 00:55
хиты: 0
рейтинг:0
для добавления комментариев необходимо авторизироваться.
  Copyright © 2013-2024. All Rights Reserved. помощь