Как узнать код клавиши linux

Обновлено: 07.07.2024

НАЗВАНИЕ
keyboard - клавиатура персонального компьютера.

ОПИСАНИЕ
Клавиатура персонального компьютера используется для ввода данных, переключения экранов и направления некоторых управляющих сигналов компьютеру. Система UNIX выполняет эмуляцию экрана и клавиатуры терминала и при этом извлекает пользу из некоторых особенных клавиш и их комбинаций. Эти клавиши и их комбинации имеют специальные названия, которые уникальны в системе UNIX и могут соответствовать, а могут и не соответствовать меткам клавиш на вашей клавиатуре. Эти клавиши будут описаны позже.

  • Вводится символ ASCII.
  • Компьютеру посылается символьная строка.
  • Запускается какая-либо функция.
  • Меняется значение другой клавиши или клавиш.

Когда нажимается клавиша, клавиатура посылает компьютеру скан-код, который интерпретируется драйвером клавиатуры. Интерпретация кодов клавиш может быть изменена так, что клавиши могут начать функционировать по другому, отлично от их установок по умолчанию.

  • Переключение экранов.
  • Генерация сигнала.
  • Изменение значения предыдущего символа, символов или строки.

Переключение экранов (многоэкранный режим)
Для переключения на следующий экран нажмите Ctrl-PrtSc, используя клавиши Ctrl и PrtSc. Любой активный экран может быть выбран нажатием alt-Fn, где Fn - одна из функциональных клавиш. F1 относится к дисплею компьютера (/dev/tty01).

Сигналы
Сигналы оказывают воздействие на процесс или несколько процессов. Примерами сигналов являются Ctrl-d (конец ввода и выход из оболочки), Ctrl-\ (завершение процесса), Ctrl-s ( остановка выдачи еа экран) и Ctrl-q (возобновление выдачи).

Обычно символы ставятся в соответствие сигналам с помощью stty(1). Единственный способ поставить сигнал в соответствие символам через посредство stty.

Изменение значения нажатий клавиш
Действительный код, посылаемый драйверу клавиатуры, может быть изменен с помощью комбинации некоторых клавиш. Например, клавиша SHIFT меняет значение символов ASCII буквенно-цифровых клавиш. Удерживание клавиши Ctrl при нажатии других клавиш генерирует управляющие коды (Ctrl-d, Ctrl-s, Ctrl-q и др.).

Следующие клавиши Fn (F49-F60) находятся на дополнительной цифровой панели (Shift не используется): F49 - '7'
F55 - '6'
F50 - '8'
F55 - '+'
F51 - '9'
F55 - '1'
F52 - '-'
F55 - '2'
F53 - '4'
F55 - '3'
F54 - '5'
F55 - '0'

  • Base
  • Shift
  • Ctrl
  • Alt
  • Ctrl-Shift
  • Alt-Shift
  • Alt-Ctrl
  • Alt-Ctrl-Shift

Два дополнительных состояния обозначаются двумя специальными байтами. Первый является байтом "специального состояния", биты которого указывают, является ли данный ключ "специальным" в одном или нескольких из первых восьми состояний.

Второй может быть одним из четырех символов (C, N, B, O), указывающих на то, как служебные клавиши фиксации регистров влияют на них.

Режимы клавиатуры
Большинство клавиатур обычно находятся в режиме XT, но некоторые из них могут быть установлены в режим AT. Для определения того, поддерживает ли клавиатура режим AT, имеется утилита kbmode(8), которая может быть также использована для переключения клавиатуры в режим AT после очередной перезагрузки системы. Можно установить системную конфигурацию клавиатуры на режим AT с помощью утилиты configure(8).

Клавиатуры с расширенными возможностями программируются в режиме AT более полно, в котором распознаются также по две клавиши Ctrl и Alt.

Скан-коды
В следующей таблице описывается содержимое файла /usr/lib/keyboard/keys, устанавливаемое по умолчанию. Она содержит следующие заголовки колонок:

SCAN CODE - скан-код, генерируемый аппаратной частью клавиатуры при нажатии клавиши. Пользователь не имеет доступа к скан-коду, генерируемому на отжатие клавиши.

BASE - нормальное значение, генерируемое при нажатие клавиши.

SHIFT - значение, генерируемое при нажатии клавиши при нажатой клавише SHIFT.

  • C указывает на воздействие со стороны Capslock
  • N указывает на воздействие со стороны Numlock
  • B указывает на воздействие со стороны Numlock и Capslock вместе
  • O указывает на отсутствие этого воздействия

Клавиши типа C, N и B генерируют смещенное значение скан-кода в состоянии, когда эти служебные клавиши включены. Если при этом будет нажата клавиша Shift, то значение скан-кода будет переключено обратно.

