我从来都不记得我是怎么做到的,因为它很少出现在我身上。但是在C或c++中,从标准输入中读取字符而不等待换行符(按enter)的最佳方法是什么?

理想情况下,它也不会将输入字符回显到屏幕上。我只是想在不影响控制台屏幕的情况下捕捉击键。


当前回答

#include <conio.h>

if (kbhit() != 0) {
    cout << getch() << endl;
}

它使用kbhit()来检查键盘是否被按下,并使用getch()来获取被按下的字符。

其他回答

我总是想要一个循环读取我的输入而不按返回键。 这对我很管用。

#include<stdio.h>
 main()
 {
   char ch;
    system("stty raw");//seting the terminal in raw mode
    while(1)
     {
     ch=getchar();
      if(ch=='~'){          //terminate or come out of raw mode on "~" pressed
      system("stty cooked");
     //while(1);//you may still run the code 
     exit(0); //or terminate
     }
       printf("you pressed %c\n ",ch);  //write rest code here
      }

    }

ssinfod对Linux的回答的变体,对我的口味来说稍微干净一些,为wcout和wchar_t实现,并在没有错误的情况下擦除无效字符。

#include <functional>

//For Linux kbhit(). For Windows, use conio.h.
#ifdef __unix__
  #include <sys/ioctl.h> //For FIONREAD.
  #include <termios.h>

  //Call this at program start to setup for kbhit.
  void initTerminalInput()
  {
    //Disable internal buffering.
    std::wcout << std::unitbuf;

    //Turn off line buffering.
    struct termios term;
    tcgetattr(0, &term);
    term.c_lflag &= ~ICANON;
    tcsetattr(0, TCSANOW, &term);
    setbuf(stdin, NULL);
  }

  //Returns 0 if there's no input character to read.
  int kbhit()
  {
    static int nbbytes;
    ioctl(0, FIONREAD, &nbbytes);
    return nbbytes;
  }
#endif

//Waits for and retrieves a single validated character, calling a validation function on each character entered and
//erasing any that are invalid (when the validation function returns false).
static wchar_t getWChar(std::function<bool(wchar_t)> validationFunction)
{
  static wchar_t inputWChar;
  do
  {
    //Wait until there's an input character.
    while (!kbhit())
    {
    }
    inputWChar = getwchar();
    //Validate the input character.
    if (validationFunction(inputWChar))
    {
      //Valid.
      break;
    }
    else
    {
      //Erase the invalid character.
      std::wcout << L"\b \b";
    }
  } while (true);
  return inputWChar;
}

在下面的例子中,我想让用户输入1、2或3。输入的任何其他字符都不会显示,它将等待,直到按下其中一个有效字符:

int main()
{
  #ifdef __unix__
    initTerminalInput();
  #endif

  getWChar([] (wchar_t inputWChar)
  {
    return (inputWChar >= L'1' && inputWChar <= L'3');
  });

  return 0;
}

Ncurses提供了一个很好的方法来做到这一点! 这也是我的第一篇文章(我记得),所以欢迎任何评论。我会欣赏有用的,但都是受欢迎的!

编译: g++ -std=c++11 -pthread -lncurses .cpp -o

#include <iostream>
#include <ncurses.h>
#include <future>

char get_keyboard_input();

int main(int argc, char *argv[])
{
    initscr();
    raw();
    noecho();
    keypad(stdscr,true);

    auto f = std::async(std::launch::async, get_keyboard_input);
    while (f.wait_for(std::chrono::milliseconds(20)) != std::future_status::ready)
    {
        // do some work
    }

    endwin();
    std::cout << "returned: " << f.get() << std::endl;
    return 0;
}

char get_keyboard_input()
{
    char input = '0';
    while(input != 'q')
    {
        input = getch();
    }
    return input;
}

我使用kbhit()来查看是否存在一个字符,然后使用getchar()来读取数据。 在windows上,您可以使用“conio.h”。在linux上,您必须实现自己的kbhit()。

参见下面的代码:

// kbhit
#include <stdio.h>
#include <sys/ioctl.h> // For FIONREAD
#include <termios.h>
#include <stdbool.h>

int kbhit(void) {
    static bool initflag = false;
    static const int STDIN = 0;

    if (!initflag) {
        // Use termios to turn off line buffering
        struct termios term;
        tcgetattr(STDIN, &term);
        term.c_lflag &= ~ICANON;
        tcsetattr(STDIN, TCSANOW, &term);
        setbuf(stdin, NULL);
        initflag = true;
    }

    int nbbytes;
    ioctl(STDIN, FIONREAD, &nbbytes);  // 0 is STDIN
    return nbbytes;
}

