Захват символов со стандартного ввода без ожидания нажатия клавиши

Я никогда не могу вспомнить, как я это делаю, потому что это происходит редко для меня. Но в C или С++, как лучше всего читать символ со стандартного ввода, не дожидаясь новой строки (нажмите enter).

В идеале он не будет отображать входной символ на экране. Я просто хочу захватить нажатия клавиш, не используя экран консоли.

+150
07 янв. '09 в 20:04
источник поделиться
15 ответов

Это невозможно в портативном виде в чистом C++, потому что это слишком сильно зависит от используемого терминала, который может быть подключен к stdin (обычно это буферизованная линия). Однако вы можете использовать библиотеку для этого:

  1. conio доступен с компиляторами Windows. Используйте _getch() чтобы дать вам символ, не дожидаясь клавиши Enter. Я не частый разработчик для Windows, но я видел, как мои одноклассники просто включают <conio.h> и используют его. Смотрите conio.h в Википедии. Он перечисляет getch(), который объявлен устаревшим в Visual C++.

  2. проклятия доступны для Linux. Совместимые реализации curses доступны и для Windows. Он также имеет функцию getch(). (попробуйте man getch чтобы просмотреть его man- man getch). Смотрите Проклятия в Википедии.

Я бы порекомендовал вам использовать curses, если вы стремитесь к кроссплатформенности. Тем не менее, я уверен, что есть функции, которые вы можете использовать для отключения буферизации линии (я считаю, что это называется "сырой режим", а не "приготовленный режим" - посмотрите на man stty). Проклятия справятся с тобой портативно, если я не ошибаюсь.

+88
07 янв. '09 в 20:08
источник

В Linux (и других unix-подобных системах) это можно сделать следующим образом:

#include <unistd.h>
#include <termios.h>

char getch() {
        char buf = 0;
        struct termios old = {0};
        if (tcgetattr(0, &old) < 0)
                perror("tcsetattr()");
        old.c_lflag &= ~ICANON;
        old.c_lflag &= ~ECHO;
        old.c_cc[VMIN] = 1;
        old.c_cc[VTIME] = 0;
        if (tcsetattr(0, TCSANOW, &old) < 0)
                perror("tcsetattr ICANON");
        if (read(0, &buf, 1) < 0)
                perror ("read()");
        old.c_lflag |= ICANON;
        old.c_lflag |= ECHO;
        if (tcsetattr(0, TCSADRAIN, &old) < 0)
                perror ("tcsetattr ~ICANON");
        return (buf);
}

В основном вы должны отключить канонический режим (и режим эха для подавления эха).

+76
26 мая '09 в 21:14
источник

Связанные вопросы


Похожие вопросы

Я нашел это на другом форуме, пытаясь решить ту же проблему. Я немного изменил его из того, что нашел. Он отлично работает. Я запускаю OS X, поэтому, если вы используете Microsoft, вам нужно найти правильную команду system(), чтобы переключиться на сырые и приготовленные режимы.

#include <iostream> 
#include <stdio.h>  
using namespace std;  

int main() { 
  // Output prompt 
  cout << "Press any key to continue..." << endl; 

  // Set terminal to raw mode 
  system("stty raw"); 

  // Wait for single character 
  char input = getchar(); 

  // Echo input:
  cout << "--" << input << "--";

  // Reset terminal to normal "cooked" mode 
  system("stty cooked"); 

  // And we're out of here 
  return 0; 
}
+16
26 мая '09 в 19:07
источник

conio.h

нужны следующие функции:

int getch();
Prototype
    int _getch(void); 
Description
    _getch obtains a character  from stdin. Input is unbuffered, and this
    routine  will  return as  soon as  a character is  available  without 
    waiting for a carriage return. The character is not echoed to stdout.
    _getch bypasses the normal buffering done by getchar and getc. ungetc 
    cannot be used with _getch. 
Synonym
    Function: getch 


int kbhit();
Description
    Checks if a keyboard key has been pressed but not yet read. 
Return Value
    Returns a non-zero value if a key was pressed. Otherwise, returns 0.

libconio http://sourceforge.net/projects/libconio

или

Реализация Linux С++ для conio.h http://sourceforge.net/projects/linux-conioh

