Захват символов из стандартного ввода, не дожидаясь нажатия клавиши enter
Я никогда не могу вспомнить, как я это делаю, потому что это происходит так редко для меня. Но в C или c++, каков наилучший способ прочитать символ из стандартного ввода, не дожидаясь новой строки (нажмите enter).
также В идеале он не будет эхом входного символа на экране. Я просто хочу захватить нажатия клавиш без воздействия на экран консоли.
15 ответов:
это невозможно переносимо в чистом C++, потому что это слишком сильно зависит от используемого терминала, который может быть связан с stdin (они обычно буферизуются линией). Вы можете, однако, использовать библиотеку для этого:
- conio доступно с компиляторами windows. Используйте функцию
_getch()чтобы дать вам символ, не дожидаясь ввода ключа. Я не часто разработчик windows, но я видел, что мои одноклассники просто включаютconio.hи использовать его. Смотрите conio.h at Википедия. Он перечисляетgetch, который объявлен устаревшим в Visual C++.- проклятия доступны для linux, совместимые реализации проклятий доступны и для windows. Он также имеет
в 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); }В общем, вы должны отключить канонический режим (и режим ЭХО подавление Эхо).
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 c++ реализация conio.ч http://sourceforge.net/projects/linux-conioh
Я нашел это на другом форуме, пытаясь решить ту же проблему. Я изменил его немного от того, что я нашел. Он отлично работает. Я запускаю 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; }
#include <conio.h> if (kbhit() != 0) { cout << getch() << endl; }использует
kbhit()чтобы проверить, если клавиатура нажата и используетgetch()чтобы получить символ, который нажимается.
Если вы находитесь на Windows, вы можете использовать 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честно говоря, это из какого-то старого кода у меня есть, так что вам придется немного повозиться с ним.
самое классное, что он читает ввод без запроса на что-либо, поэтому символы не отображаются вообще.
C и C++ принимают очень абстрактный вид ввода / вывода, и нет стандартного способа делать то, что вы хотите. Существуют стандартные способы получения символов из стандартного входного потока, если таковые имеются, и ничто другое не определяется ни одним из языков. Поэтому любой ответ должен быть специфичным для платформы, возможно, в зависимости не только от операционной системы, но и от программного обеспечения.
есть некоторые разумные предположения, но нет никакого способа, чтобы ответить на ваш вопрос не зная, что такое ваша целевая среда.
самое близкое к портативному-использовать
ncursesбиблиотека для перевода терминала в режим"cbreak". API гигантский; процедуры, которые вы хотите больше всего
initscrиendwincbreakиnocbreakgetchудачи!
ниже приводится решение, извлеченное из Эксперт C Программирование: Глубокие Секреты, который должен работать на 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"); }
Я всегда хотел, чтобы цикл считывал мой ввод, не нажимая клавишу возврата. это сработало для меня.
#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 } }
Я использую kbhit (), чтобы увидеть, присутствует ли символ, а затем getchar () для чтения данных. В windows вы можете использовать "conio.ч." В 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; }
вы можете сделать это переносимо с помощью SDL (простая библиотека DirectMedia), хотя я подозреваю, что вам может не понравиться его поведение. Когда я попробовал это, мне пришлось создать SDL новое окно видео (хотя мне это не нужно для моей программы) и иметь это окно "захватить" почти весь ввод клавиатуры и мыши (что было хорошо для моего использования, но может быть раздражающим или неработоспособным в других ситуациях). Я подозреваю, что это перебор и не стоит того, если полная переносимость не является обязательным-в противном случае попробуйте один из других предлагаемое решение.
кстати, это даст вам ключ нажмите и отпустите события отдельно,если вы в этом.
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; }
Comments