¿Cómo simular "Presione cualquier tecla para continuar?"

87

Estoy tratando de escribir un programa en C ++ en el que cuando el usuario ingrese cualquier carácter desde el teclado, debería moverse a la siguiente línea de código.

Aquí está mi código:

char c;

cin>>c;

cout<<"Something"<<endl;

pero esto no funciona, porque solo se mueve a la siguiente línea cuando ingreso algún carácter y luego presiono ENTER.

O

Si uso esto

cin.get() or cin.get(c)

se mueve a la siguiente línea de instrucción cuando presiono Enter.

Pero quería que se moviera a la siguiente línea en cualquier tecla presionada en el teclado, ¿cómo se puede hacer esto?

itsaboutcode
fuente
Hasta donde yo sé, el problema es que su shell está esperando que presione ENTER o EOF y luego dejará que su programa se encargue de lo que esté en el búfer, o algo así. Quizás alguien con más conocimientos pueda dar una explicación real. Pero creo que no es tan fácil como parece.
Lucas
7
Con mucho, la forma más fácil de manejar esto, y la única forma portátil, es cambiar su mensaje de "Presione cualquier tecla para continuar" a "Presione la tecla Enter para continuar".
Rob Mayoff
@Lucas - Estoy usando mac con xcode.
trata del código
@Lucas: No es el shell, es el programa en sí.
Keith Thompson
@KeithThompson: Esto fue hace más de dos años, pero creo que estaba tratando de dejar claro que la cola de entrada no es manejada por el proceso del usuario sino dentro del Kernel.
Lucas

Respuestas:

64

En Windows:

system("pause");

y en Mac y Linux:

system("read");

mostrará "Presione cualquier tecla para continuar ..." y obviamente, espere a que se presione cualquier tecla. Espero que eso sea lo que quisiste decir

MrMartin
fuente
5
systemllama programa externo. ¡No tiene que llamar a un programa externo para esperar ninguna tecla! Es como llamar a otra persona para que encienda su computadora cuando está sentado frente a ella; esta es una solución lenta.
GingerPlusPlus
8
Es cierto, ¡pero solo tiene una línea! A veces simplemente no vale la pena el esfuerzo de salvar la computadora algunos ciclos ...
Elliot Cameron
14
Olvídese de la lentitud, llama al primer programa llamado "pausa" que encuentra en PATH y le da el nivel de privilegio del programa que llama. Incluso si eres un estudiante que está probando tu propio código, sigue siendo un riesgo de seguridad masivo.
Anne Quinn
6
@XDfaceme - pause es un programa real que system () pide a Windows que ejecute. Sin embargo, si hay otro programa llamado 'pausa' y Windows encuentra ese programa primero, lo ejecutará en su lugar. Supongo que podría haber exagerado un poco la importancia, pero aún es más fácil usar cin.get () y presionar regresar para pausar / reanudar un programa
Anne Quinn
2
No soy fanático de los absolutos. Hacer una declaración general de que el sistema ("pausa") es un riesgo para la seguridad y que es malo incluso cuando probar su propio código es hacer las cosas fuera de proporción aquí. cin.get () podría ser la solución correcta, pero no resuelve la pregunta que se estaba haciendo ... cin.get () solo responde después de presionar "enter" o "return". La pregunta específicamente era responder a cualquier pulsación de tecla. system ("pause") hace exactamente eso. En primer lugar, el único lugar donde he visto esto útil es en una clase de desarrollo al depurar desde Visual Studio, así que creo que el sistema ("pausa") funciona
Gregor
52

Si está en Windows, puede usar el kbhit()que forma parte de la biblioteca de tiempo de ejecución de Microsoft. Si está en Linux, puede implementarlo kbhitasí ( fuente ):

#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>

