Клавиатура используется в большинстве программ, которые пишутся пользователями и для пользователей. В X Window, когда пользователь нажимает(отпускает) клавишу, сервер получает соответствующий сигнал, который преобразуется в событие и отправляется в очередь программы, имеющей фокус ввода (input focus).
Так как клавиатура обычно у машины одна, она разделяется между всеми одновременно выполняющимися программами. Сигнал поступающий от устройства доступен лишь одной из них, обычно, той, которой принадлежит активное окно. Под этим и стоит понимать, что программа и её окно имеют фокус ввода. Последний может переходить от окна к окну и от программы к программе.
Когда окно получает фокус, соответствующей программе посылается событие FocusIn
, при потере - приходит событие FocusOut
.
Когда пользователь нажимает клавишу клавиатуры, программа получает событие KeyPress
. Сервер также может послать событие KeyRelease
, когда клавиша отпускается, но это справедливо не для всех типов компьютеров.
Оба этих события сопровождаются структурой типа XKeyEvent
. Ее поле keycode
содержит код нажатой клавиши, а поле state
- состояние клавиш-модификаторов и кнопок мыши. Модификаторами называются такие клавиши, как Shift
, Ctrl
, Caps Lock
. Кроме этого, X предусматривает наличие дополнительных модификаторов, которые обозначаются Mod1
, ..., Mod5
. Каждой нажатой клавише-модификатору и кнопке мыши соответствует флаг в поле state
.
Коды, передаваемые через поле keycode
структуры XKeyEvent
, однозначно идентифицируют клавиши. Их конкретные значения зависят от типа машины и клавиатуры. Эти коды можно назвать физическими. Чтобы обеспечить переносимость программ, сервер устанавливает соответствие между физическими кодами клавиш, которые могут меняться от компьютера к компьютеру, и целочисленными константами - логическими кодами (символами). Они имеют предопределенные значения, которые приведены в файле /usr/include/X11/keysymdef.h
и начинаются с префикса "XK_
". Так, букве "a" соответствует символ XK_a
, клавише <Return> (<Enter>) - символ XK_Return
и т.д.
Для разных алфавитов X поддерживает разные множества логических кодов. Возможные типы алфавитов перечисляются в файле /usr/include/X11/keysym.h
.
Одному коду клавиши может соответствовать несколько символов в зависимости от состояния клавиш-модификаторов. Функция
KeySym XKeycodeToKeysym (Display* display, KeyCode keycode, int index);
позволяет по коду keycode
получить соответствующий ему символ с номером index
. Если index
равен 0, то полученный символ соответствует просто нажатой клавише. Если index
равен 1, то возвращается символ,соответствующий ситуации, когда клавиша нажата одновременно с
Shift
.
Функция XKeysymToKeycode()
осуществляет обратное преобразование.
Программа может получить карту соответствия кодов и символов, обратившись к функции XGetKeyboardMapping()
.
Изменяется соответствие физических и логических кодов функцией XChangeKeyboardMapping()
. Следующая последовательность операторов ставит клавише <F2>
в соответствие символ XK_F3
.
........ Keysym F2sym, F3symbol; int nF2Keycode; Display *display; ........ F2symbol = XStringToKeysym ("F2"); F3symbol = XStringToKeysym ("F3"); nF2Keycode = XKeysymToKeycode (display, F2symbol); XChangeKeyboardMapping (display, F2keycode, 1, &F3symbol, 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
". Эта комбинация используется для завершения программы.
........ Display *display; int screenNumber; GC gc; XEvent report; Window window; char keyStr[20]; KeySym keySym, modList[2]; int n; /* Устанавливаем связь с сервером, получаем номер экрана . . . */ ......... /* Задаем соответствие символ-строка */ modList[0] = XK_Control_L; modList[1] = XK_Shift_L; XRebindKeysym (display, XK_F6, modList, 2, "EXIT", strlen ("EXIT")); /* Цикл получения и обработки событий */ while (1) { XNextEvent (display, &report); switch (report.type) { ...... case KeyPress : /* Очищаем строку */ memset (keyStr, 0, sizeof (keyStr)); /* Получаем строку, соответствующую событию */ XLookupString (&report.xkey, keyStr), sizeof (keyStr), &keySym, NULL); if ( !strcmp (keyStr, "EXIT")) { XFreeGC (display, gc); XCloseDisplay (display); exit (0); } n = keySym == XK_F1 ? 1 : keySym == XK_F2 ? 2 : keySym == XK_F3 ? 3 : keySym == XK_F4 ? 4 : keySym == XK_F5 ? 5 : 0; if (n) { sprintf (keyStr, "F%d pressed.", n); XClearWindow (display, window); XDrawString (display, window, gc, 10, 50, keyStr, strlen (keyStr)); } break; } } ........
Сервер имеет ряд атрибутов, воздействующих на обработку сигналов клавиатуры. Получить их можно с помощью функции XGetKeyboardControl()
. Она возвращает указанные параметры в переменной, имеющей тип XKeyboardState
, определенный следующим образом:
typedef struct { int key_click_percent; int bell_percent; unsigned int bell_pitch, bell_duration; unsigned long led_mask; int global_auto_repeat; char auto_repeats[32]; } XKeyboardsState;
Поле key_click_percent
указывает, имеет ли нажатие клавиши звуковое сопровождение; значения поля задаются в %; 0 - звукового сопровождения нет, 100 - громкий звук. Поле bell_percent
, bell_pitch
и bell_duration
указывают, какую силу, частоту и продолжительность имеет предупреждающий сигнал, возникающий при нажатии некоторых клавиш.
Некоторые клавиатуры используют для клавиш-модификаторов световую подсветку. Поле led_mask
представляет собой комбинацию флагов, показывающую, для каких клавиш эта подсветка используется.
Когда клавиша нажата и удерживается, то сервер может автоматически имитировать ее повторное нажатие. Поле global_auto_repeat
определяет, делает это сервер или нет. Особенностью X является то, что автоматическую генерацию событий о нажатии можно разрешать или запрещать для отдельных клавиш. Массив auto_repeats
содержит информацию о том, для каких клавиш автоповтор включен, а для каких нет. Каждый бит массива соответствует клавише с определенным физическим кодом. Если бит установлен, то генерация разрешена, если сброшен, то запрещена. Каждый байт N
массива содержит биты для клавиш с кодами от 8N
до 8N+7
.
Изменить параметры клавиатуры можно с помощью XChangeKeyboardControl()
.
Желаемые установки передаются через переменную, которая указывает на структуру типа
XKeyboardControl
, определяемую следующим образом:
typedef struct { int key_click_percnet; int bell_percent; int bell_pitch; int bell_duration; int led; int led_mode; int key; int auto_repeat_mode; } XKeyboardControl;
Первые четыре поля совпадают с аналогичными полями структуры XKeyboardState
. Поля 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
.