Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: jmhr98 en 17 Agosto 2018, 22:07 pm



Título: ¿Parar un bucle for pulsando una tecla?
Publicado por: jmhr98 en 17 Agosto 2018, 22:07 pm
¿Alguien sabe alguna forma de hacerlo? He usado un condicional if en el ciclo for. De la forma: if(cin.get()=='d') Return 0; pero el bucle se queda esperando a que yo pulse alguna otra tecla. Es decir, lo que quiero es que el bucle se vaya ejecutando y cuando yo pulse la d, se termine el programa. No que se quede esperando a que yo pulse la d u otra para funcionar y volver al mismo punto de pedirme otra vez que introduzca otra tecla. Gracias


Título: Re: ¿Parar un bucle for pulsando una tecla?
Publicado por: MAFUS en 17 Agosto 2018, 22:26 pm
Para eso debes cambiar el modo de trabajo del terminal. En el compilador de Borland eso lo hacía getch pero puedes emularlo. Busca en Google, o por el foro ya que también se ha tocado este tema, cómo emular getch en windows o linux, según sea tu sistema operativo.


Título: Re: ¿Parar un bucle for pulsando una tecla?
Publicado por: jmhr98 en 17 Agosto 2018, 22:53 pm
Entré en el mundo de la programación y el C++ hace unos días. No sé a qué se refiere. Pero si consiguiese eso, ¿Podría poner ese condicional y no pararse hasta que introduzca un carácter?
Sí me pudiese ser más concreto y ayudarme, se lo agradecería mucho.


Título: Re: ¿Parar un bucle for pulsando una tecla?
Publicado por: ThunderCls en 17 Agosto 2018, 23:32 pm
Has probado tu codigo de comprobacion en un nuevo hilo?

Código
  1. while(true)
  2. {
  3.   if(cin.get()=='d')
  4.      exit(0);
  5.   Sleep(10);
  6. }


Título: Re: ¿Parar un bucle for pulsando una tecla?
Publicado por: MAFUS en 18 Agosto 2018, 00:13 am
getch es  una forma de conseguir una tecla sin que se detenga el programa para que el usuario haga la entrada, es decir, si no se produce una pulsación el programa continua, y si se produce el programa continuará y getch te retornará que se ha pulsado. Además no producirá eco en la pantalla.

Implementación para windows:
https://helloacm.com/modern-getch-implementation-on-windows-cc/

Implementación para linux:
https://stackoverflow.com/questions/7469139/what-is-equivalent-to-getch-getche-in-linux


Título: Re: ¿Parar un bucle for pulsando una tecla?
Publicado por: jmhr98 en 18 Agosto 2018, 00:36 am
Getch es para detectar si se ha pulsado una tecla o no. No entiendo la función que tendría en el hecho de detener el programa. ThunderCls, he usado tu código y no funciona.
Para que entendáis mi problema, éste es el código:



Código
  1.  
  2. #include "iostream"
  3. #include "conio.h"
  4. #include "time.h"
  5. using namespace std;
  6. int main(){
  7.   srand(time(NULL));
  8. int Y,num=10;
  9.      int n[11]={0,1,2,3,4,5,6,7,8,9,10};
  10.      Y=rand()%num;
  11.   for (int i=0; i<10;i++){
  12.         if (i==Y){
  13.      cout <<"\033[1;35m\033[1m" << n[i] << "\033[1;35m\033[0m"<<endl;  
  14.      }
  15.         else{   cout << n[i]<<endl;  
  16.  
  17.      sleep(1);
  18.  
  19.   if {(cin.get()=='d')
  20.       return 0;}
  21.  
  22.   }
  23.   }
  24. return 0;  
  25.  
  26. }
[/quote]


Para que entiendan como es el funcionamiento normal que quiero para el programa (cuenta atrás y un número aleatorio se torna de un determinado color), quiten la parte del condicional if que lleva el cin.get.

Gracias por sus mensajes y ayuda. Es que me estoy desanimando de seguir aprendiendo porque no entiendo nada.


Título: Re: ¿Parar un bucle for pulsando una tecla?
Publicado por: Serapis en 18 Agosto 2018, 01:32 am
De entrada, C tiene una curvatura de aprendizaje muy muy larga, así que o se tiene paciencia, o es mejor saltar a otro lenguaje... Además si uno accede a C, sin conocimientos previos de ningún tipo, es manifiestamente más complicado, porque se rodea de demasiada jerga que complica al no iniciado.

Si dentro de un bucle pones una llamada que interrogue al usuario para pulsar una tecla, evidentemente el suceso es que se detiene la ejecución en ese punto hasta recibir una pulsación de tecla....