// main
#include <unistd.h>

int main(int argc, char** argv) {
    char c;
    //setbuf(stdout, NULL); // Optional: No buffering.
    //setbuf(stdin, NULL);  // Optional: No buffering.
    printf("Press key");
    while (!kbhit()) {
        printf(".");
        fflush(stdout);
        sleep(1);
    }
    c = getchar();
    printf("\nChar received:%c\n", c);
    printf("Done.\n");

    return 0;
}

管道演示:如何从C语言的系统调用管道读取键盘按键

理想情况下,它也不会将输入字符回显到屏幕上。我只是想在不影响控制台屏幕的情况下捕捉击键。

要在Linux上做到这一点,您可以使用以下bash命令:

read -sn1 c && printf "You Pressed: %s\n" "$c"

请看我在这里的回答关于这个的详细信息:shell脚本响应按键。

因此,要在Linux上的C或c++中做到这一点,您只需要通过使用popen()和fgets()的管道通过系统调用调用上面的bash命令,这样您就可以从bash命令读取输出。

下面是一个完整的例子,在Linux上运行良好的C和c++:

read_system_call_via_pipe__keypress.c:

#include <stdbool.h> // For `true` (`1`) and `false` (`0`) macros in C
#include <stdint.h>  // For `uint8_t`, `int8_t`, etc.
#include <stdio.h>   // For `printf()`
#include <stdlib.h>

#define BUFSIZE 32

// Read a keyboard key press and return the character pressed, or a negative
// number in the event of an error.
// NB: for help reading output from system calls, see here:
//  1. https://stackoverflow.com/a/28971647/4561887
//  2. https://stackoverflow.com/a/18297075/4561887
char getKeypress()
{
    // This bash cmd is from my answer here:
    // https://stackoverflow.com/a/70979348/4561887
    const char* cmd = "bash -c 'read -s -n1 c && printf \"%s\" \"$c\"'";
    FILE *fp = popen(cmd, "r");
    if (fp == NULL)
    {
        printf("\nError opening pipe!\n");
        return -1;
    }

    char buf[BUFSIZE] = {0};
    char* retval1 = fgets(buf, BUFSIZE, fp);
    if (retval1 == NULL)
    {
        printf("\nFailed to read cmd response.\n");
        return -2;
    }

    // See meaning of this return value here:
    // https://stackoverflow.com/questions/43116/how-can-i-run-an-external-program-from-c-and-parse-its-output/28971647#comment60311936_28971647
    int retval2 = pclose(fp);
    if (retval2 == -1)
    {
        printf("\nError obtaining the cmd's exit status code.\n");
        return -3;
    }
    else if (retval2 != 0)
    {
        printf("\nCommand exited with exit status code %i.\n", retval2);
        return -4;
    }

    char keyPressed = buf[0];
    return keyPressed;
}

// int main(int argc, char *argv[])  // alternative prototype
int main()
{
    printf("Press any key to continue: ");
    fflush(stdout);
    char keyPressed = getKeypress();
    if (keyPressed > 0)
    {
        printf("\nKey pressed = %c\n", keyPressed);
    }

    return 0;
}

C和c++编译和运行命令是下面输出的一部分。下面是一些演示:

在C:

eRCaGuy_hello_world/c$ gcc -Wall -Wextra -Werror -O3 -std=gnu17 read_keypress_system_call.c -o bin/a && bin/a
Press any key to continue:
Key pressed = P

或,在c++中:

eRCaGuy_hello_world/c$ g++ -Wall -Wextra -Werror -O3 -std=c++17 read_keypress_system_call.c -o bin/a && bin/a
Press any key to continue:
Key pressed = u

参见:

要更进一步,请参阅我在这里的另一个回答,我一次检测并解析3个字符,以便检测方向键的向上、向下、向左或向右:在C语言中读取键按下。方向键,Enter键

引用:

How I learned to read from a pipe to get system call output: How can I run an external program from C and parse its output? Is there a way to obtain the output of a linux command(like ifconfig) on a .txt file using a C program? [duplicate] How to compile and use popen() in C: use -std=gnu17 instead of -std=c17: popen implicitly declared even though #include <stdio.h> is added [my answer] How to read without blocking, via bash: shell script respond to keypress [my answer] How do I read in the Enter key as an input in C?

关于这个话题的3个问题

从标准输入中捕获字符,而不需要等待按enter键 C非阻塞键盘输入 如何避免按Enter与getchar()只为读取单个字符?