Estou brincando com um script que, entre outras coisas, lista uma lista de seleção. Como em:
1) Item 1 # (destacado) 2) Item 2 3) Item 3 # (selecionado) 4) Item 4
- Quando o usuário pressionar os
down-arrow
próximos itens, será destacado - Quando o usuário pressiona
up-arrow
os itens anteriores é destacado - etc.
- Quando o
tab
item pressionado pelo usuário é selecionado - Quando o usuário pressiona
shift+tab
todos os itens são selecionados / desmarcados - Quando o usuário pressiona
ctrl+a
todos os itens são selecionados - ...
Isso funciona bem como no uso atual, que é meu uso pessoal, onde as entradas são filtradas pela minha própria configuração.
A questão é como tornar isso confiável em vários terminais.
Eu uso uma solução um pouco hackish para ler a entrada:
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
E assim por diante.
Como mencionado, a questão é como tornar isso confiável em vários terminais: ou seja, quais seqüências de bytes definem uma chave específica. É mesmo possível no bash?
Um pensamento era usar um tput
ou infocmp
e filtrar pelo resultado dado por isso. Estou, no entanto, em uma senão lá como tanto tput
e infocmp
diferem do que eu realmente ler quando na verdade pressionando as teclas. O mesmo vale, por exemplo, usando C sobre 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)';
}
Sequências de rendimento lidas como definidas, por exemplo linux
, mas não xterm
, e é isso que é definido por TERM
.
Por exemplo, seta para a esquerda:
tput
/infocmp
:\x1 O D
read
:\x1 [ D
o que estou perdendo?
dialog
variantes ou use uma linguagem comncurses
suporte decente (perl ou python, por exemplo, se você quiser usar as linguagens de "script").zsh
possui suporte a curses integrados (no módulo zsh / curses), além da consulta básica de terminfo com sua matriz incorporadaechoti
e$terminfo
associativa.Respostas:
O que você está perdendo é que a maioria das descrições de terminal (que
linux
é minoria aqui, devido ao uso generalizado de cadeias codificadas.inputrc
) usa o modo de aplicativo para teclas especiais. Isso faz com que as teclas do cursor sejam mostradastput
einfocmp
sejam diferentes do que o seu terminal (não inicializado) envia. Os aplicativos amaldiçoados sempre inicializam o terminal e a base de dados do terminal é usada para esse fim.dialog
tem seus usos, mas não aborda diretamente essa questão. Por outro lado, é complicado (tecnicamente factível , raramente executado ) fornecer uma solução apenas para o bash. Geralmente usamos outros idiomas para fazer isso.O problema com a leitura de chaves especiais é que elas geralmente têm vários bytes, incluindo caracteres estranhos como escapee ~. Você pode fazer isso com o bash, mas precisará resolver o problema de determinar portabilidade que chave especial era essa.
dialog
ambos manipulam a entrada de teclas especiais e assumem (temporariamente) o seu monitor. Se você realmente deseja um programa simples de linha de comando, não édialog
.Aqui está um programa simples em C que lê uma chave especial e a imprime na forma imprimível (e portátil):
Supondo que isso fosse chamado
tgetch
, você o usaria em seu script assim:Leitura adicional:
dialog
- Widgets de maldições controladas por script (aplicativo e biblioteca)fonte
inputrc
era realmente o culpado que eu estava procurando. Tem que olhar um pouco mais. Já considerei usar python ou C, mas acho divertido invadir também como um script do bash. Também tentei dar uma olhada na fonte ncurses para ver se conseguia extrair os bits necessários - mas depois de algum tempo cavando a fonte, a deixei no gelo. O "projeto" começou como um comando simples, tornou-se um script interativo simples e depois estendeu-o novamente. Em algum lugar ao longo do caminho eu deveria ter ido outra língua , mas tem um teimoso bit (e como mencionado é divertido de se cortar em em bash 2 :)/usr/share/doc/readline-common/inputrc.arrows
. Como eu já tenho uma função genérica "read_key" que uso no script, esperava que houvesse uma maneira mais fácil de definir as seqüências (no script) do que é realmente apresentado quando uma tecla é pressionada. Ou seja, semelhante à extração de definições deinfocmp
. Mas acho que não, e você tem que deixá-lo como está ou seguir para outro idioma. Obviamente, um compromisso seria usar seu bom fragmento C. Mas então eu posso escrever a coisa toda em C. (Desculpe pelo-lncurses
etc.Você já tentou usar
dialog
? Ele é padrão na maioria das distribuições Linux e pode criar todos os tipos de caixas de diálogo baseadas em texto, incluindo listas de verificação.Por exemplo:
Você obterá algo como isto:
E a saída será:
(ou quaisquer itens que você selecionou).
man dialog
fornece informações sobre os outros tipos de caixas de diálogo que você pode criar e sobre como personalizar a aparência.fonte
Curses
,DBI
eDBD::SQLite
módulos. ou seus equivalentes python.