¿Cómo puedo capturar teclas individuales en una aplicación de consola Unix sin bloquear?
Pregunta
Tengo un servidor TCP muy simple escrito en C. Se ejecuta indefinidamente, esperando conexiones. En Windows, uso select
para verificar la actividad en el zócalo, y si no hay ninguna, tengo el siguiente código que me permite salir presionando 'q' en el teclado:
if( kbhit() ) {
char c = getch();
if( c == 'q' ) break;
}
Esto no funciona en Unix, ya que kbhit
no existe y getch
funciona de manera diferente. Encontré algunos código de muestra usa tcsetattr
para cambiar la configuración del terminal y permitir la entrada carácter por carácter. Después de llamar a la función init, abro / dev / stdin (con O_NONBLOCK
) y leo un carácter, pero read (f, & amp; c, 1)
bloquea hasta que un carácter es golpeado.
Supongo que podría generar un hilo separado y hacer que lo espere indefinidamente y luego señalar el primer hilo si el usuario toca 'q', pero eso parece un poco pesado. ¿Seguramente hay una manera más fácil?
Solución
Agregue stdin a su lista de identificadores seleccionados, y si tiene datos, llame a read para leer un carácter de él.
Otros consejos
Más bien, agregue " f " de tu
read( f, &c, 1 )
para seleccionar la llamada. Cuando f está listo para leer, se ha presionado un carácter y read () no se bloqueará.
En Unix, ya sea en la consola del sistema o en una ventana de terminal X, la E / S del teclado pasa por un terminal virtual. Device / dev / tty es la forma habitual, en estos días, de acceder al terminal de control de un proceso. Las manipulaciones de dispositivos que no sean abrir / cerrar / leer / escribir son manejadas por la llamada al sistema ioctl (2) para ese dispositivo específico. La idea general de lo que quieres hacer es
Abra el terminal de control (que puede o no ser estándar)
Cambie el modo de funcionamiento en ese terminal para que regrese sin esperar una línea completa de entrada (que es el valor predeterminado normal)
Continúe con el resto de su programa, sabiendo que las lecturas de ese terminal (que pueden ser estándar) pueden devolver líneas parciales o incluso cero caracteres sin que sea una condición de error o terminación.
Una respuesta detallada sobre cómo hacer el segundo paso se encuentra en las preguntas frecuentes sobre programación en C . También señalan que esta es una pregunta del sistema operativo, no una pregunta de idioma. Ofrecen nueve posibilidades, pero las tres principales relevantes para esta pregunta son
- Usa la biblioteca curses (3)
- Sistemas de estilo BSD antiguos, use sgttyb para configurar CBREAK o RAW
- Posix o sistemas de estilo System V anteriores, utilice TCGETAW / TCSETAW para establecer c_cc [VMIN] en 1 y c_cc [VTIME] en 0.
Seguir un par de referencias en las preguntas frecuentes de C podría llevar a esta página de fragmentos de código kbhit .