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

UnixForum





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

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

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

Управление светодиодами клавиатуры

Кстати, каким образом программными средствами влиять на состояние светодиодов клавиатуры? Такое управление возможно стандартными средствами в консоли (setleds) и в среде X Window System (xset) при соответствующей настройке содержимого файла xorg.conf.

Давайте приведём пример программы на языке Си, которая позволяет определить то, в каком состоянии находятся светодиоды клавиатуры (она предназначена для работы в текстовом режиме, то есть в терминале, который не зависит от работы графического сервера, в частности, X.org).

// Подключаем библиотеки функций, используемых в программе
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <linux/kd.h>  
#include <sys/ioctl.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char* argv[])
{
	// объявляем переменную, в которую будет записано значение, хранящееся в KDGETLED
   unsigned char led_status;

	// ждём три секунды на случай если состояние одного из светодиодов 
	// изменится сразу после запуска нашей программы
   sleep(3);

	// открываем файл устройства, поступающий в качестве опции на вход программе:
	// ./a.out /dev/tty

   int fd = open(argv[1], O_RDONLY);

	// выполняем системный вызов для работы с символьными устройствами
   ioctl(fd, KDGETLED, &led_status);

   close(fd);

   printf("Текущий статус светодиодов в числовой форме: 0x%02X\n", led_status);

	// В зависимости от содержимого led_status и результатов его сравнения с
	// LED_CAP, LED_NUM и LED_SCR, принимаем решение о том, какое сообщение
	// вывести на экран. Файл linux/kd.h содержит шестнадцатеричные значения,
	// соответствующие этим константам: LED_CAP == 0x04, LED_NUM == 0x02,
	// LED_SCR == 0x01.

   if(led_status == LED_CAP)
      printf("Caps Lock светится!\n");

   if(led_status == LED_NUM)
      printf("Num Lock светится!\n");

   if(led_status == LED_SCR)
      printf("Scroll Lock светится!\n");

   if(led_status == LED_NUM + LED_SCR)
      printf("Num Lock и Scroll Lock светятся!\n");

	if(led_status == LED_SCR + LED_CAP)
      printf("Scroll Lock и Caps Lock светятся!\n");

   if(led_status == LED_NUM + LED_CAP)
      printf("Num Lock и Caps Lock светятся!\n");

   if(led_status == LED_SCR + LED_NUM + LED_CAP)
      printf("Scroll Lock, Num Lock и Caps Lock светятся!\n");

   if(led_status == 0)
      printf("Все светодиоды клавиатуры находятся во выключенном состоянии!\n");
}

Важно отметить, что содержимое переменной led_status (см. исходный код выше) даёт нам информацию именно о состоянии светодиодов, а не о состоянии флагов виртуального терминала. Например, команда sudo setleds -L +caps < /dev/tty7, зажжёт светодиод, соответствующий Caps Lock, но никак не повлияет на регистр (``размер'') букв (за это отвечают флаги виртуального терминала), которые сразу после её исполнения будут введены в окне терминала, относящегося к устройству под именем /dev/tty7. Наша программа (представленная выше) среагирует на изменение состояния светодиодов вне зависимости от состояния флагов терминала и выведет сообщение ``Caps Lock светится!'' (здесь мы исходим из того, что до выполнения команды setleds светодиоды были отключены).

#: sudo setleds -L +caps < /dev/tty7
#: ./a.out /dev/tty7
Текущий статус светодиодов в числовой форме: 0x04
Caps Lock светится!

Программа setleds является инструментом, входящим в базовый набор программ ОС GNU/Linux. Она максимально эффективна только в консоли (туда, куда можно попасть нажав, например, <Ctrl>+<Alt>+<F2>). В рамках X11 сессии (когда активирован графический интерфейс пользователя) её функциональность максимально ограничена (она не может влиять на состояние флагов виртуального терминала и выводить статистику).

Существует программа xset (она не работает в текстовом режиме), одной из функций которой является управление состояниями светодиодов и флагами виртуального терминала. Увы, функциональность xset (в плане работы с клавиатурой) тоже ограничена и сводится к возможности изменить состояние светодиода Scroll Lock.

#: xset led 3
#: xset -led 3

