Ввод данных с клавиатуры

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

Драйвер клавиатуры интерпретирует скан-код клавиши и преобразует в код виртуальной клавиши. Код виртуальной клавиши не зависит от прибора и определяется ОС, которая идентифицирует назначение клавиши. После перевода скан-кода, ПО клавиатуры создает сообщение, которое включает в себя скан-код, код виртуальной клавиши и другую информацию о нажатии клавиши и посылает это сообщение в системную очередь сообщений. ОС выбирает из системной очереди сообщение и помещает его в очередь сообщений соответствующего потока. В конечном счете, цикл обработки сообщений потока выбирает из очереди сообщение и передает его для обработки соответствующей оконной процедуре для обработки (рисунок 2).

Рисунок 2 - Модель ввода данных с клавиатуры

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

Поток может вызвать функцию GetFocus для определения, какое из окон в текущий момент времени имеет фокус ввода. Поток может поместить фокус ввода на одно из своих окон с помощью функции SetFocus. При изменении положения фокуса ввода, ОС посылает сообщение WM_KILLFOCUS тому окну, которое потеряло фокус ввода, а затем посылает сообщение WM_SETFOCUS тому окну, на которое перешел фокус ввода.

Концепция фокуса ввода связана с понятием активное окно. Активное окно - окно верхнего уровня, с которым работает пользователь. Окно, обладающее фокусом ввода является либо активным окном, либо порожденным окном активного окна. Чтобы пользователь мог определить, какое окно является активным, ОС выделяет заголовок окна (если он есть) или перемещает его на передний план.

Поток может выбрать активное окно с помощью функции SetActiveWindow. Для определения того, какое окно является активным - поток может использовать функцию GetActiveWindow. Обе эти функции в качестве входного (SetActiveWindow) и выходного (GetActiveWindow) параметра используют дескриптор окна.

Для блокировки ввода от клавиатуры и мыши используется функция BlockInput. В качестве входного параметра задается логическое значение, определяющее заблокировать ввод (если входной параметр имеет значение ИСТИНА) или разблокировать ввод (если входной параметр имеет значение ЛОЖЬ). Необходимо отметить, что разблокировать заблокированный ввод может успешно только тот поток, который и заблокировал ввод.

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

Когда пользователь нажимает на клавиши, оконная процедура окна, имеющего фокус ввода получает сообщения о нажатии клавиши. Сообщений о нажатии клавиш всего 4: WM_KEYDOWN (клавиша нажата), WM_KEYUP (клавиша отпущена), WM_SYSKEYDOWN (нажата системная клавиша) и WM_SYSKEYUP (системная клавиша отпущена). Обычно, оконная процедура игнорирует все сообщения о нажатии клавиши за исключением сообщения WM_KEYDOWN.

Когда оконная процедура получает сообщение WM_KEYDOWN, она должна обработать нажатие клавиши в соответствии со значением кода виртуальной клавиши. Код виртуальной клавиши находится в параметре wParam сообщения WM_KEYDOWN. Обычно, приложения обрабатывает только нажатия клавиш, сгенерированные несимвольными клавишами (т.е. функциональными клавишами, клавишами управления курсора и т.п.). В параметре lParam сообщения WM_KEYDOWN содержит дополнительную информацию (например, счетчик повторений, если пользователь нажал и удерживает клавишу). Любой поток, который получает символьный ввод от пользователя, должен включать функцию TranslateMessage в цикл обработки сообщений. Эта функция проверяет код виртуальной клавиши сообщения о нажатии клавиши и, если код соответствует какому-либо символу, помещает сообщение с символом в очередь сообщений. Сообщение с символом обрабатывается и удаляется в следующей итерации цикла обработки сообщений, параметр wParam этого сообщения содержит код символа.

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

Как уже говорилось выше, оконная процедура получает сообщение с символом после того, как функция TranslateMessage преобразует код виртуальной клавиши в код символа. Существует 4 типа сообщений с символами: WM_CHAR, WM_DEADCHAR, WM_SYSCHAR и WM_SYSDEADCHAR.

