1

可能重复:
C/C++:从标准输入中捕获字符而不等待按下回车键

char ch;

我想我想得到一个角色。我知道两种不同的方式。

1- 在 iostream 头文件中使用 cin 命令。

cin >> ch;

它将等待用户输入某些内容,然后用户必须按 enter 将输入发送到 ch 变量。

2- conio.h 头文件中的 getch() 命令。

ch = _getch();

它会等待用户输入一些东西,一旦输入一个字符,它将被保存在 ch 变量中,用户不需要按 enter。顺便说一句,此代码将停止程序并等待输入。

现在我想写一个不需要按回车的命令,它不会停止程序按下某些东西。想象一下我将程序延迟 1 秒,如果用户按下某些东西,它会将其保存到 ch 变量中,如果不是什么都没有,程序将继续并且不会因为按下某些东西而停止。它就像一个选择器命令,如果有东西它会选择它,如果没有它会继续。

希望我很清楚。那么该怎么做呢?

4

2 回答 2

2

在 Windows 上,您可以这样做:

  1. CreateFile使用 filename "CONIN$",它将为您提供控制台的 Win32 句柄。
  2. WaitForSingleObject,传递控制台句柄和超时。
  3. 如果等待成功,则用于ReadConsoleInput确定甚至发生了什么。
  4. 如果等待失败,则发生超时。

如果您只是在循环中轮询执行其他操作,那么您可以使用PeekConsoleInput,它会检查输入队列中是否有任何事件,并始终立即返回。


在 Unix 上,类似的方法将起作用。请注意:

  1. 不必打开文件,因为stdin始终是文件描述符0
  2. 使用selectpoll测试超时输入的活动。

最后的区别:在 Windows 上,鼠标活动的捕获方式相同。在 Unix 上,您通常会从 tty 读取键盘输入,而鼠标是完全独立的。

于 2012-05-27T18:35:09.877 回答
1

首先我们需要一个函数来打开和关闭非阻塞输入:

void nonblock(const bool state){

    struct termios ttystate;

    //get the terminal state
    tcgetattr(STDIN_FILENO, &ttystate);

    if (state){
        //turn off canonical mode
        ttystate.c_lflag &= ~ICANON;
        //minimum of number input read.
        ttystate.c_cc[VMIN] = 1;
    }
    else{
        //turn on canonical mode
        ttystate.c_lflag |= ICANON;
    }

    //set the terminal attributes.
    tcsetattr(STDIN_FILENO, TCSANOW, &ttystate);
}

现在我们需要一个函数来测试是否按下了某个键:

int keypress(void){
    struct timeval tv;
    fd_set fds;
    tv.tv_sec = 0;
    tv.tv_usec = 0;
    FD_ZERO(&fds);
    FD_SET(STDIN_FILENO, &fds);
    select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
    return FD_ISSET(STDIN_FILENO, &fds);
}

我们将并行检查两件事。用户是否按下了某个键,或者时间用完了?这是一个在指定秒数后更改布尔值的函数:

void SleepForNumberOfSeconds(const int & numberofSeconds,bool & timesUp){

    timespec delay = {numberofSeconds,0};
    timespec delayrem;

    nanosleep(&delay, &delayrem);
    timesUp = true;

    return;
}

这是您可以调用的主要功能:

void WaitForTimeoutOrInterrupt(int const& numberofSeconds){

    bool timesUp = false;

    std::thread t(SleepForNumberOfSeconds, numberofSeconds, std::ref(timesUp));
    nonblock(1);
    while (!timesUp && !keypress()){

    }

    if (t.joinable()){
        t.detach();
    }
    nonblock(0);

    return;
}

这是要测试的代码。
编译:

g++ -std=c++0x -o rand rand.cpp -lpthread

上:

gcc (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1

这只是一种解决方案,它可能对您不起作用。
考虑研究 ncurses 为好。

于 2012-05-27T19:16:57.220 回答