Библиотека сайта rus-linux.net
Назад | Введение в мир программирования Глава 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 клавиши, представляющая значительный интерес с исторической точки зрения.
Предыдущий раздел: | Оглавление | Следующий раздел: |
Кодирование текста | Программная обработка скан-кодов и кодов клавиш |