Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

На главную -> MyLDP -> Электронные книги по ОС Linux
Назад Введение в мир программирования
Глава 2. Архитектура компьютера
Вперед

Ввод текста. Взаимодействие с клавиатурой

Общие замечания

Алгоритм взаимодействия операционной системы (ОС) с клавиатурой выглядит следующим образом. В результате нажатия клавиши микропроцессорная система внутри клавиатуры генерирует скан-коды (scan codes), отправляемые на вход контроллеру клавиатуры (расположенному на материнской плате), далее эти коды обрабатываются BIOS (Basic Input/Output System) и драйвером клавиатуры, работающим на уровне ядра ОС. ``Bypassing pre-boot authentification passwords by instrumenting the BIOS keyboard buffer (practical low level attacks against x86 pre-boot authentication software)'' --- интересная статья о том, как BIOS работает с клавиатурой, включащая прелюбопытнейшие схемы и примеры кода на ассемблере. Даже если вы плохо знаете английский язык, простое ознакомление с иллюстрациями к упомянутой статье позволит вам лучше понять процесс взаимодействия операционной системы с клавиатурой.

Драйвер клавиатуры, работающий на более высоком уровне абстракции, чем BIOS, либо без изменений отправляет полученные скан-коды пользовательским программам, либо преобразует скан-коды в коды клавиш (keyboard codes, keycodes) и также отправляет их внешним программам (исключения из этого правила обсуждаются далее в разделе ``Режимы работы драйвера клавиатуры'').