+14
07 янв. '09 в 21:37
источник

Если вы находитесь в окнах, вы можете использовать PeekConsoleInput, чтобы определить, есть ли какой-либо вход,

HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
DWORD events;
INPUT_RECORD buffer;
PeekConsoleInput( handle, &buffer, 1, &events );

затем используйте ReadConsoleInput для "потреблять" входной символ.

PeekConsoleInput(handle, &buffer, 1, &events);
if(events > 0)
{
    ReadConsoleInput(handle, &buffer, 1, &events);  
    return buffer.Event.KeyEvent.wVirtualKeyCode;
}
else return 0

честно говоря, это из какого-то старого кода, который у меня есть, поэтому вам придется немного поиграть с ним.

Приятно, однако, что он читает ввод без запроса чего-либо, поэтому символы вообще не отображаются.

+8
08 янв. '09 в 1:10
источник
#include <conio.h>

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

Это использует kbhit(), чтобы проверить, нажата ли клавиатура, и использует getch(), чтобы получить символ, который нажат.

+8
07 июл. '12 в 23:44
источник

C и С++ принимают очень абстрактный вид ввода-вывода, и нет стандартного способа делать то, что вы хотите. Существуют стандартные способы получения символов из стандартного входного потока, если они есть, и ничего другого не определяется ни одним из языков. Поэтому любой ответ должен быть специфичным для платформы, возможно, зависит не только от операционной системы, но и от программного обеспечения.

Здесь есть некоторые разумные догадки, но нет способа ответить на ваш вопрос, не зная, что такое целевая среда.

+5
07 янв. '09 в 20:59
источник

Предположив Windows, взгляните на функцию ReadConsoleInput.

+5
07 янв. '09 в 20:13
источник

Я использую kbhit(), чтобы увидеть, присутствует ли char, а затем getchar() для чтения данных. В окнах вы можете использовать "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;
}
+4
18 окт. '15 в 18:01
источник

Самое близкое к портативному - использовать библиотеку ncurses чтобы перевести терминал в "режим cbreak". API гигантский; процедуры, которые вы хотите больше всего,

  • initscr и endwin
  • cbreak и nocbreak
  • getch

Удачи!

+4
08 янв. '09 в 0:44
источник

Ниже приведено решение, извлеченное из Expert C Programming: Deep Secrets, которое должно работать на SVr4. Он использует stty и ioctl.

#include <sys/filio.h>
int kbhit()
{
 int i;
 ioctl(0, FIONREAD, &i);
 return i; /* return a count of chars available to read */
}
main()
{
 int i = 0;
 intc='';
 system("stty raw -echo");
 printf("enter 'q' to quit \n");
 for (;c!='q';i++) {
    if (kbhit()) {
        c=getchar();
       printf("\n got %c, on iteration %d",c, i);
    }
}
 system("stty cooked echo");
}
+3
08 янв. '09 в 9:04
источник

Я всегда хотел, чтобы цикл читал мой ввод без нажатия клавиши возврата. это сработало для меня.

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

    }
+2
19 февр. '15 в 19:10
источник

работает для меня в окнах:

#include <conio.h>
char c = _getch();
+2
12 июн. '15 в 6:40
источник

ncurses - отличный способ сделать это! Также это мой первый пост (который я помню), поэтому любые комментарии вообще приветствуются. Я по достоинству оценят полезные, но все приветствуются!

для компиляции: g++ -std = С++ 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;
}
+1
26 июн. '18 в 21:53
источник

Вы можете сделать это с помощью SDL (Simple DirectMedia Library), хотя я подозреваю, что вам может не нравиться его поведение. Когда я это пробовал, мне пришлось создать SDL новое видео-окно (даже если оно мне не понадобилось для моей программы), и у этого окна "хватают" почти все ввод клавиатуры и мыши (что было хорошо для моего использования, но могло быть раздражающим или неработоспособным в других ситуациях). Я подозреваю, что это излишнее и не стоит того, если полная переносимость - необходимость - в противном случае попробуйте одно из других предлагаемых решений.

Кстати, это даст вам нажатия клавиш и разблокировки отдельно, если вы в этом заняты.

+1
28 авг. '12 в 22:38
источник

Посмотрите другие вопросы по меткам или Задайте вопрос