阻止在keypress linux c ++上写入控制台

时间:2015-04-30 16:47:14

标签: 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;
}

3 个答案:

答案 0 :(得分:3)

这是一个不响应击键但是将字符写入stderr的程序。如果您使用g++ -o t t.cpp进行编译,那么您可以使用例如./t 2>somefile,因此将stderr重定向到somefile

在第二个终端中,您可以在每次击键后执行cat somefile以控制程序写入的内容。 (警告:less somefile没有在我的cygwin安装上工作,因为文件增长只出现在较少的块中(我告诉它等待输入,按下&#34; F&#34;)。 / p>

由于所有击键被转发到控制程序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);
        }
    }
}

答案 1 :(得分:0)

您可以使用:

#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';
            }
        }
    }
}

(请原谅不完整的课程,你是实验性的)

答案 2 :(得分:-2)

使用getpass()

  

getpass()函数打开进程的控制终端,写入   对该设备的以null结尾的字符串提示,禁用回显,   读取一串字符直到下一个换行符或EOF,   恢复终端状态并关闭终端。

相关问题