c++ - 防止在 keypress linux c++ 的控制台上写入

标签 c++ linux

我正在尝试用 C++ 做一个简单的游戏 (Pong)。该游戏是“控制台游戏”。 我刚刚写了一部分代码,但现在我发现了一个问题: 我创建了一个 _getch() 和 _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;
}

但是当我按下一个键时,它会打印在控制台上。我该如何防止这种情况?

我的完整代码:

#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's printed on terminal, how prevent?
                case 'w':
                    pl1.moveUp();
                    break;
                case 's':
                    pl2.moveDown();
                    break;
                case 'q':
                    game.stop();
                    break;
            }   
        }
    }
    return 0;
}

最佳答案

这是一个程序,它不会回显击键,而是将字符写入 stderr。如果你用 g++ -o t t.cpp 编译它,那么你可以用例如./t 2>somefile,从而将 stderr 重定向到 somefile

在第二个终端中,您可以在每次击键后执行 cat somefile 以控制程序写入的内容。 (警告:less somefile 在我的 cygwin 安装上不起作用,因为文件增长只出现在 less 中的 block 中(我告诉它按“F”等待输入)。

由于所有击键都被转发到控制程序 Control-C 或其他通过其控制终端向正在运行的程序发送信号的方法不起作用。你必须从不同的终端杀死它。

基本思想是 read() 在原始模式下阻塞,直到输入可用,因此不需要单独的 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);
        }
    }
}

关于c++ - 防止在 keypress linux c++ 的控制台上写入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29973445/

相关文章:

c++ - 关于标题、转发以及如何组织大量包含

c++ - 我的工具箱中应该有哪些现代 C++ 库?

linux - 在 if 语句中使用 grep

java - 如何开始在 Ubuntu Linux 上使用和开发?

linux - Shell 脚本 - Linux - 列出空目录

c++ - MFC Picture Control 不会根据 Windows 显示比例自动缩放

c++ - 通过指针取消引用的函数调用语法

python - 没有名为 yum 的模块

c++ - 带继承的构造函数的重新定义

linux - 使用 Diff 检查文件夹结构中更改的文件,忽略以模式开头的行