Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 15
  1. #1

    [c++] Prelevare Input da tastiera in modo asincrono linux

    Salve Sono un newbie del c++ e girovagando sui vari siti web ho trovato questo video {http://www.youtube.com/watch?v=TiSAH_MNHN0} dove viene realizzata una versione base del celebre gioco Space Invaders realizzata su sistema operativo Windows in c++

    Provo a realizzare da 2 giorni questo piccolo progetto ma Poiché utilizzo come sistema operativo Linux non posso utilizzare la libreria window.h e sono bloccato perchè non riesco a prelevare gl'input da tastiera in modo asincrono cioè senza pressione successiva del tasto enter, (cosa che nel video viene fatta con GetAsyncKeyState, funzione della libreria window.h)

    Ho provato ad ovviare a questo problema includendo la libreria ncurse.h e usare la funzione getch() e getchar() ma nonostante ciò non riesco a fare quello che mi serve.


    Le cose fondamentali che dovrebbe fare questa funzione alternativa sono:
    1. Avere una funzione che preleva input da tastiera senza la pressione successiva del tasto enter.
    2. Lo script quando arriva a quella linea di codice non deve fermarsi ad attendere l'input da tastiera ma deve restituire vuoto o 0 e deve andare avanti (come succede con GetAsyncKeyState).


    C'è un modo alternativo per prelevare input da tastiera in modo asincrono per linux come succede su windows con "GetAsyncKeyState"?

    Grazie mille in anticipo
    Andrea


    codice:
    #include <iostream>
    #include <cstdlib>
    
    #include <ncurses.h>
    #include <time.h>
    #include <unistd.h>
    
    
    
    using namespace std;
    
    
    //Inizializzo la mappa (array di caratteri bidimensionale)
    char Map[20][20] = {
    	"###################",
    	"#                 #",
    	"#                 #",
    	"#                 #",
    	"#                 #",
    	"#                 #",
    	"#                 #",
    	"#                 #",
    	"#                 #",
    	"#                 #",
    	"#                 #",
    	"#                 #",
    	"#                 #",
    	"#                 #",
    	"#                 #",
    	"#                 #",
    	"#                 #",
    	"#                 #",
    	"#        W        #",
    	"###################"
    };
    
    
    
    bool endgame = false;
    int GameSpeed = 400;
    int k = 0;
    
    int main(){
    
    
    	while(endgame == false){
    
    		unsigned int sleep(unsigned int seconds = 0);
    
    
    		  #ifdef WINDOWS
    
    		  system("CLS");
    
    		  #else
    
    		  // Assume POSIX
    
    		  system("clear");
    
    		  #endif
    
    
    
    		 for( int y=0; y<20; y++ ){
    
    			cout << Map[y] << endl;
    
    		 }
    		 cout << k << endl;
    		 k++;
    
    
    
    		 int ch = 0;
    		 initscr();
    		 timeout(0);
    
    		 ch = getch();
    		 endwin();
    
    		 if(ch >= 0 && ch!=10){
    			 endgame = true;
    		 }
    		 /*int ch;
    		 ch = getchar( );*/
    		 cout << "Tasto premuto è: " << ch << endl;
    
    
    
    		 /*//Controllo ogni carattere nello schermo
    		 for(int y = 0; y < 20; y++){
    			 //Scorro le righe
    			 for(int x = 0; x<20; x++){
    				 //Scorro i singoli caratteri su ogni riga
    
    				 switch(Map[y][x]){
    
    				 	 case 'w':
    
    
    
    				 	 break;
    
    				 }
    
    
    			 }
    		 }
    
    
    		  */
    
    
    	}
    
    
    	return 0;
    }

  2. #2
    Ma stiamo parlando di un'applicazione console o di un'applicazione grafica (=basata su X)?
    Amaro C++, il gusto pieno dell'undefined behavior.

  3. #3
    Un applicazione Console come quella che Crea nel video quel programmatore (Non penso di essere ancora capace di utilizzare X)

  4. #4
    I terminali UNIX lavorano normalmente in modalità "canonica" - ovvero, inviano solo linee complete allo standard input; per fare quello che chiedi devi impostare il terminale in modalità "raw" e usare funzioni di IO non-bloccanti.
    Fortunatamente, c'è chi ha già scritto del codice per emulare le "classiche" funzioni kbhit/getch (dall'header non-standard conio.h) su sistemi POSIX.

    (nota comunque che l'uso che si fa della GetAsyncKeyState nel video è abbastazna criminale - anche sotto Windows basta usare funzioni di input non bloccante; non è necessario scomodare la GetAsyncKeyState, che va ad intercettare le pressioni di tasti a prescindere dalla finestra che ha il focus)
    Amaro C++, il gusto pieno dell'undefined behavior.

  5. #5
    Grazie mille della risposta Repentina ed Esauriente, Ma voglio approfondire un attimino un aspetto:

    - Cosa significa impostare il terminale in modalità raw e usare funzioni non bloccate?? (e nel caso chi o cosa le blocca?)

  6. #6
    Originariamente inviato da cataDesign
    - Cosa significa impostare il terminale in modalità raw
    Sui sistemi POSIX il terminale può funzionare in diverse modalità, tra cui la modalità "raw" e la modalità "cooked" (più la modalità "cbreak" che è una via di mezzo); la differenza sta nel fatto che in modalità raw tutti i caratteri inseriti sono immediatamente disponibili per l'applicazione (tramite una read dallo standard input). In modalità "cooked", invece, il sistema fa una prima gestione dell'input (consentendo all'utente di tornare indietro sulla riga, modificare quello che ha scritto, gestendo combinazioni speciali come Ctrl-C, ...) e passa all'applicazione solo righe "complete". Per ulteriori dettagli, leggi:
    https://en.wikipedia.org/wiki/Raw_mode#History
    https://en.wikipedia.org/wiki/Cooked_mode
    e usare funzioni non bloccate?? (e nel caso chi o cosa le blocca?)
    Funzioni non bloccanti; funzioni come la read (a cui poi gli stream C e C++ si appoggiano in ultima analisi) sono normalmente funzioni bloccanti, dato che non ritornano (=il programma non continua) finché non hanno letto dal file descriptor specificato i dati richiesti. In altri termini, se chiedi alla read di leggere 100 bytes, questa non ritorna finché non li ha effettivamente letti (se il FD è in modalità bloccante, come è di default).
    Le chiamate di I/O non bloccanti, invece, non tengono bloccato il programma se l'input richiesto non è disponibile: semplicemente falliscono, restituendo un preciso codice di errore che indica che non è stato possibile leggere i dati richiesti dato che non c'era niente da leggere. In realtà comunque nel codice linkato prima non sono usate, viene invece usata la select per chiedere al sistema operativo se nel buffer del specificato (nello specifico, nello standard input) ci sono caratteri da leggere, e poi viene fatta una normale read bloccante (che però si sa che non bloccherà, dato che con la select si è già verificato che ci sono dati da leggere*).

    ---

    * in realtà in ambiente multithreaded questo non è strettamente vero, ma fa niente.
    Amaro C++, il gusto pieno dell'undefined behavior.

  7. #7
    Perfetto Perfetto Sei stato chiaro comunque volevo dirti che ho copiato il codice che mi hai postato e ho cercato di implementare il tutto in questo modo:

    codice:
    while(endgame == false){
    int ch;
    		 bool kbhitVar = kbhit();
    		 if (!kbhitVar) {
    
    			 ch = getch();
    
    		 }else{
    			 (void)getch();
    			 ch = -1;
    		 }
    
    		 cout << "Tasto premuto è: " << ch << "kbhit: " << kbhitVar << endl;
    		 (void)getch(); /* consume the character */
    }
    Il problema è che il codice sembra "Bloccante" cioè ferma l'esecuzione dell'applicazione (Va avanti di 1 ciclo ad ogni mio input da tastiera) Forse sono io che lo implemento male boh...

  8. #8
    getch() è bloccante, infatti la devi chiamare solo se kbhit() restituisce true (ovvero, sai che è già stato premuto un tasto e quindi sai che getch() non dovrà attendere).
    Amaro C++, il gusto pieno dell'undefined behavior.

  9. #9
    Sono contendo come un bambino
    Inizia a funzionare qualcosina adesso però c'è un problema, "penso" facilmente risolvibile,

    Adesso che il terminale si trova in modalità raw non riesco a far andare a capo le stringhe quindi la "mappa" si vede tutta su una righa cioè:

    ############## # # ecc...

    per fare in modo che la mappa si veda in questo modo:

    ########
    # #
    # #
    ecc..

    devo modificare la dimensione della finestra del terminale o c'è qualche altro modo??


  10. #10
    Per andare a capo basta stampare il carattere '\n' (la modalità raw del terminale comunque non dovrebbe c'entrare).
    Amaro C++, il gusto pieno dell'undefined behavior.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.