Прочие колонки таблицы представляют значения, генерируемые при нажатии данной клавиши в комбинации с удерживаемыми клавишами CTRL, ALT и SHIFT.

Все эти значения, за исключением ключевых слов, представляют собой символы ASCII. Ключевые слова относятся к специальным функциональным клавишам.

Следующие скан-коды генерируются только на клавиатурах, которые поддерживают и находятся в режиме AT.

В следующей таблице перечисляются "значения" специальных ключевых слов в файле /usr/lib/keyboard/keys (и в предыдущей таблице). mapkey(ADM) помещает "значение" ключевого слова в буфер управления вводом/выводом во время назначения клавиш. Эти ключевые слова используются только в файле скан-кодов /usr/lib/keyboard/keys для упрощения его чтения.

В следующей таблице перечисляются названия ключевых слов и их десятичные значения, которые могут взаимозаменяться в файле mapkey. Эти названия используются вместо соответствующих численных констант для облегчения чтения таблицы скан-кодов. Но в буфер управления вводом/выводом помещаются только десятичные значения. Они берутся из ascci(5).

Назначение клавиш клавиатуры
Установление соответствия клавиш клавиатуры является составной частью эмуляции терминала. Эта процедура выполняется только для клавиатуры компьютера, но не для удаленных терминалов. Для изменения таблицы соответствий клавиш используйте утилиту mapkey. Чтобы изменить эту таблицу для отдельных каналов (экранов в многоэкранном режиме) используйте программу mapchan(5).

Установка соответствий клавиш клавиатуры может быть также выполнена с помощью ioctl. Синтаксис - тот же, что и для соответствий функциональных клавиш в предыдущем разделе.

При установке соответствий клавиш клавиатуры значение cmd=GIO_KEYMAP высвечивает текущую таблицу соответствий, а cmd=PIO_KEYMAP помещает готовый буфер на место.

Назначение функциональных клавиш
Для назначения функциональных клавиш используйте утилиту mapstr (см. mapkey(8)). mapstr модифицирует таблицу соответствий функциональных клавиш, в которой эти клавиши определяются.

Таблица соответствий функциональных клавиш представляет собой массив из 512 байтов (typedef strmap_t - тип структуры), содержащий строки, заканчивающиеся нулем и переопределяющие функциональные клавиши. Первая строка приписывается первой функциональной клавише, вторая - второй и т.д.

Не существует ограничения на длину строки, кроме предела самой таблицы, 512 байтов, включая нули. Строки обнуляются введением дополнительных нулевых символов.

Далее приведен список значений функциональных клавиш, устанавливаемых по умолчанию:

Вы можете назначать функциональные клавиши с помощью ioctl(2). Синтаксис имеет вид:

При установке соответствий клавиш клавиатуры значение cmd=GIO_KEYMAP высвечивает текущую таблицу соответствий, а cmd=PIO_KEYMAP устанавливает новую таблицу на место.

Исходный код, отвечающий за обработку скан-кодов и кодов клавиш, входит в состав многих программ, распространяемых согласно свободной лицензии. К ним относятся kbd (мы будем рассматривать версию 1.15.3) и console-tools (версия 0.2.3, например). Архивы с исходными текстами и kbd и console-tools содержат файл showkey.c , в котором реализуется механизм вывода скан-кодов и кодов (keycodes) клавиш, генерируемых когда пользователь нажимает кнопки на клавиатуре.

И kbd и console-tools являются приложениями с текстовым интерфейсом. В среде GNU/Linux такие программы почти всегда включают в свой состав стандартную функцию getopt_long() , осуществляющую синтаксический анализ аргументов командной строки. Достаточно подробные пояснения по поводу использования этой функции даны в работе [МитчеллОулдемСамьюэл2003, С. 31-34].

Применяется ли getopt_long() в kbd и console-tools ? Да. Код в файле src/showkey.c (из набора программ kbd-1.15.3 ) служит наглядным примером того, как это делается.

Исходя из того, что одним из основных недостатков современной литературы о программировании является почти полное отсутствие примеров кода, решающего реальные, а не учебные задачи, остановимся на src/showkey.c подробнее.

/*--- Начало файла src/showkey.c с комментариями ---*/

/* В системах GNU/Linux заголовочные файлы обычно хранятся в каталоге /usr/include . Иными словами, если в командной строке ввести ``less /usr/include/stdio.h'' , можно будет увидеть содержание заголовочного файла, ответственного за реализацию ввода/вывода в приложении. В английском языке словам ``ввод'' и ``вывод'' соответствуют ``input'' и ``output''. Таким образом, stdio.h расшифровывается как ``Standard Input/Output Header file''. */

/* Имена заголовочных файлов, находящихся в каталоге /usr/include (или его аналоге), заключаются в угловые скобки. В свою очередь, двойные кавычки применяются для выделения имён заголовочных файлов, расположенных в одном каталоге с кодом программы, которую предстоит компилировать (переводить с языка высокого уровня на язык понятный компьютеру, то есть --- в машинный код). */