int kbhit(void)
{
  struct termios oldt, newt;
  int ch;
  int oldf;

  tcgetattr(STDIN_FILENO, &oldt);
  newt = oldt;
  newt.c_lflag &= ~(ICANON | ECHO);
  tcsetattr(STDIN_FILENO, TCSANOW, &newt);
  oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
  fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);

  ch = getchar();

  tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
  fcntl(STDIN_FILENO, F_SETFL, oldf);

  if(ch != EOF)
  {
    ungetc(ch, stdin);
    return 1;
  }

  return 0;
}

Actualización: la función anterior funciona en OS X (al menos, en OS X 10.5.8 - Leopard, por lo que esperaría que funcione en versiones más recientes de OS X). Esta esencia se puede guardar kbhit.cy compilar tanto en Linux como en OS X con

gcc -o kbhit kbhit.c

Cuando se ejecuta con

./kbhit

Le solicita que presione una tecla y sale cuando presiona una tecla (no se limita a Enter o teclas imprimibles).

@Johnsyweb : explique lo que quiere decir con "respuesta canónica detallada" y "todas las preocupaciones". Además, vuelva a ser "multiplataforma": con esta implementación kbhit(), puede tener la misma funcionalidad en un programa C ++ en Linux / Unix / OS X / Windows. ¿A qué otras plataformas se está refiriendo?

Actualización adicional para @Johnsyweb: las aplicaciones C ++ no viven en un entorno C ++ herméticamente sellado. Una gran razón del éxito de C ++ es la interoperabilidad con C. Todas las plataformas principales se implementan con interfaces C (incluso si la implementación interna usa C ++), por lo que su discurso de "legado" parece fuera de lugar. Además, como estamos hablando de una sola función, ¿por qué necesita C ++ para esto ("C con clases")? Como señalé, puede escribir en C ++ y acceder a esta funcionalidad fácilmente, y es poco probable que a los usuarios de su aplicación les importe cómo la implementó.

Vinay Sajip
fuente
Es una pena que no haya una forma estándar de manejar la consola, siempre tienes que usar algo de magia del sistema operativo
Vargas
1
@Johnsyweb: Gracias usted , pero su ejemplo muestra características que me deprimen sobre C ++. Su kbhit()función declara una terminal_settingsvariable en una línea que parece no hacer nada y, sin embargo, lo hace todo. Algunos pueden pensar que es genial, pero lo encuentro oscuro hasta el punto de que no se puede leer.
Vinay Sajip
1
@VinaySajip: Mi implementación usa RAII , que es uno de los modismos más importantes en C ++. Si bien no es estrictamente necesario en este ejemplo, me ha parecido un buen hábito adoptar cuando desea guardar algún estado y restaurarlo.
Johnsyweb
4
@Johnsyweb: Soy consciente de RAII y de los beneficios que trae, yo mismo soy un experto en C ++. Mi punto sigue siendo: no hay una conexión clara entre la declaración y lo que está haciendo detrás de escena. Si bien podría estar usando modismos brillantes de C ++ en lugar de C simple y antiguo, mi opinión es que hace poco para iluminar y mucho para ocultar lo que está sucediendo. Esto no está dirigido a usted personalmente de ninguna manera, es solo una opinión sobre cómo se puede usar C ++ para crear código que es innecesariamente difícil de entender. Saldré de mi tribuna ahora ', dijo Nuff.
Vinay Sajip
2
Es agradable y todo, pero aún atrapa cualquier basura anterior en el stdin :-)
Tiago
8

No existe una solución completamente portátil.

La pregunta 19.1 de las preguntas frecuentes de comp.lang.c cubre esto con cierta profundidad, con soluciones para Windows, sistemas similares a Unix e incluso MS-DOS y VMS.

Un resumen rápido e incompleto:

  • Puede utilizar la cursesbiblioteca; llamada cbreak()seguida de getch()(no confundir con la getch()función específica de Windows ). Tenga en cuenta que cursesgeneralmente toma el control del terminal, por lo que es probable que esto sea excesivo.
  • Es posible que pueda utilizar ioctl()para manipular la configuración del terminal.
  • En sistemas compatibles con POSIX tcgetattr()y tcsetattr()puede ser una mejor solución.
  • En Unix, puede utilizar system()para invocar el sttycomando.
  • En MS-DOS, puede usar getch()o getche().
  • En VMS (ahora llamado OpenVMS), las SMG$rutinas de Gestión de pantalla ( ) pueden funcionar.