Типичная оконная процедура игнорирует все сообщения с символами за исключением сообщения WM_CHAR. Это сообщение формируется функцией TranslateMessage когда пользователь нажимает одну и следующих клавиш:

· Любую символьную клавишу

· BACKSPACE

· ENTER

· ESC

· SHIFT+ENTER

· TAB

Когда оконная процедура получает сообщение WM_CHAR, она должна проверить код символа и в зависимости от его значения определить, как обработать символ. Код символа передается в параметре wParam.

Пример использования функции TranslateMessage можно обнаружить в приложении А.

1.2.4.1.2 Ввод данных с помощью "мыши"

Хотя "мышь" и является важным, она все же является необязательным устройством ввода для приложений. Хорошо написанное приложение должно использовать интерфейс "мыши", но оно не должно зависеть исключительно от "мыши" для получения пользовательского ввода. Приложение также должно обеспечивать полноценную поддержку использования клавиатуры для ввода.

Приложение получает данные от "мыши" в форме сообщений, посылаемых окну.

Когда пользователь двигает "мышью", ОС перемещает растровую картинку на экране, называемую курсором "мыши". Курсор "мыши" содержит точку размером в 1 пиксель, называемую hot-spot (дословно, "горячая точка") - именно по координатам этой точки ОС определяет координату курсора. Когда происходит событие с манипулятором типа "мышь" (мышь двигается, нажимается клавиша мыши и т.п.) окну, которое содержит курсор мыши (точнее, горячую точку курсора мыши) посылается сообщение. Для получения сообщения от "мыши" окну не обязательно быть активным или иметь фокус ввода. Система обычно посылает сообщение от "мыши" тому окну, которое содержало горячую точку курсора во время свершения события. Приложение может изменить такой порядок вещей с помощью функции SetCapture. То есть функция SetCapture осуществляет захват ввода с помощью "мыши". В качестве входного параметра функция SetCapture получает дескриптор окна, созданного текущим потоком, которому будут пересылаться все сообщения от "мыши". В качестве выходного параметра функции SetCapture выступает дескриптор того окна, который захватывал ввод "мыши" непосредственно до настоящего момента.

Окно получает все сообщения мыши до тех пор, пока приложение не вызовет функцию ReleaseCapture (вызывается без входных параметров, в качестве выходного параметра выдает ненулевое значение в случае, если функция выполнилась успешно и 0 - в противном случае) или не определит для захвата другое окно. Необходимо отметить, что захват ввода "мыши" может осуществить лишь окно (или часть окна), находящееся на переднем плане.

Захват ввода "мыши" может быть полезен, если окно должно получить все сообщения от мыши, даже когда курсор перемещается за пределы окна. Например, приложения обычно отслеживают позицию курсора после того, как нажимается клавиша мыши и следят за курсором до тех пор, пока пользователь не отпустит клавишу "мыши". Если приложение не захватывает ввод "мыши" и пользователь отпускает клавишу "мыши" за пределами окна, окно не получит сообщения об отпускании клавиши "мыши".

Поток может использовать функцию GetCapture для определения того, какое из его окон захватило "мышь". Функция GetCapture вызывается без входных параметров, а в качестве выходного параметра выдает дескриптор окна, захватившего ввод "мыши" (если в результате выполнения функции формируется нулевое значение - значит, окна текущего потока не осуществляли захват ввода "мыши").

Хотя "мышь" является важным устройством ввода, а для некоторых пользователей - основным устройством ввода, не все пользователи обязательно имеют "мышь". Приложение может определить наличие "мыши" в системе с помощью значения параметра SM_MOUSEPRESENT функции GetSystemMetrics. Функция GetSystemMetrics позволяет определить установки конфигурации системы. Сообщения и поименованные константы [4,5] имеют в своем составе буквы L, M и К для связи с соответствующими клавишами "мыши". Символ L свидетельствует о связи с левой клавишей мыши, R - правой, M - средней клавишей "мыши". Хотя Windows поддерживает и "мыши" с большим числом клавиш, большинство приложений используют в основном левую клавишу "мыши", а остальные - в меньшей степени (если вообще используют).

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

