Программирование в X-Window
средствами Free Pascal
Авторы: А.П. Полищук, С.А. Семериков
[Оформление в HTML: Valery Votintsev]
Содержание
1. Основы программирования в системе X Window
1.3. Работа с внешними устройствами
1.3.1. Клавиатура
Как и большинство интерактивных программ, задачи,
выполняющиеся в 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 .
|