Существует несколько наборов скан-кодов. Первый набор (Set 1) появился в 1981 году вместе с клавиатурой для IBM PC/XT. Set 2 начал применяться вместе с IBM AT Keyboard (1984 год; см. также http://www.win.tue.nl/~aeb/linux/kbd/scancodes-11.html). IBM PS/2 Keyboard (1987 год) предоставляет возможность работы с Set 3 (подробнее см. статью ``The PS/2 Keyboard Interface''). Известна также альтернативная версия истории развития событий.

Современные клавиатуры умеют генерировать скан-коды по правилам разных наборов (и в Set 1 и в Set 2 и в Set 3).

Скан-коды, генерируемые USB клавиатурами можно отнести к Set 4. Хорошая свободная таблица, где указаны все четыре набора скан-кодов размещена по адресу http://www.win.tue.nl/~aeb/linux/kbd/scancodes-10.html#ss10.6. В том, что касается наборов Set 1, Set 2 и Set 3, контроллер клавиатуры обычно осуществляет преобразование скан-кодов, поступающих с клавиатуры, в набор Set 1. Поддержка USB клавиатур осуществляется средствами хост-контроллера (USB Host Controller). Старые версии драйверов USB клавиатуры, получив скан-коды, направляли их на вход драйвера kbd (или ему подобных). Материалы, с которых можно начать знакомство с логикой работы драйвера хост-контроллера доступны в Интернет. Получить общее представление о драйвере USB клавиатуры можно обратившись к файлу usbkbd.c, входящему в состав Linux (ядра операционной системы GNU/Linux). Поиск по исходникам ядра удобно осуществлять через сайт http://tomoyo.sourceforge.jp/cgi-bin/lxr/ident (в поле identifier нужно ввести название искомой функции или переменной).

Нажатие и отпускание одной и той же клавиши результируется в отличающихся друг от друга скан-кодах (один --- соответствует нажатию, а другой --- отпусканию). Код клавиши будет одинаков в обоих случаях. Например, нажатие и отпускание <d> имеет код (keycode), равный 32 (десятичное представление шестнадцатеричного числа 20: 3210 = 2016).

В рамках проекта графической системы X Window, используются уникальные символические имена (KEYSYM - KEY SYMbols) каждой надписи на клавише клавиатуры. Например, на руссифицированной клавиатуре со стандартной QWERTY раскладкой, есть клавиша, на которой нарисованы буквы ``d'' и ``в''. Каждая из этих букв имеет своё собственное KEYSYM имя (XK_d и XK_Cyrillic_ve). KEYSYM определены в документе X Window System Protocol (см. раздел 5. Keyboards и Приложение A).

В описании протокола X Window System отмечается (см. страницу 91), что возможны два подхода к созданию списка KEYSYM:

  • присвоение отдельного KEYSYM каждой надписи, находящейся на кнопке клавиатуры (при таком подходе клавиши <DEL> и <Delete> будут иметь различные KEYSYM);
  • присвоение единого KEYSYM для надписей одинаковых по смыслу (<DEL> и <Delete> будут иметь один и тот же KEYSYM).

Подход, заключающийся в присвоении KEYSYM по смыслу был избран в качестве основного. Файл, в котором представлены макроопределения (подробнее см. [КерниганРитчи2006, с. 102]) KEYSYM, обычно размещён под именем /usr/include/X11/keysymdef.h.

Привязка между кодами клавиш и KEYSYM осуществляется через специальные таблицы соответствий (keymaps). Подробнее см. статью о работе виртуальной клавиатуры.

Программа dumpkeys отправляет на стандартное устройство вывода упомянутую таблицу соответствий. loadkeys загружает новую версию таблицы из файла или со стандартного устройства ввода. Формат таблицы соответствий описан в руководстве пользователя (см. man keymaps). Коды, генерируемые клавишами, могут быть определены с помощью программы showkey (речь о ней пойдёт ниже). В системе X Window для этих целей подходит приложение под названием xev.

Правка таблицы соответствий (keymap) возможна также средствами xmodmap (подробнее см. работы М. Ф. Крафта и А. Бруэра). Для начала, разумеется, лучше получить информацию о текущих настройках. Это позволяет сделать опция -pke.

xmodmap -pke|less

Теперь с помощью опции -e можно назначить соответствие между кодом клавиши и списком KEYSYM. У автора этих строк был случай когда сбились настройки поведения клавиши с кодом 61. Благодаря следующей команде их удалось поправить.

xmodmap -e "keycode  61 = slash question period comma"

Узнать какие соответствия кодов клавиш и скан-кодов используются ядром вашей ОС, можно средствами программы getkeycodes.

#: getkeycodes
Plain scancodes xx (hex) versus keycodes (dec)
for 1-83 (0x01-0x53) scancode equals keycode

 0x50:   80  81  82  83  84   0  86  87
 0x58:   88 117   0   0  95 183 184 185
 0x60:    0   0   0   0   0   0   0   0
 0x68:    0   0   0   0   0   0   0   0
 0x70:   93   0   0  89   0   0  85  91
 0x78:   90  92   0  94   0 124 121   0

Escaped scancodes e0 xx (hex)

e0 00:    0 164 128 165 163 224 225 236
e0 08:    0 161 205 227   0   0   0   0
e0 10:  165   0 226   0   0   0   0   0
e0 18:    0 163   0   0  96  97   0   0
e0 20:  113 140 164   0 166   0   0   0
e0 28:    0   0 255   0   0   0 114   0
e0 30:  115   0 172   0   0  98 255  99
e0 38:  100   0   0   0   0   0   0   0
e0 40:    0   0   0   0   0 119 119 102
e0 48:  103 104   0 105 112 106 118 107
e0 50:  108 109 110 111   0   0   0   0
e0 58:    0   0   0 125 126 127 116 142
e0 60:    0   0   0 143   0 217 156 173
e0 68:  128 159 158 157 155 226   0 112
e0 70:    0   0   0   0   0   0   0   0
e0 78:    0   0   0   0   0   0   0   0

Поясним значение информации, выводимой getkeycodes.

Во-первых, в представленном выше примере вывода говорится, что ``for 1-83 (0x01-0x53) scancode equals keycode'' (скан-код эквивалентен коду клавиши для десятичных значений от 1 до 83). Вы, вероятно догадались, что шестнадцатеричная запись 0x01 соответствует десятичной единице, а запись 0x53 эквивалентна десятичному числу 83: 5316 = 010100112 = 20 + 21 + 24 + 26 = 8310. Каждый из двух разрядов шестнадцатеричного числа преобразуется в четыре разряда двоичного числа (подробнее о переводе чисел из одной системы счисления в другую см. раздел ``Ячейки памяти и позиционные системы счисления'').

Знание данного обстоятельства помогает понять логику работы программы showkey, которая и в режиме scancodes (опция -s) и в режиме keycodes (опция -k) может выводить одинаковые числовые последовательности.

Во-вторых, нажатию/отпусканию некоторых кнопок на клавиатуре соответствуют целые группы скан-кодов, начинающихся с управляющих кодов 0xe0 или 0xe1. Ни 0xe0, ни 0xe1 обычно не используются как независимые скан-коды (хотя встречаются редкие исключения). Подробнее см. раздел 1.3 в http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html.

Отметим также, что нажатие клавиши, исходя из правил установленных для набора Set 1, результируется в скан-коде, старший бит которого равен 0. Отпускание соответствует тому же скан-коду, но с установленным в 1 старшим битом. К примеру, если скан-код, генерируемый по нажатию кнопки <D>, равен 2016 = 001000002, то при отпускании <D> появится скан-код a016 = 101000002. Для клавиш, которым соответствуют группы скан-кодов, обозначенное правило остаётся верным. Например, нажатие клавиши <Pause/Break> результируется в 0xe1 0x1d 0x45 (e116, 1d16, 4516). Отпускание <Pause/Break> порождает 0xe1 0x9d 0xс5: старший бит каждого из двух младших (считаем справа налево) байтов последовательности устанавливается из нуля в единицу).