Приложение может определить количество кнопок на "мышке" с помощью значения параметра SM_CMOUSEBUTTONS функции GetSystemMetrics. Переназначать клавиши "мыши" можно с помощью функций SwapMouseButton в качестве входного параметра задается логическое значение: TRUE - левая и правая клавиши мыши меняются местами, FALSE - восстанавливается нормальное функционирование "мыши") или SystemParametersInfo (с помощь значения параметра SPI_SETMOUSEBUTTONSWAP - тип параметра логический, значения - аналогично что и у SwapMouseButton). Необходимо отметить, что поскольку "мышь" является разделяемым ресурсом - все изменения назначения клавиш "мыши" будут влиять на все приложения.

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

Сообщения "мыши" делятся на 2 группы: сообщения от клиентской области и сообщения от неклиентской области. Обычно, приложение обрабатывает сообщения клиентской области и игнорирует сообщения неклиентской области.

Окно получает сообщения клиентской области когда события "мыши" происходят внутри клиентской области окна (или рабочая область окна - все пространство окна, за исключением границ окна, полос прокрутки, меню, панелей инструментов и т.п.). ОС посылает сообщение WM_MOUSEMOVEокну всякий раз, когда пользователь двигает мышь внутри клиентской области. ОС посылает одно из сообщение (таблица 10) всякий раз, когда пользователь нажимает или отпускает клавиши "мыши" внутри клиентской области.

 

Таблица 10 - Сообщения "мыши"

Сообщение Значение Код сообщения (16 с/с)
WM_LBUTTONDBLCLK Левая клавиша дважды нажата 0х0203
WM_LBUTTONDOWN Нажата левая клавиша 0х0201
WM_LBUTTONUP Левая клавиша отпущена 0х0202
WM_MBUTTONDBLCLK Средняя клавиша дважды нажата 0х0209
WM_MBUTTONDOWN Средняя клавиша нажата 0х0207
WM_MBUTTONUP Средняя клавиша отпущена 0х0208
WM_RBUTTONDBLCLK Правая клавиша дважды нажата 0х0206
WM_RBUTTONDOWN Правая клавиша нажата 0х0204
WM_RBUTTONUP Правая клавиша отпущена 0х0205

 

Каждое из перечисленных сообщений имеет 2 параметра. Параметр lParam сообщения клиентской области определяет координаты курсора "мыши": младшее слово определяет кординату по X (горизонтальную координату), старше слово - координату по Y (вертикальную координату). Эти координат отсчитываются относительно клиентской области - левый верхний угол имеет координату (0,0). Параметр wParam содержит признаки, которые определяют статус других клавиш мыши и клавиш CTRL и SHIFT во время свершения события "мыши". В таблице приведены значения параметра wParam.

Таблица 11 - Значения параметра wParam сообщения "мыши"

Имя параметра Значение Код параметра
MK_CONTROL Клавиша CTRL нажата 0х0008
MK_LBUTTON Левая клавиша "мыши" нажата 0х0001
MK_MBUTTON Средняя клавиша "мыши" нажата 0х0010
MK_RBUTTON Правая клавиша "мыши" нажата 0х0002
MK_SHIFT Клавиша SHIFT нажата 0х0004

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

ОС формирует сообщения неклиентской области, в основном для своих собственных нужд. Например, ОС использует сообщение неклиенсткой области, когда курсор указывает на границу окна для изменения его внешнего вида (обычно курсор в этот момент представляется двунаправленной стрелкой). Для того чтобы использовать сообщения "мыши" неклиентской области окна, оконная процедура должна обработать эти сообщения в процедуре DefWindowProc.

Для каждого сообщения "мыши" клиентской области есть и соответствующее сообщения для неклиентской области. Имена этих сообщений такие же, за исключением того, что для сообщений неклиентской области в имена вводятся символы NC (например, WM_NCLBUTTONDBLCLK - двойное нажатие левой клавиши мыши). Параметр lParam сообщений неклиентской области содержит координаты курсора относительно левого-верхнего угла экрана (а не клиентской части окна, как у сообщений клиентской области). Параметр wParam содержит значение, которое показывает, в какой части неклиентской области произошло событие.

Таблица 12 - Некоторые значение параметра wParam сообщения "мыши" неклиентской области