Необходимо отметить, что ограничения в работе xset вводятся X сервером и, согласно документации, могут быть устранены редактированием xorg.conf (см. https://bugs.freedesktop.org/show_bug.cgi?id=2967). Лично у автора этих строк добиться данного результата не получилось.

Можно ли программно перевести клавиатуру в состояние, соответствующее нажатию клавиши Caps Lock пользователем (светодиод горит, изменяется регистр вводимых печатных символов)? Эта задача нетривиальна в свежих версиях X сервера от X.org (начиная с 1.4; подробнее см.: http://www.x.org/wiki/Development/Documentation/InputEventProcessing#An_important_requirement_to_understand_events ). Данная проблема описана по адресу https://www.libreoffice.org/bugzilla/show_bug.cgi?id=16145 и сводится к тому, что применение функций библиотеки XTest активизирует CapsLock лишь на виртуальной клавиатуре. По этой причине, стандартный подход, подразумевающий использование XTestFakeKeyEvent (см. пример ниже), не влияет на состояние светодиода клавиатуры, хотя и меняет регистр вводимых символов.

// Команда для компиляции кода примера:
// gcc имя_файла.c -lX11 -lXtst

// Подключаем необходимые заголовочные файлы,
// в которых объявляются функции и константы,
// необходимые для работы нашей программы.
#include <X11/extensions/XTest.h>
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <X11/keysym.h>

int main(int argc, char **argv)
{
   char *display_name = NULL;
   Display *display;

   // Программа завершает работу если не удаётся открыть дисплей
   if((display = XOpenDisplay(display_name)) == NULL)
   {
        return 1;
   }

   KeySym key = {XK_Caps_Lock};

// Эмулируем нажатие клавиши CapsLock
   XTestFakeKeyEvent(display, XKeysymToKeycode(display, key), True, CurrentTime);

// Эмулируем отпускание клавиши CapsLock
   XTestFakeKeyEvent(display, XKeysymToKeycode(display, key), False, CurrentTime);

   XCloseDisplay(display);
}

Каким же образом повлиять на состояние светодиода в среде X Window? С этим справляется программа setleds (входит в пакет kbd), если её запустить с опцией -L (не трогает флаги виртуального терминала, а лишь меняет состояние светодиода) и правами суперпользователя. Создав Bash скрипт и разместив его в том же каталоге, что исполняемый файл, эмулирующий нажатие CapsLock (код см. выше), можно решить поставленную задачу.

#!/bin/bash
./a.out
setleds -L "$1"caps < /dev/tty7

Файл a.out предназначен для эмуляции нажатия CapsLock. Далее, в зависимости от аргумента (``+'' или ``-''), указанного пользователем, происходит либо включение, либо отключение светодиода клавиши CapsLock. Ещё раз повторимся, что setleds может потребовать прав суперпользователя. Также не забудьте разрешить исполнение нашего Bash скрипта (это делается командой chmod 0755 имя_файла_со_скриптом).

./имя_файла_со_скриптом + # меняется регистр вводимых букв и включается светодиод CapsLock
./имя_файла_со_скриптом - # меняется регистр вводимых букв и отключается светодиод CapsLock

Изложенный подход имеет недостатки. Например, нажатие ``реальной'' клавиши CapsLock после команды ./имя_файла_со_скриптом + не повлияет на состояние светодиода. Потребуется либо выполнить ./имя_файла_со_скриптом -, либо повторно нажать ``реальный'' CapsLock (произойдёт отключение светодиода, а вот регистр символов останется верхним). Чтобы убрать инвертирование следует выполнить ./имя_файла_со_скриптом + два раза подряд.

Следует также быть готовым к тому, что X сервер периодически способен сбоить (команда setleds -L просто перестаёт работать) и для восстановления ``адекватного'' состояния системы X Window может потребоваться перезапуск компьютера (или, как минимум, X сервера).

В случае если у читателя есть желание поэкспериментировать с библиотеками libx11 и xtest, в системах, применяющих deb пакеты, потребуется установить libx11-dev и libxtst-dev. При компиляции программ необходимо будет пользоваться опциями -lX11 и -lXtst, то есть gcc имя_файла.c -lX11 -lXtst.

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

Помимо всего прочего, отметим, что разработка приложений для системы X Window, доступна (и иногда более проста для понимания) на основе библиотек Gtk+, Tk и Qt (обращая внимание на условия лицензирования).

Литература для самообразования

  1. Брукшир Дж. Связь через контроллер // Информатика и вычислительная техника. 7-е изд. СПб.: Питер, 2004. C. 121-124.
  2. Брэй Б. Микропроцессоры Intel: 8086/8088, 80186/80188, 80286, 80386, 80486, Pentium, Pentium Pro Processor, Pentium 4. Архитектура, программирование и интерфейсы. Шестое издание: Пер. с англ. СПб.: БХВ-Петербург, 2005. 1328 с.
  3. Вахалия Ю. UNIX изнутри. СПб.: Питер, 2003. 844 с.
  4. Гук М. Ю. Скан-коды // Аппаратные средства IBM PC. Энциклопедия. 3-е изд. СПб.: Питер, 2006. С. 648-649.
  5. Керниган Б., Ритчи Д. Язык программирования C. 2-е изд.: Пер. с англ. М.: Издательский дом ``Вильямс'', 2006. 304 с.
  6. Митчелл М., Оулдем Д., Самьюэл А. Программирование для Linux. Профессиональный подход.: Пер. с англ. М.: Издательский дом ``Вильямс'', 2003. 288 с.
  7. Немет Э., Снайдер Г., Сибасс С., Хейн Т. UNIX: руководство системного администратора. Для профессионалов. 3-е изд. СПб.: Питер; К.: Издательская группа BHV, 2003. 925 c.
  8. Рочкинд М. Дж. Программирование для UNIX. 2-е изд. перераб и доп.: Пер. с англ. М.: Издательско-торговый дом ``Русская редакция''; СПб.: БХВ-Петербург, 2005. 704 с.
  9. Таненбаум Э., Вудхалл А. Программное обеспечение терминала. Программное обеспечение ввода // Операционные системы: разработка и реализация. Классика CS. СПб.: Питер, 2006. С. 270-277.
  10. Akesson L. The TTY demystified. URL: http://www.linusakesson.net/programming/tty/index.php (дата обращения: 02.04.2012).
  11. Allen J. How does the keyboard interface work? URL: http://www.cs.cmu.edu/afs/cs/usr/jmcm/www/info/key2.txt (дата обращения: 09.03.2012).
  12. Benson A. J., Aitken G., Fortune E., Converse D., Sachs G., Walker W. The X Keyboard Extension: Library Specification. URL: http://www.x.org/releases/X11R7.6/doc/libX11/specs/XKB/xkblib.html
  13. Berrange D. P. A summary of scan code & key codes sets used in the PC virtualization stack. URL: http://berrange.com/tags/scan-codes/ (дата обращения: 03.04.2012).
  14. Brossard J. Bypassing pre-boot authentification passwords by instrumenting the BIOS keyboard buffer (practical low level attacks against x86 pre-boot authentication software). URL: http://www.ivizsecurity.com/research/preboot/preboot_whitepaper.pdf (дата обращения: 02.04.2012).
  15. Brouwer A. E. Keyboard Programming Interface. URL: http://www.kernel.org/pub/linux/kernel/people/aeb/kbdbook.tmpl (дата обращения: 01.04.2012).
  16. Brouwer A. The Linux keyboard and console HOWTO. URL: http://www.faqs.org/docs/Linux-HOWTO/Keyboard-and-Console-HOWTO.html (дата обращения: 10.02.2012).
  17. Brouwer A. E. The Linux keyboard driver. URL: http://www.linuxjournal.com/article/1080 (дата обращения: 07.03.2012).
  18. Krafft M. F. Extending the X keyboard map with xkb. URL: http://madduck.net/docs/extending-xkb/ (дата обращения: 10.02.2012).
  19. Lee K., Bae K., Yim K. Hardware Approach to Solving Password Exposure Problem through Keyboard Sniff. URL: http://www.waset.org/journals/waset/v56/v56-5.pdf (дата обращения: 03.04.2012).
  20. Savard J. J. G. Scan Codes Demystified. URL: http://www.quadibloc.com/comp/scan.htm (дата обращения: 09.03.2012).
  21. Sweet M. R. Serial Programming Guide for POSIX Operating Systems. URL: http://www.easysw.com/~mike/serial/serial.html (дата обращения: 03.04.2012). См. также среднего качества перевод документа на русский язык.
  22. The Linux Cyrillic HOWTO (текст на русском языке). URL: http://www.opennet.ru/docs/HOWTO-RU/Cyrillic-HOWTO.html (дата обращения: 24.01.2012).
  23. TTY in raw mode // Programming with system calls and libraries. URL: http://uw714doc.sco.com/en/SDK_sysprog/_TTY_in_Raw_Mode.html (дата обращения: 02.04.2012).
  24. Volume One: Xlib Programming Manual for Version 11 of the X Window System. 1992. URL: http://www.niksula.hut.fi/~jkirma/books/xlib.pdf (дата обращения: 01.04.2012).
  25. Volume Two: Xlib Reference Manual for Version 11 of the X Window System edited by Adrian Nye. O'Reilly & Associates, Inc. URL: http://ia600204.us.archive.org/12/items/xlibrefmanv115ed02nyemiss/xlibrefmanv115ed02nyemiss.djvu (дата обращения: 01.04.2012).
  26. XTEST Extention Protocol. Version 2.2. X Consortium Standard. URL: http://www.x.org/docs/Xext/xtest.pdf (дата обращения: 01.04.2012).

Предыдущий раздел: Оглавление Следующий раздел:
Управление светодиодами клавиатуры   Программирование глифов и шрифтов