Así que, en efecto, esa funconalidad no te sirve si lo que pretendes es que se ejecute sin pausa y salga cuando se pulse determinada tecla.

El driver del teclado, almacena en un búfer las teclas que se van pulsando y el sistema operativo, obtiene información sobre el búfer mediante interrupciones, cuando se detecta que hay nuevas pulsaciones, las aplicaciones que se 'enganchen', reciben una notificación, donde se señala el código de la tecla pulsada y algún detalle extra.

Por ejemplo, si una aplicación tiene interfaz de usuario, cada control de la interfaz gráfica que tenga eventos de teclado, se engancha a dichas funciones y son notificadas... la forma en que el usuario interacciona en dicho caso es muy similar al getch.

Básicamente una función recibe la notificación y dentro se examina si se dan las condiciones que se desean... y se activa algún flag que se consulta en otra parte (o s e lanza un evento en caso de objetos, para notificar a otros objetos que estén enganchados a dichas notificaciones)
Código:
funcion NotificacionTeclado( entero codigo, entero flags) //flags puede ser indicadores del tipo del estado de las teclas ALT, Mayusculas, CTRL, etc...
    Si codigo = codigoquemeinteresa luego
        codigoEntrado = TRUE
    fin si
fin funcion

Y tu bucle lo condicionas a la espera de dicho suceso (o añadido a otras condiones si hay más)

Código:
... otra función en alguna parte

codigoquemeinteresa = ???? //el que tu veas preciso...
bucle ....
   ...loque sea que haga el bucle
repetir mientras codigoEntrado = FALSE  // and ....otras condiciones
codigoEntrado = FALSE  // se desactiva la bandera salvo que se requiera algo más adelante...

