Как и большинство интерактивных программ, задачи, выполняющиеся в X Window, активно используют для ввода информации клавиатуру компьютера. Когда пользователь нажимает или отпускает клавишу, сервер получает соответствующий сигнал, который преобразуется в событие и отправляется в очередь программы, имеющей фокус ввода (input focus).
Поясним, что такое фокус ввода. Дело в том, что клавиатура у машины одна, и она разделяется всеми выполняющимися одновременно программами. Но в каждый момент времени поступающий от устройства сигнал доступен лишь одной из них, как правило, той, которой принадлежит активное окно. В этом случае говорят, что программа и ее окно имеют фокус ввода. Последний может переходить от окна к окну и от программы к программе.
Когда окно получает фокус, соответствующей программе посылается событие FocusIn
, при потере - приходит событие FocusOut
.
Когда пользователь нажимает клавишу клавиатуры, программа получает событие KeyPress
. Сервер также может послать событие KeyRelease
, когда клавиша отпускается, но это справедливо не для всех типов компьютеров.
Оба этих события сопровождаются структурой типа TXKeyEvent
. Ее поле keycode
содержит код нажатой клавиши, а поле state
- состояние клавиш-модификаторов и кнопок мыши. Модификаторами называются такие клавиши, как Shift
, Ctrl
, Caps Lock
. Кроме этого, X предусматривает наличие дополнительных модификаторов, которые обозначаются Mod1
, …, Mod5
. Каждой нажатой клавише-модификатору и кнопке мыши соответствует флаг в поле state
.
Коды, передаваемые через поле keycode
структуры TXKeyEvent
, однозначно идентифицируют клавиши. Их конкретные значения зависят от типа машины и клавиатуры. Эти коды мы будем называть физическими. Чтобы обеспечить переносимость программ, сервер устанавливает соответствие между физическими кодами клавиш, которые могут меняться от компьютера к компьютеру, и целочисленными константами - логическими кодами (символами). Они имеют предопределенные значения, которые приведены в файле /usr/include/X11/keysymdef.h
и начинаются с префикса «XK_
». Так, букве «a» соответствует символ XK_a
, клавише <Return> (<Enter>) - символ XK_Return
и т.д.
Для разных алфавитов X поддерживает разные множества логических кодов. Возможные типы алфавитов перечисляются в файле /usr/include/X11/keysym.h
.
Одному коду клавиши может соответствовать несколько символов в зависимости от состояния клавиш-модификаторов. Функция
Function XKeycodeToKeysym(prDisplay : PDisplay;nKeycode : TKeyCode; nIndex : longint) : TKeySym; cdecl;external;
позволяет по коду nKeyCode
получить соответствующий ему символ с номером nIndex
. Если nIndex
равен 0, то полученный символ соответствует просто нажатой клавише. Если nIndex
равен 1, то возвращается символ, соответствующий ситуации, когда клавиша нажата одновременно с Shift
.
Функция XKeysymToKeycode()
осуществляет обратное преобразование.
Программа может получить карту соответствия кодов и символов, обратившись к процедуре XGetKeyboardMapping()
.
Изменяется соответствие физических и логических кодов процедурой XChangeKeyboardMapping()
. Следующая последовательность операторов ставит клавише <F2>
в соответствие символ XK_F3
.
........ var nF2Sym, nF3Sym : TKeysym; nF2Keycode : TKeyCode; prDisplay : PDisplay; ........ nF2Sym := XStringToKeysym ("F2"); nF3Sym := XStringToKeysym ("F3"); nF2Keycode := XKeysymToKeycode (prDisplay, nF2Sym); XChangeKeyboardMapping (prDisplay, nF2Keycode, 1, @nF3Sym, 1); ........
Здесь использована процедура XStringToKeysym()
, которая по строке «str
» возвращает соответствующий символ XK_str
.
Когда соответствие кодов меняется, всем работающим в настоящее время клиентам посылается событие MappingNotify
.
Клавиши-модификаторы также имеют логические коды. Клавишам Shift
сопоставлены символы XK_Shift_L
и XK_Shift_R
; Caps Lock
соответствует XK_CapsLock
; Control
- XK_Control_L
; Mod1
- XK_Meta_L
и XK_Meta_R
. Символы остальных модификаторов (Mod2
- Mod5
) не определены. X содержит набор специальных процедур, которые позволяют получить и установить соответствие код-символ для модификаторов. Эти функции следующие:
XGetModifierMapping(),
.
XInsertModifiermapEntry(),
XDeleteModifiermapEntry(),
XSetModifierMapping()
X не останавливается на задании соответствия код клавиши - символы, а идет дальше. Система позволяет программе сопоставить любой комбинации модификаторов и клавиш (например, <Shift+Ctrl+A>
) ASCII строку (например, «EXIT
»). Для некоторых клавиш соответствующие строки задаются сервером по умолчанию. Так, символу XK_A
соответствует строка «A
».
Макрос XRebindKeysym()
берет символ, список модификаторов и сопоставляет им строку.
Процедура XLookupString()
, наоборот, берет событие о нажатии (отпускании) клавиши и возвращает соответствующие ему символ и строку. Последний ее параметр - указатель на структуру типа XComposeStatus
. Дело в том, что некоторые клавиатуры имеют специальную клавишу Compose
, которая позволяет печатать символы, которым нет соответствия среди клавиш. Специальная таблица указывает, какой символ должен быть создан, если обычна клавиша нажимается одновременно с Compose
. Ссылка на эту информацию и возвращается в структуре XComposeStatus
.
Ниже приводится фрагмент программы, которая распознает функциональные клавиши <F1>-<F5>
, и при их нажатии печатает соответствующую строку. Программа также сопоставляет комбинации <Shift+Control+A>
строку «EXIT
». Эта комбинация используется для завершения программы.
........ var prDisplay : PDisplay; nScreenNum : integer; prGC : TGC; rEvent : TXEvent; nWnd : TWindow; sKeyStr : array [0..19] of char; nKeySym : TKeySym; naModList : array [0..1] of TKeySym; n : integer; r: char; const XK_Control_L=$FFE3; (* Left control *) XK_Shift_L=$FFE1; (* Left shift *) XK_F1=$FFBE; XK_F2=$FFBF; XK_F3=$FFC0; XK_F4=$FFC1; XK_F5=$FFC2; XK_F6=$FFC3; (* Устанавливаем связь с сервером, получаем номер экрана . . . *) ......... (* Задаем соответствие символ-строка *) naModList[0] := XK_Control_L; naModList[1] := XK_Shift_L; XRebindKeysym (prDisplay, XK_F6, naModList, 2, 'EXIT', strlen('EXIT')); (* Цикл получения и обработки событий *) while true do begin XNextEvent (prDisplay, @rEvent); case (rEvent.eventtype) of ...... KeyPress : begin (* Очищаем строку *) for n:=0 to 19 do sKeyStr[n]:=#0; (* Получаем строку, соответствующую событию *) XLookupString (@rEvent.xkey, sKeyStr, 20, @nKeySym, NIL); if ( strcomp (sKeyStr, 'EXIT')=0 ) then begin XFreeGC (prDisplay, prGC); XCloseDisplay (prDisplay); halt (0); end; case nKeySym of XK_F1: r:='1'; XK_F2: r:='2'; XK_F3: r:='3'; XK_F4: r:='4'; XK_F5: r:='5'; else r:='0'; end; if (n<>0) then begin sKeyStr[0]:='F'; sKeyStr[1]:=r; sKeyStr[2]:=#0; strcat(sKeyStr, ' pressed.'); XClearWindow (prDisplay, nWnd); XDrawString (prDisplay, nWnd, prGC, 10, 50, sKeyStr, strlen (sKeyStr)); end; end; end; end; ........
Сервер имеет ряд атрибутов, воздействующих на обработку сигналов клавиатуры. Получить их можно с помощью функции XGetKeyboardControl()
. Она возвращает указанные параметры в переменной, имеющей тип TXKeyboardState
, определенный следующим образом:
TXKeyboardState = record key_click_percent : longint; bell_percent : longint; bell_pitch : cardinal; bell_duration : cardinal; led_mask : cardinal; global_auto_repeat : longint; auto_repeats : array[0..(32)-1] of char; end; PXKeyboardState = ^TXKeyboardState;
Поле key_click_percent
указывает, имеет ли нажатие клавиши звуковое сопровождение; значения поля задаются в %; 0 - звукового сопровождения нет, 100 - громкий звук. Поле bell_percent
, bell_pitch
и bell_duration
указывают, какую силу, частоту и продолжительность имеет предупреждающий сигнал, возникающий при нажатии некоторых клавиш.
Некоторые клавиатуры используют для клавиш-модификаторов световую подсветку. Поле led_mask
представляет собой комбинацию флагов, показывающую, для каких клавиш эта подсветка используется.
Когда клавиша нажата и удерживается, то сервер может автоматически имитировать ее повторное нажатие. Поле global_auto_repeat
определяет, делает это сервер или нет. Особенностью X является то, что автоматическую генерацию событий о нажатии можно разрешать или запрещать для отдельных клавиш. Массив auto_repeats
содержит информацию о том, для каких клавиш автоповтор включен, а для каких нет. Каждый бит массива соответствует клавише с определенным физическим кодом. Если бит установлен, то генерация разрешена, если сброшен, то запрещена. Каждый байт N
массива содержит биты для клавиш с кодами от 8N
до 8N+7
.
Изменить параметры клавиатуры можно с помощью XChangeKeyboardControl()
.
Желаемые установки передаются через переменную, которая указывает на структуру типа TXKeyboardControl
, определяемую следующим образом:
TXKeyboardControl = record key_click_percent : longint; bell_percent : longint; bell_pitch : longint; bell_duration : longint; led : longint; led_mode : longint; key : longint; auto_repeat_mode : longint; end; PXKeyboardControl = ^TXKeyboardControl;
Первые четыре поля совпадают с аналогичными полями структуры TXKeyboardState
.
Поля led
и led_mode
позволяют сообщить серверу, какие из клавиш-модификаторов должны сопровождаться подсветкой. Если поле led
не задано, и led_mode
равно LedModeOn
, то изменяется состояние всех клавиш, для которых поддерживается световое сопровождение.
Если led_mode
равно LedModeOff
, то состояние клавиш не меняется. Если поле led
задано, то это есть комбинация флагов, указывающих, для каких клавиш подсветку включить (led_mode
равно LedModeOn
) или выключить (led
_mode равно LedModeOff
).
Поля key
и auto_repeat_mode
определяют, для какой клавиши (клавиш) включить (auto_repeat_mode
равно AutoRepeatModeOn
) или выключить (auto_repeat_mode
равно AutoRepeatModeOff
) режим автоматического повтора. Если поле key
задано, то автоматический повтор включается или выключается только для клавиши с кодом key
.