Посмотрите ещё раз на вывод программы getkeycodes и обратите внимание на то, что все скан-коды, соответствующие нажатию кнопки, содержат нуль на месте старшего бита. Например, 0x78 = 011110002.

В случае если в стандартную таблицу соответствий ``скан-код --- код клавиши'' по какой-либо причине требуется внести правку, то имеет смысл воспользоваться программой setkeycodes. Например, setkeycodes e06b 115 свяжет скан-код 0xe0 0x6b с кодом клавиши 115.

Помимо setkeycodes, для управления привязкой ``скан-код --- код клавиши'' применяется набор программ udev. На сайте проекта archlinux есть статья о том, как использовать udev в этих целях. Кстати сказать udev включает в свой состав библиотеку файлов keymap для разных физических устройств (см. каталог /lib/udev/keymaps/).

Многие из продаваемых ныне клавиатур оснащены мультимедиа-клавишами. Некоторые из них, хоть и распознаются ядром операционной системы, но не имеют привязки ``скан-код --- код клавиши --- KEYSYM''. Очень толковые материалы о том как осуществить эту привязку, опубликованы в рамках проекта документации archlinux.

Аппаратное обеспечение для взаимодействия с клавиатурой

В старых ЭВМ контроллер клавиатуры представлял из себя отдельный чип, например, VT82C42 или Intel 8042. Cовременные персональные компьютеры обычно оснащаются ``Суперконтроллерами ввода/вывода'' на одном чипе --- Super I/O controllers, например, VT1211, взаимодействующими с ЦПУ через интерфейс LPC (Low Pin Count). Эти суперконтроллеры включают в себя не только контроллер клавиатуры (в частности, умеющий работать с интерфейсом PS/2), но и контроллеры параллельного и последовательного портов, дисковода гибких дисков. Бывают также случаи, когда контроллер клавиатуры входит в состав южного моста чипсета материнской платы, отвечающего за работу с ``медленными'' устройствами.

На сегодняшний день самыми распространёнными являются PS/2 (работающие через контроллер клавиатуры) и USB (работающие через интерфейсы хост-контроллеров Open HCI, Universal HCI, Enhanced HCI, eXtensible HCI).

USB клавиатуры более уязвимы к перехвату вводимой информации, чем клавиатуры работающие через коннектор PS/2. Защитить PS/2 устройства относительно легко, если использовать простые аппаратные модули шифрования.

Помимо прочего, имеет смысл отметить возможность конструирования самодельных клавиатур на базе микроконтроллеров Atmel. Любопытная статья на эту тему: ``Учебный курс. Опрос матричной клавиатуры. Пример использования автомата (State Machine)''. Методы подключения клавиатуры через микросхему Intel 82C55 к персональному компьютеру, рассмотрены в работе [Брэй2005, С. 556-566].

Интересные зарисовки о внутреннем устройстве клавиатуры находятся по адресу http://www.pcguide.com/ref/kb/const/op.htm (на английском языке). На том же сайте размещена статья об особенностях клавиатуры PC/XT на 83 клавиши, представляющая значительный интерес с исторической точки зрения.


Предыдущий раздел: Оглавление Следующий раздел:
Кодирование текста   Программная обработка скан-кодов и кодов клавиш