Lo que te señala Mafus, de getch es para hacer la parte que en el pseudocódigo se señala como función...
Nota que codigoEntrado se declara de tipo buleano a nivel del módulo lo mismo que 'codigoquemeinteresa', que ha de contener el valor del código que tu esperas (el valor asociado a la tecla 'd' (con ayuda de un flag, sabrás si es 'd' ó 'D'...)


De todos modos si estás empezando, aprendiendo, debes hacerlo con código que entiendas de cabo a rabo, e ir avanzando poco a poco...

Más adelante, cuando ya tengas una base mínima del lenguaje (el tiempo transcurrido para esto es relativo, ya que cada cual aprende a su ritmo y cada cual dedica el tiempo que quiere-puede) ya entonces con ejemplos más complejos, aunque parte del código no lo entiendas.
A menudo al poner un ejemplo para explicar algo, o se pone un ejemplo demasiado tonto, o fuerza a ponerse algo más ameno a cambio de exponer cosas que aún no se hayan dado... en los ejemplos, quédate con la parte que comenta el libro, tutorial, curso que estés leyendo/siguiendo/dando, ya llegará la parte en que explique aquello que en dicho instante queda oscuro...


Título: Re: ¿Parar un bucle for pulsando una tecla?
Publicado por: MAFUS en 18 Agosto 2018, 02:23 am
En C no hay una entrada directa desde el teclado. Hay un buffer, algo así como un contenedor, que se va llenando a medida que se van pulsando teclas y el lenguaje cuándo captura las entradas del teclado lo que hace es sacar del buffer lo que se ha ido introduciendo en el mismo orden.

Por otra parte C es un lenguaje próximo a la máquina así que depende mucho de cómo funcione el hardware, en su defecto, de cómo lo gestione el sistema operativo.

De normal lo que hace el sistema operativo es si le han pedido algo desde el teclado y el buffer está vacío detendrá el programa hasta que alguien pulse una tecla, entonces entregará esa tecla pulsada, la mostrará por pantalla y continuará con la ejecución el programa. Pero este comportamiento se puede cambiar y eso es lo que muestran los dos enlaces que te he pasado: allí el programa seguirá corriendo aún haya petición y el buffer esté vacío. También, si se va llenando no existirá aviso sino que en el momento que se pida una tecla pulsada ésta se entregará si hay petición. Y de hecho esto es lo que buscas en tu programa.

Pero me quedo con lo que te ha dicho NEBIRE: sigue aprendiendo el lenguaje, quizás con programas más básicos que no requieran estos efectos. Una vez lo domines podrás escalar de nivel. Ya ves que C depende de en qué máquina te encuentres. Otros lenguajes son más portables porque todo el framework que los soporta los ha alejado mucho de la máquina, en cambio C es un lenguaje muy básico y su framework es básicamente el sistema entero.


Título: Re: ¿Parar un bucle for pulsando una tecla?
Publicado por: jmhr98 en 18 Agosto 2018, 17:36 pm
Sí, MAFUS, es cierto todo. Pero es que ando sin guía y es un amigo el que me hace esta especie de retos. Así voy aprendiendo mientras buscó (como he aprendido el tema de poner colores a los caracteres y demás). Pero si no paso "esta pantalla", no puedo seguir sus peticiones. No sé, leí la página pero no entendí nada. Es por ello que quizás era lo que buscaba, pero por falta de conocimiento no me dí cuenta. ¿Sabes de alguna guía? ¿Y como de usaría lo de la web que me recomendaste? Estoy pensando que antes del for almacenar en el buffer un carácter y así no se defendía el bucle? Es eso lo que quieres decir?


Título: Re: ¿Parar un bucle for pulsando una tecla?
Publicado por: MAFUS en 19 Agosto 2018, 00:16 am
Intentando resolver tu problema me he encontrado con que la solución es más sencilla, en Windows:
https://msdn.microsoft.com/es-es/library/windows/desktop/ms646301(v=vs.85).aspx

resultando el siguiente código  (no lo mires si quieres hacerlo tu mismo):



Código
  1. #include <stdio.h>
  2. #include <windows.h>
  3.  
  4. int main() {
  5.    for(unsigned i=0; !(GetKeyState(0x44)&0x80); ++i)
  6.        printf("%i\n", i);
  7. }
  8.  


Título: Re: ¿Parar un bucle for pulsando una tecla?
Publicado por: Beginner Web en 22 Agosto 2018, 14:35 pm
Hola  la solucion seria la siguiente xd

Código
  1. #include <iostream>
  2.  
  3. using namespace std;
  4.  
  5. int main()
  6. {
  7. char input=0;
  8.  
  9. cout << "Presione d para ejecutar ciclo" << endl;
  10. while(1){
  11. cin >> input;
  12. if(input=='d'){
  13. ejecutar ciclo();
  14. }
  15. else{
  16. ejecutar_otras_acciones();
  17. }
  18. }
  19. system("pause");
  20. return 0;
  21. }


Título: Re: ¿Parar un bucle for pulsando una tecla?
Publicado por: ThunderCls en 22 Agosto 2018, 18:05 pm
Getch es para detectar si se ha pulsado una tecla o no. No entiendo la función que tendría en el hecho de detener el programa. ThunderCls, he usado tu código y no funciona.

El codigo de ejemplo que te puse fue solo una guía, igual no lo he probado,  aunque supongo que lo probaste dentro de un hilo diferente al winmain, cierto?. Como perfectamente te ha explicado NEBIRE, C++ no es un lenguaje trivial, así que no creas que seras un experto o que lograras codear todo lo que desees en un par de semanas.
La función cin.get() es una función síncrona, lo que significa que tu hilo principal se bloqueara al llamar a dicha función y solo continuara una vez haya leído una linea completa de la consola. Hasta donde se C++ no posee ninguna funcion estandar de entrada sin bloqueo del hilo principal. Las implementaciones de dichas funciones son dependiente de plataforma, en tu caso la solución al problema es fundamentalmente dependiente del sistema operativo, si en tu caso se trata de Windows, pudieras revisar algunas de estas opciones:

1- Instalar un hook de teclado con SetWindowsHookEx
https://stackoverflow.com/questions/10049764/detecting-escape-keypress-in-console-mfc-program
2- Usar un Control Handler Función con SetConsoleCtrlHandler
https://docs.microsoft.com/en-us/windows/console/registering-a-control-handler-function
3- Usar la función GetAsyncKeyState en un hilo separado a winmain
4- Usar _kbhit/_getch en un loop
https://stackoverflow.com/questions/6171132/non-blocking-console-input-c

*- Una opción multiplataforma seria usar la función cin.get() en un hilo separado del hilo de ejecución principal (como mi primer mensaje)

Para Linux y demás SO podrías hacer tus búsquedas en google: "Non-blocking console input C++"


Título: Re: ¿Parar un bucle for pulsando una tecla?
Publicado por: enriquemesa8080 en 23 Agosto 2018, 00:26 am
Hola, yo aconsejo que pongas un thread de ejecucion aparte donde puedas mantener en uno el conteo del for (tal vez el hilo nuevo), y la comprobacion de si se està presionando la tecla en otro hilo. Quizas en el mismo main().

Busca como usar los threads. Ya que lo que tu necesitas es sencillo es cuestion de usar la API plana de Windows.

Usa windows.h.

Yo tengo un blog donde voy subiendo informacion. No te resolverè tu problema con codigo, pero si puedo darte tips para que mejores. Pendiente del blog.

enriquemesa8080.blogspot.com