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, определенный следующим образом:
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.
1.3.2 Мышь
С точки зрения программы общение с мышью похоже на работу с клавиатурой. X получает сигналы от устройства, преобразует их в события и помещает последние в очередь программы. Однако есть и существенная разница. Если события от клавиатуры передаются лишь программе, окно которой имеет фокус ввода, то события от мыши могут передаваться, в принципе, любой задаче, окно (окна) которой присутствуют на экране.
Чаще всего приходится обрабатывать события нажатия (отпускания) кнопки мыши. Для регистрации такого типа событий, необходимо добавить одну из следующих масок с помощью функции XSelectInput():
• ButtonPressMask - уведомлять о нажатии любой кнопки в одном из окон программы.
• ButtonReleaseMask - уведомлять об отпускании любой кнопки в одном из окон программы.
В цикле обработки сообщений могут проверяться такие события:
• ButtonPress - нажата кнопка в одном из окон программы.
• ButtonRelease - отпущена кнопка в одном из окон программы.
Структура для этих сообщений получается доступом к полю xbutton объединения TXEvent и содержит, в частности, такие поля:
• window: TWindow - идентификатор окна, которому было послано сообщение (в случае, если оно было зарегистрировано для нескольких окон программы).
• x, y: longint - координаты x и y (в пикселях) мышиного курсора в момент нажатия.
• button: cardinal - номер нажатой кнопки (может принимать значения Button1, Button2, Button3).
• time: TTime - время (в миллисекундах), которое длилось событие. Может использоваться для определения "двойного щелчка".
В качестве примера приведем фрагмент кода, в котором рисуется черный пиксель в позиции мыши всякий раз, когда мы получаем событие "нажатие кнопки" от первой кнопки мыши, и стирается пиксель (то есть рисуется белый), когда нажата вторая кнопка мыши. Предполагается существование двух GC: gc_draw с черным цветом переднего плана и gc_erase с белым цветом переднего плана.
…
ButtonPress:
 begin
 (* сохраняем координаты кнопки мыши в целых переменных *)
 (* также сохраняем идентификатор окна, в котором была нажата кнопка мыши *)
 x:= an_event.xbutton.x;
 y:= an_event.xbutton.y;
 the_win:= an_event.xbutton.window;
 (* проверяем, какая из кнопок была нажата, и действуем соответственно *)
 case (an_event.xbutton.button) of
 Button1:
  (* рисуем пиксель в позиции мыши *)
  XDrawPoint(display, the_win, gc_draw, x, y);
 Button2:
  (* стираем пиксель в позиции мыши *)
  XDrawPoint(display, the_win, gc_erase, x, y);
 else (* возможно, третья кнопка - игнорируем *)
  ;
 end;
end;
…
Подобно событиям нажатия и отпускания кнопки мыши, нас также могут извещать о различных событиях перемещения мыши. Они делятся на два семейства. Первое - перемещение указателя мыши, пока никакие кнопки не нажимаются, и второе - движение указателя мыши при одной (или более) нажатых кнопках (это иногда называется операцией "перетаскивания" (drag)). Следующие маски событий должны быть добавлено в вызов XSelectInput() для получения извещений о таких событиях:
• PointerMotionMask - события указателя, перемещающегося в одном из окон программы, когда ни одна кнопка мыши не нажата.
• ButtonMotionMask - события перемещения указателя, пока одна (или более) кнопок мыши удерживается нажатой.
• Button1MotionMask - тоже, что и ButtonMotionMask, но только когда первая кнопка мыши удерживается нажатой.
• Button2MotionMask, Button3MotionMask, Button4MotionMask, Button5MotionMask - аналогично для кнопок 2, 3, 4 или 5.
В цикле обработки сообщений проверяется событие MotionNotify - указатель мыши перемещался в одном из окон, для которых мы запросили уведомление о таких событиях.
Структура для этих сообщений получается доступом к полю xmotion объединения TXEvent и содержит, в частности, такие поля:
• window: TWindow - идентификатор окна, которому было послано сообщение движения мыши (в случае, если оно было зарегистрировано для нескольких окон программы).
• x, y: longint - координаты x и y (в пикселях) мышиного курсора в момент генерации сообщения.
• state: cardinal - маска кнопок (или клавиш), удерживаемых во время этого события (если таковые имеются). Эта поле - побитовое "ИЛИ" любого из следующих значений: Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask, ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask. Первые пять значений ссылаются на кнопки мыши, которые нажимаются, остальные соответствуют различным специальным клавишам (Mod1 - обычно клавиша Alt или Meta).