Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Создание эффективных приложений для Windows Джеффри Рихтер 2004 (Книга).pdf
Скачиваний:
375
Добавлен:
15.06.2014
Размер:
8.44 Mб
Скачать

чтобы никакое окно не могло его закрыть. (Поскольку меню Start не явля ется встроенным, то при его открытии Windows Explorcr сам вызывает эти функции.)

Система автоматически снимает блокировку с функции SetForegroundWindow, когда пользователь нажимает клавишу Alt или активизирует какое-либо окно. Так что при ложение не может навечно заблокировать SetForegroundWindow.

Другой аспект управления клавиатурой и локальным состоянием ввода связан с массивом синхронного состояния клавиш (synchronous key state array). Этот массив включается в переменные локального состояния ввода каждого потока. В то же время массив асинхронного состояния клавиш (asynchronous key state array) — только один, и он разделяется всеми потоками. Эти массивы отражают состояние всех клавиш на данный момент, и функция GetAsyncKeyState позволяет определить, нажата ли сейчас заданная клавиша:

SHORT GetAsyncKeyState(int nVirtKey);

Параметр nVirtKey задает код виртуальной клавиши, состояние которой нужно проверить. Старший бит результата определяет, нажата в данный момент клавиша (1) или нет (0). Я часто пользовался этой функцией, определяя при обработке сообще ния, отпустил ли пользователь основную (обычно левую) кнопку мыши. Передав зна чение VK_LBUTTON, я ждал, когда обнулится старший бит Заметьте, что GetAsyncKey State всегда возвращает 0 (не нажата), если ее вызывает другой поток, а не тот, кото рый создал окно, находящееся сейчас в фокусе ввода.

Функция GetKeyState отличается от GetAsyncKeyState тем, что возвращает состоя ние клавиатуры на момент, когда из очереди потока извлечено последнее сообщение от клавиатуры:

SHORT GetKeyState(int nVirtKey);

Эту функцию можно вызвать в любой момент; для нее невяжно, какое окно в фокусе.

Управление курсором мыши

В концепцию локального состояния ввода входит и управление состоянием курсора мыши. Поскольку мышь, как и клавиатура, должна быть доступна всем потокам, Win dows не позволяет какому-то одному потоку монопольно распоряжаться курсором мыши, изменяя его форму или ограничивая область его перемещения. Посмотрим, как система управляет этим курсором

Один из аспектов управления курсором мыши заключается в его отображении или гашении, Если поток вьзывает ShowCursor(FAI.SE), то система скрывает курсор, когда он оказывается на любом окне, созданном этим потоком, и показывает курсор вся кий раз, когда он попадает в окно, созданное другим потоком.

Другой аспект управления курсором мыши — возможность ограничить его пере мещение каким-либо прямоугольным участком. Для этого надо вызвать функцию ClipCursor:

BOOL ClipCursor(CONST RECT *ргс);

Она ограничивает перемещение курсора мыши прямоугольником, на который указывает параметр prc. И опять система разрешает потоку ограничить перемещение курсоря заданным прямоугольником. Но, когда возникает событие асинхронной ак тивизации, т. e. когда пользователь переключается в окно другого приложения, нажи мает клавиши Ctrl+Esc или же поток вызывает SetForegroundWindow, система снимает ограничения на передвижение курсора, позволяя свободно перемещать его по экрану.

И здесь мы подошли к концепции захвата, мыши (mouse capture). «Захватывая» мышь (вызовом SetCapture), окно требует, чтобы все связанные с мышью сообщения RIT отправлял в очередь виртуального ввода вызывающего потока, а из нее — устано вившему захват окну до тех пор, пока программа не вызовет ReleaseCapture.

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

Обычно приложение вызывает SetCapture, когда пользователь нажимает кнопку мыши. Но поток может вызвать эту функцию, даже если нажатия кнопки мыши не было. Если SetCapture вызывается при нажатой кнопке, захват действует для всей си стемы Как только система определяет, что все кнопки мыши отпущены, RIT переста ет направлять сообщения от мыши исключительно в очередь виртуального ввода дан ного потока. Вместо этого он передает сообщения в очередь ввода, связанную с ок ном, «поверх» которого курсор находится в данный момент. И это нормальное пове дение системы, когда захват мыши не установлен

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

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

Последняя переменная локального состояния ввода, связанная с мышью, относится к форме курсора. Всякий раз, когда поток вызывает SetCursor для изменения формы курсора, переменные локального состояния ввода соответствующим образом обнов ляются То есть переменные локального состояния ввода всегда запоминают послед нюю форму курсора, установленную потоком

Допустим, пользователь перемещает курсор мыши на окно Вашей программы, окно получает сообщение WM_SETCURSOR, и Вы вызываете SetCursor, чтобы преоб разовать курсор в «несочные часы». Вызвав SetCursor, программа начинает выполнять какую-то длительную операцию (Бесконечный цикл — лучший пример длительной операции Шутка ) Далее пользователь перемещает курсор из окна Вашей программы в окно другого приложения, и это окно может изменить форму курсора.