防止在控制台上按键写入 Linux C++
prevent write on console at keypress linux c++
我正在尝试用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[2Je[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 安装上不起作用,因为文件增长只出现在更少的块中(我告诉它通过按"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 attribsn");
}
cfmakeraw(&oldt);
if( tcsetattr(0, TCSANOW, &oldt) )
{
fprintf(stderr, "Error setting term attribsn");
}
char inp;
while(true)
{
int bytesRead = read(0, &inp, 1);
if( bytesRead <= 0)
{
fprintf(stderr, "oops, bytes read return val is %dn", bytesRead);
}
else
{
write(2, &inp, 1);
}
}
}
您可以使用:
#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';
}
}
}
}
(请原谅不完整的课程,你的是实验性的)
相关文章:
- 在C++/Linux中设置单调时钟的一些技巧
- Linux的Cpp上的计时器
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- 在Linux中哪里可以找到互斥、未来等的源代码
- 如何在linux终端中同时编译和运行c++代码
- 在Linux for Windows上编译C++代码时出错
- 如何找到锁定Linux futex的C++行
- 在linux上调试巨大的C++项目
- 如何处理linux终端中带有负号(-)的C++中的命令行参数
- c++方法参数只能在linux的发布模式下自行更改
- 在Linux和C++中的Windows上,散列字符串值会产生不同的输出
- 这里在 Linux 中具有"CreatePipe"和"CreateProcessW"功能吗?
- 函数在Windows或Linux上运行时表现不同
- 在Linux下捕获SIGKILL的C++程序
- 在为LINUX创建共享库时,如何避免STL的私有/弱副本
- 使用 cmake 的 Linux 终端上的"Conversion to non-scalar type is requested"错误
- 如何在CPP中创建应该在Windows和Linux上运行的套接字?
- mysql C++ connector [mysql-connector-c++-8.0.19-linux-glibc2
- 这些是什么样的错误?即使我不在 Linux 上工作,我也遇到了 Linux 错误
- CMake WxWidgets项目成功地在Linux上构建,但没有在Windows上构建