Estoy jugando con un guión que, entre otras cosas, enumera una lista de selección. Como en:
1) Elemento 1 # (resaltado) 2) Artículo 2 3) Elemento 3 # (seleccionado) 4) Artículo 4
- Cuando el usuario presiona los
down-arrow
siguientes elementos se resalta - Cuando el usuario presiona
up-arrow
los elementos anteriores se resalta - etc.
- Cuando el usuario presiona el
tab
elemento está seleccionado - Cuando el usuario presiona
shift+tab
todos los elementos están seleccionados / deseleccionados - Cuando el usuario presiona
ctrl+a
todos los elementos están seleccionados - ...
Esto funciona bien a partir del uso actual, que es mi uso personal donde mi propia configuración filtra la entrada.
La pregunta es cómo hacer que esto sea confiable en varios terminales.
Yo uso una solución algo hack para leer la 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
Y así.
Como se mencionó, la pregunta es cómo hacer que esto sea confiable en varios terminales: es decir, qué secuencias de bytes definen una clave específica. ¿Es factible incluso en bash?
Un pensamiento era usar uno tput
o infocmp
y filtrar por el resultado dado por eso. Sin embargo estoy en un obstáculo que hay que tanto tput
y infocmp
difieren de lo que en realidad leo cuando en realidad la pulsación de teclas. Lo mismo ocurre, por ejemplo, con 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)';
}
Las secuencias de rendimiento se leen como se define, por ejemplo linux
, pero no xterm
, que es lo que establece TERM
.
Por ejemplo, flecha izquierda:
tput
/infocmp
:\x1 O D
read
:\x1 [ D
¿Qué me estoy perdiendo?
dialog
variantes, o use un lenguaje conncurses
soporte decente (perl o python, por ejemplo, si desea seguir con los lenguajes de "scripting").zsh
tiene soporte para maldiciones incorporadas (en el módulo zsh / curses) además de consultas básicas de terminfo con su matrizechoti
incorporada y$terminfo
asociativa.Respuestas:
Lo que falta es que la mayoría de las descripciones de terminal (
linux
es una minoría aquí, debido al uso generalizado de cadenas codificadas.inputrc
) usan el modo de aplicación para teclas especiales. Eso hace que las teclas de cursor como se muestrantput
yinfocmp
difieran de lo que envía su terminal (sin inicializar). las aplicaciones curses siempre inicializan el terminal, y la base de datos del terminal se usa para ese propósito.dialog
tiene sus usos, pero no aborda directamente esta pregunta. Por otro lado, es engorroso (técnicamente factible , rara vez se hace ) proporcionar una solución de solo bash. Generalmente usamos otros idiomas para hacer esto.El problema con la lectura de claves especiales es que a menudo son múltiples bytes, incluidos caracteres incómodos como escapey ~. Puede hacer esto con bash, pero luego debe resolver el problema de determinar de forma portátil qué clave especial era esta.
dialog
ambos manejan la entrada de teclas especiales y se hacen cargo (temporalmente) de su pantalla. Si realmente quiere un programa simple de línea de comandos, no lo esdialog
.Aquí hay un programa simple en C que lee una clave especial y la imprime en forma imprimible (y portátil):
Suponiendo que se llamara a esto
tgetch
, lo usaría en su script de esta manera:Otras lecturas:
dialog
- Widgets de maldiciones guiadas por script (aplicación y biblioteca)fuente
inputrc
fue el culpable que estaba buscando. Hay que mirarlo un poco más. He considerado ir a Python o C, pero también resulta divertido piratearlo como un script bash. También intenté echar un vistazo a la fuente ncurses para ver si podía extraer los bits que necesitaba, pero después de bastante tiempo cavando la fuente, la dejé en hielo. El "proyecto" comenzó como un comando simple, luego se convirtió en un script interactivo simple y luego se extendió nuevamente. En algún lugar del camino, debería haber ido a otro idioma , pero me puse un poco terco (y como se mencionó, es divertido hackearlo en bash 2 :)/usr/share/doc/readline-common/inputrc.arrows
,. Como ya tengo una función genérica "read_key" que utilizo en todo el script, esperaba que hubiera una manera más fácil de definir las secuencias (en el script) de lo que realmente se presenta cuando se presiona una tecla. Es decir, similar a extraer definiciones deinfocmp
. Pero suponga que no, y que tenga que dejarlo como está o pasar a otro idioma. Un compromiso podría ser, por supuesto, usar su, agradable, C-snippet. Pero luego puedo escribir todo en C en su lugar. (Perdón por-lncurses
, etc.¿Has intentado usar
dialog
? Viene de manera estándar con la mayoría de las distribuciones de Linux y puede crear todo tipo de cuadros de diálogo basados en texto, incluidas las listas de verificación.Por ejemplo:
Obtendrás algo como esto:
Y la salida será:
(o los elementos que haya seleccionado).
man dialog
obtendrá información sobre los otros tipos de diálogos que puede crear y cómo personalizar la apariencia.fuente
Curses
,DBI
yDBD::SQLite
módulos. o sus equivalentes en pitón.