Захват символов со стандартного ввода без ожидания нажатия клавиши
Я никогда не могу вспомнить, как я это делаю, потому что это происходит редко для меня. Но в C или С++, как лучше всего читать символ со стандартного ввода, не дожидаясь новой строки (нажмите enter).
В идеале он не будет отображать входной символ на экране. Я просто хочу захватить нажатия клавиш, не используя экран консоли.
Ответы
Ответ 1
Это невозможно в портативном виде в чистом C++, потому что это слишком сильно зависит от используемого терминала, который может быть подключен к stdin
(обычно это буферизованная линия). Однако вы можете использовать библиотеку для этого:
-
conio доступен с компиляторами Windows. Используйте _getch()
чтобы дать вам символ, не дожидаясь клавиши Enter. Я не частый разработчик для Windows, но я видел, как мои одноклассники просто включают <conio.h>
и используют его. Смотрите conio.h
в Википедии. Он перечисляет getch()
, который объявлен устаревшим в Visual C++.
-
проклятия доступны для Linux. Совместимые реализации curses доступны и для Windows. Он также имеет функцию getch()
. (попробуйте man getch
чтобы просмотреть его man- man getch
). Смотрите Проклятия в Википедии.
Я бы порекомендовал вам использовать curses, если вы стремитесь к кроссплатформенности. Тем не менее, я уверен, что есть функции, которые вы можете использовать для отключения буферизации линии (я считаю, что это называется "сырой режим", а не "приготовленный режим" - посмотрите на man stty
). Проклятия справятся с тобой портативно, если я не ошибаюсь.
Ответ 2
В 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);
}
В основном вы должны отключить канонический режим (и режим эха для подавления эха).
Ответ 3
Я нашел это на другом форуме, пытаясь решить ту же проблему. Я немного изменил его из того, что нашел. Он отлично работает. Я запускаю 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;
}
Ответ 4
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
Ответ 5
Если вы находитесь в окнах, вы можете использовать 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
честно говоря, это из какого-то старого кода, который у меня есть, поэтому вам придется немного поиграть с ним.
Приятно, однако, что он читает ввод без запроса чего-либо, поэтому символы вообще не отображаются.
Ответ 6
#include <conio.h>
if (kbhit() != 0) {
cout << getch() << endl;
}
Это использует kbhit()
, чтобы проверить, нажата ли клавиатура, и использует getch()
, чтобы получить символ, который нажат.
Ответ 7
Предположив Windows, взгляните на функцию ReadConsoleInput.
Ответ 8
C и С++ принимают очень абстрактный вид ввода-вывода, и нет стандартного способа делать то, что вы хотите. Существуют стандартные способы получения символов из стандартного входного потока, если они есть, и ничего другого не определяется ни одним из языков. Поэтому любой ответ должен быть специфичным для платформы, возможно, зависит не только от операционной системы, но и от программного обеспечения.
Здесь есть некоторые разумные догадки, но нет способа ответить на ваш вопрос, не зная, что такое целевая среда.
Ответ 9
Самое близкое к портативному - использовать библиотеку ncurses
чтобы перевести терминал в "режим cbreak". API гигантский; процедуры, которые вы хотите больше всего,
-
initscr
и endwin
-
cbreak
и nocbreak
-
getch
Удачи!
Ответ 10
Я использую 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;
}
Ответ 11
Ниже приведено решение, извлеченное из 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");
}
Ответ 12
Я всегда хотел, чтобы цикл читал мой ввод без нажатия клавиши возврата.
это сработало для меня.
#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
}
}
Ответ 13
работает для меня в окнах:
#include <conio.h>
char c = _getch();
Ответ 14
Вы можете сделать это с помощью SDL (Simple DirectMedia Library), хотя я подозреваю, что вам может не нравиться его поведение. Когда я это пробовал, мне пришлось создать SDL новое видео-окно (даже если оно мне не понадобилось для моей программы), и у этого окна "хватают" почти все ввод клавиатуры и мыши (что было хорошо для моего использования, но могло быть раздражающим или неработоспособным в других ситуациях). Я подозреваю, что это излишнее и не стоит того, если полная переносимость - необходимость - в противном случае попробуйте одно из других предлагаемых решений.
Кстати, это даст вам нажатия клавиш и разблокировки отдельно, если вы в этом заняты.
Ответ 15
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;
}