Я играю со сценарием, который, помимо прочего, перечисляет список выбора. Как в:
1) Пункт 1 # (выделено) 2) Пункт 2 3) Пункт 3 # (выбранный) 4) Пункт 4
- Когда пользователь нажимает
down-arrow
следующие пункты, выделяется - Когда пользователь нажимает
up-arrow
предыдущие элементы, выделяется - и т.п.
- Когда пользователь нажимает
tab
элемент - Когда пользователь нажимает
shift+tab
все элементы выбираются / отменяются - Когда пользователь нажимает
ctrl+a
все элементы выбраны - ...
Это отлично работает с текущим использованием, которое является моим личным использованием, когда вход фильтруется моей собственной настройкой.
Вопрос в том, как сделать это надежным на разных терминалах.
Я использую несколько хакерское решение для чтения ввода:
while read -rsn1 k # Read one key (first byte in key press)
do
case "$k" in
[[:graph:]])
# Normal input handling
;;
$'\x09') # TAB
# Routine for selecting current item
;;
$'\x7f') # Back-Space
# Routine for back-space
;;
$'\x01') # Ctrl+A
# Routine for ctrl+a
;;
...
$'\x1b') # ESC
read -rsn1 k
[ "$k" == "" ] && return # Esc-Key
[ "$k" == "[" ] && read -rsn1 k
[ "$k" == "O" ] && read -rsn1 k
case "$k" in
A) # Up
# Routine for handling arrow-up-key
;;
B) # Down
# Routine for handling arrow-down-key
;;
...
esac
read -rsn4 -t .1 # Try to flush out other sequences ...
esac
done
И так далее.
Как уже упоминалось, вопрос заключается в том, как сделать это надежным для различных терминалов: то есть, какие последовательности байтов определяют конкретный ключ. Это вообще возможно в bash?
Одна мысль состояла в том, чтобы использовать или tput
или infocmp
и фильтровать результат, данный этим. Я, однако, в затруднении, поскольку оба tput
и infocmp
отличаюсь от того, что я фактически читаю, фактически нажимая клавиши. То же самое касается, например, использования C над Bash.
for t in $(find /lib/terminfo -type f -printf "%f\n"); {
printf "%s\n" "$t:";
infocmp -L1 $t | grep -E 'key_(left|right|up|down|home|end)';
}
Последовательности доходности читаются так, как определено, например linux
, но нет xterm
, что устанавливается TERM
.
Например, стрелка влево:
tput
/infocmp
:\x1 O D
read
:\x1 [ D
Что мне не хватает?
dialog
вариантов или используйте язык с достойнойncurses
поддержкой (например, perl или python, если вы хотите придерживаться языков «сценариев»).zsh
имеется встроенная поддержка curses (в модуле zsh / curses) в дополнение к базовым запросам terminfo с егоechoti
встроенным и$terminfo
ассоциативным массивом.Ответы:
Чего вам не хватает, так это того, что большинство описаний терминалов (
linux
здесь меньшинство из-за повсеместного использования жестко запрограммированных строк.inputrc
) используют режим приложения для специальных клавиш. Это делает клавиши курсора, как показано,tput
иinfocmp
отличается от того, что посылает ваш (неинициализированный) терминал. приложения curses всегда инициализируют терминал, и для этого используется база данных терминала .dialog
имеет свое использование, но не имеет прямого отношения к этому вопросу. С другой стороны, это громоздко (технически выполнимо , редко делается ), чтобы обеспечить решение только для bash. Обычно мы используем другие языки для этого.Проблема с чтением специальных клавиш состоит в том, что они часто состоят из нескольких байтов, включая такие неудобные символы, как escapeи ~. Вы можете сделать это с помощью bash, но тогда вам придется решить проблему переносного определения, каким специальным ключом это было.
dialog
оба обрабатывают ввод специальных клавиш и принимают (временно) ваш дисплей. Если вы действительно хотите простую программу командной строки, это не такdialog
.Вот простая программа на C, которая читает специальный ключ и печатает его в печатной (и переносимой) форме:
Предположим, это было вызвано
tgetch
, вы бы использовали его в своем скрипте так:Дальнейшее чтение:
dialog
- скриптовые виджеты виджетов (приложение и библиотека)источник
inputrc
действительно был виновником, которого я искал. Надо посмотреть на это еще немного. Рассматривали переход на python или C, но было бы забавно взломать и скрипт bash. Я также попытался взглянуть на источник ncurses, чтобы узнать, смогу ли я извлечь нужные мне биты, но, по прошествии некоторого времени, копая источник, я оставил его на льду. «Проект» начали как простая команду, а затем стал простым интерактивным сценарием, а затем распространяется на это снова. Где-то по пути я должен был пойти другим языком , но стал немного упрямым (и, как уже упоминалось, в bash 2 интересно взломать :)/usr/share/doc/readline-common/inputrc.arrows
. Поскольку у меня уже есть универсальная функция «read_key», которую я использую в сценарии, я надеялся, что существует более простой способ определить последовательности (в сценарии) из того, что фактически отображается при нажатии клавиши. Т.е. похоже на извлечение определений изinfocmp
. Но не угадайте и либо оставьте все как есть, либо переходите на другой язык. Конечно, компромиссом может быть использование вашего красивого C-сниппета. Но тогда я могу написать все это на С вместо этого. (Извините за превышение.)-lncurses
т. Д.Вы пробовали использовать
dialog
? Он входит в стандартную комплектацию большинства дистрибутивов Linux и может создавать все виды текстовых диалогов, включая контрольные списки.Например:
Вы получите что-то вроде этого:
И вывод будет:
(или какие предметы вы выбрали).
man dialog
даст вам информацию о других видах диалогов, которые вы можете создать, и о том, как настроить внешний вид.источник
Curses
,DBI
иDBD::SQLite
модулей. или их эквиваленты Python.