Что такое необработанный режим ввода с клавиатуры?

Давайте посмотрим на пример с некоторым тщательно созданным входным текстом:

text=' hello  world\
foo\bar'

Это - две строки, первое начало с пространства и окончание обратной косой чертой. Во-первых, давайте посмотрим на то, что происходит без любых мер предосторожности вокруг read (но использование printf '%s\n' "$text" тщательно распечатать $text без любого риска расширения). (Ниже, $ ‌ приглашение оболочки.)

$ printf '%s\n' "$text" |
  while read line; do printf '%s\n' "[$line]"; done
[hello worldfoobar]

read съел обратные косые черты: новая строка обратной косой черты заставляет новую строку быть проигнорированной, и обратная косая черта - что-либо игнорирует ту первую обратную косую черту. Для предотвращения обратных косых черт, которые рассматривают особенно, мы используем read -r.

$ printf '%s\n' "$text" |
  while read -r line; do printf '%s\n' "[$line]"; done
[hello  world\]
[foo\bar]

Это лучше, у нас есть две строки как ожидалось. Эти две строки почти содержат желаемое содержание: двойной интервал между hello и world был сохранен, потому что это в line переменная. С другой стороны, начальное пространство было съедено. Поэтому read отбрасываются чтения столько слов, сколько Вы передаете его переменные, за исключением того, что последняя переменная содержит остальную часть строки — но это все еще запускается с первого слова, т.е. начальных пробелов.

Так, для чтения каждой строки буквально, мы должны удостовериться, что никакое разделение слова не продолжается. Мы делаем это путем установки IFS переменная к пустому значению.

$ printf '%s\n' "$text" |
  while IFS= read -r line; do printf '%s\n' "[$line]"; done
[ hello  world\]
[foo\bar]

Отметьте, как мы устанавливаем IFS специально для продолжительности read встроенный. IFS= read -r line устанавливает переменную среды IFS (к пустому значению) специально для выполнения read. Это - экземпляр общего простого синтаксиса команды: (возможно пустой) последовательность переменных присвоений, сопровождаемых названием команды и его аргументами (также, можно добавить перенаправления в любой точке). С тех пор read встроенное, переменная никогда на самом деле заканчивается в среде внешнего процесса; тем не менее, значение $IFS то, что мы присваиваем там пока read выполняет ¹. Отметьте это read не встроенное специальное предложение, таким образом, присвоение действительно только продолжается в свой период.

Таким образом мы заботимся для не изменения значения IFS для других инструкций, которые могут полагаться на него. Этот код будет работать независимо от того, что установил окружающий код IFS к первоначально, и это не доставит неприятностей, если код в цикле будет полагаться IFS.

Контраст с этим фрагментом кода, который ищет файлы в разделенном от двоеточия пути. Список имен файлов прочитан из файла, одно имя файла на строку.

IFS=":"; set -f
while IFS= read -r name; do
  for dir in $PATH; do
    ## At this point, "$IFS" is still ":"
    if [ -e "$dir/$name" ]; then echo "$dir/$name"; fi
  done
done 

Если цикл был while IFS=; read -r name; do …, затем for dir in $PATH не разделил бы $PATH в разделенные от двоеточия компоненты. Если код был IFS=; while read …, это было бы еще более очевидно это IFS не установлен на : в теле цикла.

Конечно, было бы возможно восстановить значение IFS после выполнения read. Но это потребовало бы знания предыдущего значения, которое является дополнительным усилием. IFS= read простой путь (и, удобно, также самый короткий путь).

¹ И, если read прерван захваченным сигналом, возможно в то время как прерывание выполняется — это не указано POSIX и зависит от оболочки на практике.

27
18.10.2017, 20:06
2 ответа

При нажатии клавиши на клавиатуре она отправляет цифровой код на компьютер, названный скэн-кодом. Скэн-код говорит компьютер, какая клавиша была нажата; например, на типичной американской клавиатуре, ключ отправляет скэн-код 30 при нажатии его (и 158 при выпуске его). Драйвер клавиатуры сообщает об этих кодах непосредственно приложениям, когда клавиатура находится в режиме без предварительной обработки (“сырые данные” означают необработанный, непосредственно-клавиатура). Несколько программ используют режим без предварительной обработки и делают их собственную обработку клавиатуры; X-сервер является самым видным.

Большинство программ ожидает, что при нажатии клавиши программа читает символ a (ASCII 97) и это, когда Вы нажимаете Shift+A чтения программы A (ASCII 65), и когда Вы нажимаете Ctrl+A программа, читает Ctrl+A символ (ASCII 1). Ключи, которые не имеют связанных символов, отправляют escape-последовательности, например. \e[A для Левого, где \e символ ESC (ASCII 27). Драйвер клавиатуры выполняет этот перевод, когда клавиатура находится в режиме ASCII, также названный режимом XLATE (короткий для “переводят”). Режим XLATE позволяет приложениям сделать ввод символов, за счет не наличия доступа к таким нюансам как “Клавиша сдвига влево, нажатая” или Ctrl+Shift+A в отличие от Ctrl+A.

kbd_mode позволяет Вам переключиться между режимами и показывает текущий режим, если Вы вызываете его без какого-либо аргумента.

Волшебные сочетания клавиш SysRq предназначены для восстановления с различных противных ситуаций. Одно из сочетаний клавиш Alt+SysRq+K закрыть все программы на текущей виртуальной консоли; если та программа поместит клавиатуру в режим без предварительной обработки, то Вы не сможете ввести при приглашении ко входу в систему (который будет часто появляться, в зависимости от Вашей конфигурации системы). Нажатие Alt+SysRq+R восстанавливает обычное (вне X) режим ASCII, где можно ввести символы.

23
27.01.2020, 19:39

Можно определить, какой тип кода клавиатура отправляет. Это сделано через режим ввода с клавиатуры. Можно изменить режим клавиатуры с kbd_mode.

Это опции из страницы справочника:

   -s: scancode mode (RAW),
   -k: keycode mode (MEDIUMRAW),
   -a: ASCII mode (XLATE),
   -u: UTF-8 mode (UNICODE).

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

9
27.01.2020, 19:39

Теги

Похожие вопросы