/* Структура termios используется функциями управления терминалом в Unix-подобных системах. Подробнее см. [Рочкинд2005, С. 226-228]. Структура --- это совокупность нескольких переменных, часто различных типов, сгруппированных под единым именем для удобства обращения. [КернигаРитчи2006, с. 139] */

/* Область действия функции get_mode() ограничивается данным файлом исходного кода: от точки объявления до конца (на это указывает слово static перед именем функции). Иными словами, к функции get_mode() нельзя обращаться за пределами файла, в котором она объявлена. */

/* В свою очередь, тип void (в переводе с английского --- ``пустой'') обозначает пустое множество значений. Он используется для указания типа возвращаемого функцией значения в случае если функция ничего не возвращает. */

/* Предшествующая строка кода указывает, что функция get_mode() не только не возвращает, но и не получает никаких значений на вход. */

/* *m является указателем и представляет из себя группу ячеек памяти, которые могут содержать адрес переменной типа char . */

/* KDGKMODE (Get Keyboard Mode) объявляется в файле /usr/include/kd.h и хранит название текущего режима работы драйвера клавиатуры. Нам не удалось найти документации, где пояснялось бы как расшифровывается ``KD'' . Вероятнее всего, ``KD'' --- это Keyboard Driver . */

/* ioctl - системный вызов общего назначения, служащий для управления символьными устройствами всех типов. Его синтаксис описывается следующим образом: ioctl(fd, cmd, arg) , где fd - дескриптор файла; cmd - целое число, указывающее вызываемую команду; arg - дополнительный аргумент команды (обычно - адрес блока параметров). */

/* KDGKBMODE - это имя, которое в результате макроподстановки, осуществляемой препроцессором (подробнее см. [КерниганРитчи2006, С. 102-103]), заменяется на число, указывающее на команду, результатом которой является получение информации о текущем режиме работы драйвера клавиатуры. Упомянутая макроподстановка происходит благодаря содержимому файла /usr/include/linux/kd.h . */

/* Аргумент &oldkbmode содержит адрес переменной oldkbmode . Именно по этому адресу будет записан результат выполнения вызовы ioctl . K_RAW , K_XLATE , K_MEDIUMRAW , K_UNICODE - это имена, используемые для макроподстановки в файле /usr/include/linux/kd.h . */

/* Таким образом, вместо KDGKBMODE , K_RAW , K_XLATE , K_MEDIUMRAW и K_UNICODE подставляются числа, указанные через макроопределение в файле /usr/include/linux/kd.h : 0x4B44, 0x00, 0x01, 0x02, 0x03 соответственно. Именно поэтому переменная oldkbmode имеет тип int . */

/* KDSKBMODE (Set Keyboard Mode) содержит число, указывающее на команду установки режима работы драйвера клавиатуры. */

/* Конструкция еxit(выражение) эквивалентна конструкции return . Обычно она возравщает 0 если всё идёт хорошо, а 1 - когда произошла ошибка. */

/* Системный вызов tcsetattr задаёт атрибуты терминала, предварительно сохранённые в структуре old (копия структуры termios ). */

/* Атрибут attr_noreturn указывает на то, что функция никогда не возвращает значений. */

/* Функция clean_up() восстанавливает режим работы драйвера клавиатуры, исходя из данных, полученных с помощью системного вызова ioctl . */

/* Атрибут attr_unused указывает на то, что аргумент функции никак не обрабатывается. */

/* Функция usage() , выводящая информацию об аргументах, которые принимает программа, не нуждается в особых пояснениях. */

/* *short_opts - это указатель. Значение записанное в адрес, на который ссылается этот указатель, впоследствии не меняется, так как в начале строки с его объявлением стоит модификатор const . Строка, хранимая по адресу *short_opts , содержит возможные короткие опции, каждая из которых представлена одной буквой. */

/* long_opts[] (в переводе --- ``длинные опции'', то есть содержащие более одной буквы в своём имени) представляет из себя массив структур. Каждая структура массива имеет следующие элементы:
< "имя опции", наличие_аргумента, флаг, значение>. */

/* Крайняя структура в массиве должна содержать только нули. */

/* Элемент "наличие_аргумента" может содержать либо числа (0, 1 ,2), либо имена имена для макроподстановки, указанные в файле /usr/include/getopt.h и соответствующие этим числам ( no_argument соответствует нулю; required_argument соответствует единице; optional_argument соответствует двойке). */

/* Если элемент "значение" содержит короткую опцию из строки, на которую указывает *short_opts , то элемент "флаг" , будучи установленным в NULL , позволяет обеспечить соответствие между короткой и длинной опцией (например, как показано ниже, короткая опция -h соответствует длинной опции --help ). Если же заменить элемент "флаг" на указатель, то он будет указывать на переменную, имя которой находится в элементе "значение" . */

