Prevent writing to console in keypress linux C ++

I am trying to make a simple game (Pong) in C ++. The game is a "Console-Game". I just wrote a piece of code, but now I found the problem: I am creating a function _getch () and _kbhit ()

    int _getch( ) {
        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;
}

int _kbhit() {
        static const int STDIN = 0;
        static bool initialized = false;
        if (! initialized) {
                termios term;
                tcgetattr(STDIN, &term);
                term.c_lflag &= ~ICANON;
                tcsetattr(STDIN, TCSANOW, &term);
                setbuf(stdin, NULL);
                initialized = true;
        }
        int bytesWaiting;
        ioctl(STDIN, FIONREAD, &bytesWaiting);
        return bytesWaiting;
}

      

but when i press a key this is printed to the console. How can I prevent this?

My complete code:

#include <iostream> 
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <sys/select.h>
#include <stropts.h>
#include <sys/ioctl.h>

using namespace std;

void gotoxy(int x,int y){
       printf("\x1b[%d;%df",y,x);
}

int _getch( ) {
        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;
}

int _kbhit() {
    static const int STDIN = 0;
    static bool initialized = false;
    if (! initialized) {
        // Use termios to turn off line buffering
        termios term;
        tcgetattr(STDIN, &term);
        term.c_lflag &= ~ICANON;
        tcsetattr(STDIN, TCSANOW, &term);
        setbuf(stdin, NULL);
        initialized = true;
    }
    int bytesWaiting;
    ioctl(STDIN, FIONREAD, &bytesWaiting);
    return bytesWaiting;
}

class Ball{
    public:

};

class Game{
    public:
        void __init(){
            this->pointL = 0;
            this->pointR = 0;
        }

        void addScore(char side){
        if(side == 'l') pointL++;
        else if(side == 'r') pointR++;
        else cout<< "ERROR-2";
            return;
        }

        unsigned int getScore(char side){
            if(side == 'l') return this->pointL;
            else if (side == 'r') return this->pointR;
            else return 0;
        }

        bool isPlaying(){
            return this->playing;
        }

        bool stop(){
            this->playing = false;
            return true;
        }   
    private:
        unsigned int pointL, pointR;
        bool playing;
};

class Player{
    public:
        int pos[5][2];
        int maxX, maxY;
        void __init(int maxX, int maxY, char side){
            //create matrix with all cords of block of wall (r and l)
            this->maxX = maxX;
            this->maxY = maxY;
            if(side == 'l')
                for(int i = 0; i<5; i++){
                    pos[i][0] = 2;
                    pos[i][1] = 2+i;
                    gotoxy(pos[i][0],pos[i][1]);
                    cout<< "|";
                }
            else if(side == 'r')
                for(int i = 0; i<5; i++){
                    pos[i][0] = maxX-4;
                    pos[i][1] = 2+i;
                    gotoxy(pos[i][0],pos[i][1]);
                    cout<< "|";
                }
            else
                cout<<"ERRORE-1";

        }

        void moveUp(){
            gotoxy(pos[4][0],pos[4][1]);
            cout<< " ";
            for(int i = 0; i<5; i++){
                pos[i][1] = (pos[i][1] == 0)?pos[i][1]:pos[i][1]-1;
                gotoxy(pos[i][0],pos[i][1]);
                cout<< "|"; //solid rectangle
            }
        }

        void moveDown(){
            gotoxy(pos[4][0],pos[4][1]);
            cout<< " ";
            for(int i = 0; i<5; i++){
                pos[i][1] = (pos[i][1] == this->maxY)?pos[i][1]:pos[i][1]+1;
                gotoxy(pos[i][0],pos[i][1]);
                cout<< "|"; //solid rectangle
            }
        }
};

int main(){
    int a;
    Game game;
    Player pl1,pl2;
    cout<< "Ridimensiona la finestra come meglio preferisci, quando hai fatto, premi un tasto per continuare";
    _getch();
    struct winsize size;
    ioctl( 0, TIOCSWINSZ, (char *) &size );
    printf("\e[2J\e[H");
    pl1.__init(size.ws_row, size.ws_col, 'l');
    pl2.__init(size.ws_row, size.ws_col, 'r');
    //asap menu here
    cout<< "TEST: " << size.ws_row;
    char key;
    while(game.isPlaying()){
        if(_kbhit()){
            key = _getch();
            switch(key){ //when i press that keys, it printed on terminal, how prevent?
                case 'w':
                    pl1.moveUp();
                    break;
                case 's':
                    pl2.moveDown();
                    break;
                case 'q':
                    game.stop();
                    break;
            }   
        }
    }
    return 0;
}

      

+3


source to share


3 answers


Here's a program that doesn't respond to keystrokes, but instead writes characters to stderr. If you compile it with, say, with g++ -o t t.cpp

, then you can run it for example. ./t 2>somefile

, thereby redirecting stderr to somefile

.

In the second terminal, you can do cat somefile

after each keystroke to control what the program writes. (Warning: less somefile

not working on my cygwin installation because the file grew only in chunks less (I told it to wait for input by pressing "F")).

Because all keystrokes are sent to the Control-C program, or other means to send a signal to the running program through the control terminal, do not work. You have to kill him from another terminal.



