Приведенный сценарий подходит для обработки в терминале комбинаций клавиш, генерирующих управляющие последовательности. Например, во многих терминалах клавиша <— генерирует последовательность из трех символов: Escape, O и D. Эти символы передаются с небольшими промежутками времени. Приложения, их обрабатывающие, должны отличать такой случай от ситуации, когда пользователь медленно вводит каждый из указанных символов отдельно. Для этого можно выполнить операцию read() с небольшим побайтовым временным интервалом, например 0,2 секунды. Такой подход применяется в командном режиме некоторых версий редактора vi (в зависимости от продолжительности времени ожидания нажатие клавиши <— можно эмулировать с помощью быстрого ввода вышеупомянутой последовательности символов).
Изменение и восстановление значений MIN и TIME с учетом портируемости
Для совместимости с отдельными старыми реализациями UNIX стандарт SUSv3 допускает использование одних и тех же значений для констант VMIN/VTIME и VEOF/VEOL, из-за чего могут совпадать соответствующие элементы массива c_cc в структуре termios (в Linux значения указанных констант отличаются). Это становится возможным благодаря тому, что VEOF и VEOL не применяются в неканоническом режиме. Значения констант VMIN и VEOF могут совпадать, в связи с чем нужно соблюдать осторожность при написании программ, которые входят в неканонический режим, инициализируют MIN (обычно с помощью значения 1) и позже возвращаются в канонический режим. На последнем этапе код символа EOF (ASCII 4 или Ctrl+D) больше не будет стандартным. Для сохранения портируемости программы перед входом в неканонический режим параметры структуры termios следует сохранить и затем использовать их, чтобы переключиться обратно.
58.6.3. Режимы с обработкой, без обработки и cbreak
В седьмой редакции системы UNIX (а также в ранних версиях BSD) драйвер терминала мог принимать ввод в трех режимах:
Режим с обработкой фактически представлял собой канонический режим, в котором по умолчанию включена интерпретация всех специальных символов (то есть интерпретация CR, NL и EOF; редактирование текущей строки; обработка символов, генерирующих сигналы; ICRNL, OCRNL и т. д.).
Режим без обработки, напротив, являлся аналогом неканонического; в нем была выключена любая обработка ввода и вывода (он использовался приложениями, которым нужно было гарантировать, что драйвер терминала не вносит никаких изменений в данные, передающиеся через последовательный порт).
Режим cbreak служил чем-то средним между двумя предыдущими. Ввод был неканоническим, однако символы, генерирующие сигналы, интерпретировались; к тому же входящие и исходящие данные могли подвергаться различным трансформациям (в зависимости от установки отдельных флагов). Режим cbreak не отключал эхо-контроль по умолчанию, однако это обычно делали приложения, которые его использовали. Он был востребован в программах, работающих с экраном (таких как less), позволявших вводить текст посимвольно, но все же требовавших обработки ряда специальных последовательностей, таких как INTR, QUIT и SUSP.
Таблица 58.3. Различия между тремя режимами терминала: с обработкой, без обработки и cbreak
Возможность
Режим
С обработкой
cbreak
Без обработки
Ввод доступен
Построчно
Посимвольно
Посимвольно
Окончание строки
Да
Нет
Нет
Интерпретация символов, генерирующих сигналы
Да
Да
Нет
Интерпретация символов START/STOP
Да
Да
Нет
Интерпретация других специальных символов
Да
Нет
Нет
Выполнение дополнительной обработки ввода
Да
Да
Нет
Выполнение дополнительной обработки вывода
Да
Да
Нет
Эхо-контроль ввода
Да
Возможно
Нет
В седьмой редакции системы UNIX и в оригинальной версии BSD драйвер терминала позволял переключаться в режим без обработки или cbreak, изменяя всего лишь один бит (RAW или CBREAK) в соответствующей структуре данных. С переходом к POSIX-интерфейсу termios (который поддерживается всеми современными реализациями UNIX) такой способ переключения больше недоступен, а приложения, эмулирующие указанные режимы, должны явно изменять необходимые поля. В листинге 58.3 представлены две функции, ttySetCbreak() и ttySetRaw(), реализующие аналоги этих двух режимов терминала.
Приложения, использующие библиотеку ncurses, могут выполнять аналогичные действия с помощью функций cbreak() и raw().