/* Следующие три строки кода отвечают за локализацию интерфейса программы средствами GNU gettext . */

/* Пятый арумент функции getopt_long может содержать указатель на структуру в массиве long_opts[] . Подробнее см. man getopt_long (данная страница справочного руководства, помимо всего прочего, содержит пример исходного кода, где пятый аргумент является указателем, а не нулём, как в рассматриваемом нами файле). */

/* Как уже отмечалось выше, структура new - это копия структуры termios . */

/* Две строки кода, представленные далее, иллюстрируют приёмы работы с элементами структуры (локальными флагами копии структуры termios ). Флаги ICANON и ISIG устанавливаются в нуль, ECHO и ECHOCTL --- в единицу (подробнее см. [КерниганРитчи2006, с. 160]). */

/* При флаге ICANON равном нулю, вводимые символы не составляются в строки вплоть до чтения (выполнения системного вызова read ). ISIG , будучи обнулённым, блокирует обработку управляющих символов (терминал перестаёт реагировать на управляющие последовательности, вызывающие появление сигналов). К этим символам относятся: INTR (Ctrl+C), QUIT (Ctrl+\), SUSP (Ctrl+z) и DSUSP (Ctrl+y) . Подробнее см. [ТаненбаумВудхалл2006, С. 270-277].*/

/* Следующая строка устанавливает все флаги ввода (IGNBRK, BRKINT, IGNPAR, PARMRK, INPCK, ISTRIP, INLCR, IGNCR, ICRNL, IUCLC, IXON, IXANY, IXOFF, IMAXBEL, IUTF8) в нуль. Подробнее см. /usr/include/bits/termios.h , а также комментарии по флагам режимов . */

/* Когда число символов в очереди будет равно значению, записанному в new.c_cc[VMIN] , или когда пройдёт количество десятых долей секунды, указанное в new.c_cc[VTIME] (код рассматриваемого файла отключает таймер так как в new.c_cc[VTIME] заносится нуль) будет выполнен системный вызов read . Подробнее см. [Рочкинд2005, С. 233-236]. */

/* Изменения в структуре termios , хранимые в структуре new , применяются системным вызовом tcsetattr() . Аргумент TCSAFLUSH говорит о том, что помимо применения изменений должны быть очищены буферы ввода/вывода терминала (подробнее см. раздел 3.1 документа Serial Programming Guide for POSIX Operating Systems и его не самый качественный, но всё же перевод на русский язык . */

/* Функция getfd() определена в файле getfd.c . */

/* По умолчанию showkey прекращает работу при отсутствии активности пользователя (нажатых клавиш) в течение 10 секунд. */

/* Системный вызов signal устанавливает реакцию программы showkey на сигналы (запросы на прерывание, осуществляемые на уровне процессов), имена которых определены в файле /usr/include/bits/signum.h (см. /usr/include/signal.h ). По сути речь идёт о назначении подпрограмм обработки для каждого из сигналов. Разработчики showkey сделали всё достаточно прямолинейно, назначив функцию die() обрабатывать все возможные сигналы, кроме того, что генерируется по истечении времени, заданного в качестве аргумента функции alarm() (см. выше). */

/* Как видно, чтение скан-кодов осуществляется с помощью системного вызова read , считывающего в бесконечном цикле байты из файла, представленного дескриптором fd (не забывайте, что в GNU/Linux устройства также являются файлами). */

/* Как отмечалось ранее (при обсуждении вывода программы getkeycodes ), отпускание клавиши результируется в скан-коде, старший бит которого равен единице (напомним, что речь идёт об особенностях набора скан-кодов Set 1 ). Иными словами, к скан-коду нажатой клавиши прибавляется шестнадцатеричное число 80 , которое в программах на языке Си записывается как 0x80 . */

/*--- Конец файла src/showkey.c с комментариями ---*/

Компилирировать представленный выше исходный код нужно вместе с файлом src/getfd.c , содержащем определение функции getfd() .

Проверить работоспособность получившегося исполняемого файла ( a.out ) лучше всего вне X сессии. Например, в виртуальном терминале, доступном по нажатию <Ctrl>+<Alt>+<F2>.

Разумеется, для удобства, было бы хорошо иметь возможность управлять длительностью временного промежутка, который программа showkey ожидает ввода пользователя перед тем, как завершить свою работу (в kbd-1.15.3 этот промежуток времени равен 10 секундам). В рамках проекта console-tools данное пожелание реализовано (см. файл kbdtools/showkey.c в архиве). Комментарии по поводу использования некоторых приложений, входящих в состав console-tools см. в статье "VGA console basics and Linux console-tools" .

Читайте также: