c++ - Usando kbhit() y getch() en Linux
conio (4)
El cómo ncurses citado anteriormente puede ser útil. Aquí hay un ejemplo que ilustra cómo ncurses podría usarse como el ejemplo conio:
#include <ncurses.h>
int
main()
{
initscr();
cbreak();
noecho();
scrollok(stdscr, TRUE);
nodelay(stdscr, TRUE);
while (true) {
if (getch() == ''g'') {
printw("You pressed G/n");
}
napms(500);
printw("Running/n");
}
}
Tenga en cuenta que con ncurses, el encabezado
iostream
no se utiliza.
Esto se debe a que mezclar stdio con ncurses puede tener resultados inesperados.
ncurses, por cierto, define
TRUE
y
FALSE
.
Un ncurses configurado correctamente utilizará el mismo tipo de datos para ncurses ''
bool
que el compilador de C ++ utilizado para configurar ncurses.
En Windows, tengo el siguiente código para buscar entradas sin interrumpir el ciclo:
#include <conio.h>
#include <Windows.h>
#include <iostream>
int main()
{
while (true)
{
if (_kbhit())
{
if (_getch() == ''g'')
{
std::cout << "You pressed G" << std::endl;
}
}
Sleep(500);
std::cout << "Running" << std::endl;
}
}
Sin embargo, al ver que no hay
conio.h
, ¿cuál es la forma más sencilla de lograr esto mismo en Linux?
Si bien el uso de ncurses es funcionalmente equivalente a la API Turbo C "conio.h", una solución más completa es utilizar una implementación de conio, como se puede encontrar aquí .
Lo descarga y lo usa en su programa para una implementación muy completa de la interfaz conio, en Linux. (O OSX.) Escrito por Ron Burkey.
Si su Linux no tiene
conio.h
que admita
kbhit()
, puede buscar
aquí el código de Morgan Mattews
para proporcionar la funcionalidad
kbhit()
de manera compatible con cualquier sistema compatible con POSIX.
Como el truco desactiva el almacenamiento en búfer a nivel de termios, también debería resolver el problema
getchar()
como se demuestra
here
.
Una solución compacta basada en la respuesta de Christophe es
#include <sys/ioctl.h>
#include <termios.h>
bool kbhit()
{
termios term;
tcgetattr(0, &term);
termios term2 = term;
term2.c_lflag &= ~ICANON;
tcsetattr(0, TCSANOW, &term2);
int byteswaiting;
ioctl(0, FIONREAD, &byteswaiting);
tcsetattr(0, TCSANOW, &term);
return byteswaiting > 0;
}
A diferencia de esa respuesta, esto no dejará el terminal en un estado extraño después de que el programa haya salido. Sin embargo, todavía deja los caracteres sentados en el búfer de entrada, por lo que la tecla que se presionó aparecerá desagradablemente en la siguiente línea de solicitud.
Una solución diferente que soluciona este problema es
void enable_raw_mode()
{
termios term;
tcgetattr(0, &term);
term.c_lflag &= ~(ICANON | ECHO); // Disable echo as well
tcsetattr(0, TCSANOW, &term);
}
void disable_raw_mode()
{
termios term;
tcgetattr(0, &term);
term.c_lflag |= ICANON | ECHO;
tcsetattr(0, TCSANOW, &term);
}
bool kbhit()
{
int byteswaiting;
ioctl(0, FIONREAD, &byteswaiting);
return byteswaiting > 0;
}
El uso es el siguiente
enable_raw_mode();
// ...
if (kbhit()) ...
// ...
disable_raw_mode();
tcflush(0, TCIFLUSH); // Clear stdin to prevent characters appearing on prompt
Ahora los caracteres escritos entre la ejecución de la primera y la última línea no aparecerán en el terminal. Sin embargo, si sale con Ctrl + C, el terminal queda en un estado extraño. (Suspiro)