The basic idea is that read () blocks in raw mode until input is available, so there is no need for a separate one kbhit()

.

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

using namespace std;

int main()
{
    struct termios oldt;
    if( tcgetattr( 0, &oldt ) ) 
    { 
        fprintf(stderr, "Error getting term attribs\n"); 
    }
    cfmakeraw(&oldt);

    if( tcsetattr(0, TCSANOW, &oldt) ) 
    {
        fprintf(stderr, "Error setting term attribs\n");
    }

    char inp;
    while(true)
    {
        int bytesRead = read(0, &inp, 1);

        if( bytesRead <= 0)
        {
            fprintf(stderr, "oops, bytes read return val is %d\n", bytesRead);
        }
        else
        {
            write(2, &inp, 1);
        }
    }
}

      

+2


source


You can use:

#include <iostream>
#include <stdexcept>
#include <termios.h>
#include <unistd.h>

// A class for mofdifying the behavour of a terminal.
class Terminal
{
    // Types
    // =====

    public:
    typedef speed_t speed_type;

    // Terminal
    // ========

    public:
    // Initialize the terminal file descriptor and store the attributes of the terminal.
    Terminal(int fd)
    :   m_fd(fd), m_restore(get(fd))
    {}

    // Restore the orignal attributes of the terminal
    ~Terminal() {
        set(m_fd, m_restore, false);
    }

    Terminal(const Terminal&) = delete;
    const Terminal& operator = (const Terminal&) = delete;

    int fd() const { return m_fd; }
    void restore() { set(m_fd, m_restore); }

    protected:
    // Get attributes of a terminal
    static termios get(const int fd) {
        termios attributes;
        if(tcgetattr(fd, &attributes) < 0) {
            throw std::runtime_error("Terminal");
        }
        return attributes;
    }

    // Set attributes of a terminal
    static void set(const int fd, const termios& attributes, bool exception = true) {
        if(tcsetattr(fd, TCSANOW, &attributes) < 0 && exception) {
            throw std::runtime_error("Terminal");
        }
    }

    // Set attributes of a terminal
    static void set(const int fd, int action, const termios& attributes, bool exception = true) {
        if(tcsetattr(fd, action, &attributes) < 0 && exception) {
            throw std::runtime_error("Terminal");
        }
    }

    private:
    int m_fd;
    termios m_restore;
};

// A class for mofdifying the input behavour of a terminal.
class StdInputTerminal : public Terminal
{
    // Constants
    // =========

    public:
    enum Attributes {
        Blocking = 0x01,
        Echo = 0x02
    };

    // Static
    // ======

    public:
    // Clear available input in std::cin
    static void clear() {
        termios attributes = disable_attributes(Blocking);
        while(std::cin)
            std::cin.get();
        std::cin.clear();
        set(fileno(stdin), attributes);
    }

    // StdInputTerminal
    // ================

    public:
    // Initialize with 'stdin'
    StdInputTerminal()
    :   Terminal(fileno(stdin))
    {}

    public:
    // Disable attributes specified by any combination of Attributes flags
    void disable(unsigned flags) { disable_attributes(flags); }

    // Disable blocking
    void disable_blocking() { disable_attributes(Blocking); }

    protected:
    // Set attributes of the terminal
    static termios disable_attributes(unsigned flags) {
        const int fd = fileno(stdin);
        termios attributes = get(fd);
        termios a = attributes;
        if(flags & Blocking) {
            a.c_lflag &= ~ICANON;
            a.c_cc[VMIN] = 0;
            a.c_cc[VTIME] = 0;
        }
        if(flags & Echo) {
            a.c_lflag &= ~ECHO;
        }
        set(fd, a);
        return attributes;
    }
};


// Sample Usage
// ============

int kbhit() {
    StdInputTerminal terminal;
    terminal.disable(StdInputTerminal::Blocking | StdInputTerminal::Echo);
    int result = 0;
    char c;
    if( ! std::cin.get(c))
        std::cin.clear();
    else
    {
        result = c;
        std::cin.unget();
    }
    return result;
}

int getch() {
    StdInputTerminal terminal;
    terminal.disable(StdInputTerminal::Blocking | StdInputTerminal::Echo);
    char result = 0;
    while(true) {
        std::cin.get(result);
        if(std::cin.eof()) {
            std::cin.clear();
            usleep(100000);
        }
        else break;
    }
    if(std::cin.fail()) {
        std::cin.clear();
        result = 0;
    }
    return result;
}


// Test
// ====

int main()
{
    std::cout << "Enter a single sample character: ";
    char c;
    std::cin.get(c);
    std::cin.unget();

    if(kbhit()) {
        int ch = getch();
        std::cout << "Entered character: " << char(ch);
        if(kbhit()) {
            int ch = getch();
            std::cout << " Newline " << char(ch);
            if(kbhit()) {
                std::string line;
                getline(std::cin, line);
                std::cout << "\nToo many sample characters: " << line << '\n';
            }
        }
    }
}

      



(Please excuse incomplete classes, your experimental)

0


source


Use getpass()

:

The getpass () function opens the process's controlling terminal, writes a null-terminated string prompt to that device, turns off echo, reads the character string until the next newline or EOF, restores the terminal state, and closes the terminal.

-2


source







All Articles