Todas estas soluciones C deberían funcionar igualmente bien en C ++; No conozco ninguna solución específica de C ++.

Keith Thompson
fuente
Todas estas soluciones multiplataforma podrían hacer que alguien escriba una función que se implemente para hacer lo correcto dependiendo de su plataforma con muchos preprocesadores para determinar cuál es esa plataforma.
CashCow
6

Para lograr esta funcionalidad, puede usar la biblioteca ncurses que se implementó tanto en Windows como en Linux (y MacOS, hasta donde yo sé).

Kirill V. Lyadvinsky
fuente
Bueno, esta es una especie de asignación en la que no puedo usar ninguna biblioteca externa, etc., así que solo tengo que permanecer en el "contexto del capítulo" lox.
itsaboutcode
2
Entonces, la única opción es implementar la funcionalidad necesaria para cada sistema operativo que planea admitir.
Kirill V. Lyadvinsky
1
ncurses es más o menos un cliente VT200. Un poco exagerado para simplemente leer desde el TTY.
greyfade
5

En Windows, este programa corto logra el objetivo: getchpausa la consola hasta que se presiona una tecla ( https://www.geeksforgeeks.org/difference-getchar-getch-getc-getche/ )

#include<iostream.h>
#include<conio.h>

using namespace std;

void  check()
{
    char chk; int j;
    cout<<"\n\nPress any key to continue...";
    chk=getch();
    j=chk;
    for(int i=1;i<=256;i++)
      if(i==j) break;
    clrscr();
}

void main()
{
    clrscr();
    check();
    cout<<"\n\nIt works!";
    getch();
}

Cabe señalar que getch no forma parte de la biblioteca estándar.

BoldX
fuente
1
Este programa muy simple. Es muy fácil de entender
BoldX
1
Explique en qué getch()se diferencia de cin.geto cin>>, tal vez, algún enlace a la documentación
user2622016
1
conio solo está disponible en Windows
Andrew Wolfe
4

Investigué lo que estás tratando de lograr, porque recuerdo que quería hacer lo mismo. Inspirado por Vinay , escribí algo que funciona para mí y lo entiendo. Pero no soy un experto, así que tenga cuidado.

No sé cómo sabe Vinay que estás usando Mac OS X. Pero debería funcionar así con la mayoría de los sistemas operativos tipo Unix. Realmente útil como recurso es opengroup.org

Asegúrese de vaciar el búfer antes de usar la función.

#include <stdio.h>
#include <termios.h>        //termios, TCSANOW, ECHO, ICANON
#include <unistd.h>     //STDIN_FILENO


void pressKey()
{
    //the struct termios stores all kinds of flags which can manipulate the I/O Interface
    //I have an old one to save the old settings and a new 
    static struct termios oldt, newt;
    printf("Press key to continue....\n");

    //tcgetattr gets the parameters of the current terminal
    //STDIN_FILENO will tell tcgetattr that it should write the settings
    // of stdin to oldt
    tcgetattr( STDIN_FILENO, &oldt);
    //now the settings will be copied 
    newt = oldt;

    //two of the c_lflag will be turned off
    //ECHO which is responsible for displaying the input of the user in the terminal
    //ICANON is the essential one! Normally this takes care that one line at a time will be processed
    //that means it will return if it sees a "\n" or an EOF or an EOL
    newt.c_lflag &= ~(ICANON | ECHO );      

    //Those new settings will be set to STDIN
    //TCSANOW tells tcsetattr to change attributes immediately. 
    tcsetattr( STDIN_FILENO, TCSANOW, &newt);

    //now the char wil be requested
    getchar();

    //the old settings will be written back to STDIN
    tcsetattr( STDIN_FILENO, TCSANOW, &oldt);

}


int main(void)
{
  pressKey();
  printf("END\n");
  return 0;
}

O_NONBLOCK también parece ser una bandera importante, pero no cambió nada para mí.

Agradezco que personas con un conocimiento más profundo comenten sobre esto y den algún consejo.

Lucas
fuente
O_NONBLOCK debe establecerse porque sin él, getchar () (que llama a read ()) bloqueará la espera de entrada. La solución kbhit () le dice si se presiona una tecla, sin esperar; puede usarlo en un ciclo de espera o para cualquier otro propósito, por lo que es una solución más general. Una solución sin O_NONBLOCK esperará hasta que se presione una tecla; está bien para esta pregunta, pero generalmente es menos útil.
Vinay Sajip
4

Puede utilizar la función _getch específica de Microsoft :

#include <iostream>
#include <conio.h>
// ...
// ...
// ...
cout << "Press any key to continue..." << endl;
_getch();
cout << "Something" << endl;
Salman A
fuente
3

Esto funciona en una plataforma Windows: usa los registros del microprocesador directamente y se puede usar para verificar la pulsación de teclas o el botón del mouse

    #include<stdio.h>
    #include<conio.h>
    #include<dos.h>
    void main()
    {
     clrscr();
     union REGS in,out;
     in.h.ah=0x00;
     printf("Press any key : ");

     int86(0x16,&in,&out);
     printf("Ascii : %d\n",out.h.al);
     char ch = out.h.al;
     printf("Charcter Pressed : %c",&ch);
     printf("Scan code : %d",out.h.ah);
     getch();
    }
Rohit Vipin Mathews
fuente
3

Si usa Visual Studio 2012 o una versión anterior, use la getch()función; si usa Visual Studio 2013 o una versión más reciente, use _getch(). Tendrás que usar #include <conio.h>. Ejemplo:

#include <iostream>
#include <conio.h>

int main()
{
   std::cout << "Press any key to continue. . .\n";
   _getch(); //Or getch()
}
John Doe
fuente
1

Puede utilizar la rutina getchar .

Desde el enlace de arriba:

/* getchar example : typewriter */
#include <stdio.h>

int main ()
{
  char c;
  puts ("Enter text. Include a dot ('.') in a sentence to exit:");
  do {
    c=getchar();
    putchar (c);
  } while (c != '.');
  return 0;
}
Nick Dandoulakis
fuente
3
No creo que esto sea lo que pedía el OP, si lo entiendo correctamente. Aún debe presionar ENTER para llenar el búfer antes de que getchar () pueda leerlo.
Lucas
0

También puede usar getch () de conio.h. Así:

...includes, defines etc
void main()
{
//operator
getch(); //now this function is waiting for any key press. When you have pressed its     just     //finish and next line of code will be called
}

Entonces, debido a que UNIX no tiene conio.h, podemos simular getch () mediante este código (pero este código ya está escrito por Vinary, mi error):

#include <stdio.h>
#include <termios.h>
#include <unistd.h>

int mygetch( ) {
  struct termios oldt,
             newt;
  int            ch;
  tcgetattr( STDIN_FILENO, &oldt );
  newt = oldt;
  newt.c_lflag &= ~( ICANON | ECHO );
  tcsetattr( STDIN_FILENO, TCSANOW, &newt );
  ch = getchar();
  tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
  return ch;
}
m9_psy
fuente
-1

Si busca la función kbhit () en MSDN ahora, dice que la función está obsoleta. Utilice _kbhit () en su lugar.

#include <conio.h>
int main()
{
    _kbhit();
    return 0;
}
BG4WCE
fuente
-1
#include <iostream>
using namespace std;

int main () {
    bool boolean;
    boolean = true;

    if (boolean == true) {

        cout << "press any key to continue";
        cin >> boolean;

    }
    return 0;
}
Jeffery
fuente
-4

Solo usa el system("pause");comando.

Todas las demás respuestas complican el problema.

Chad
fuente