Как не нажимать enter с помощью getchar ()

Это вопрос «новато» для языка программирования C:

В следующем коде:

#include  int main(void) { int c; while ((c=getchar())!= EOF) putchar(c); return 0; } 

Я должен нажать Enter, чтобы напечатать все буквы, которые я ввел с помощью getchar , но я не хочу этого делать, я хочу нажать букву и сразу увидеть букву, которую я вводил, без нажатия Enter . Например, если я нажму букву «a», я хочу увидеть другую «a» рядом с ней и так далее:

 aabbccddeeff..... 

Но когда я нажимаю «ничего», я могу писать другие буквы, и копия появляется только тогда, когда я нажимаю Enter :

 abcdef abcdef 

Как я могу это сделать?

Я использую команду cc -o example example.c в Ubuntu для компиляции.

В linux-системе вы можете изменять поведение терминала с помощью команды stty . По умолчанию терминал будет буферизовать всю информацию до тех пор, пока не будет нажата клавиша « Ввод» , прежде чем отправить ее в программу C.

Быстрый, грязный и не особенно портативный пример для изменения поведения внутри самой программы:

 #include int main(void){ int c; /* use system call to make terminal send all keystrokes directly to stdin */ system ("/bin/stty raw"); while((c=getchar())!= '.') { /* type a period to break out of the loop, since CTRL-D won't work raw */ putchar(c); } /* use system call to set terminal behaviour to more normal behaviour */ system ("/bin/stty cooked"); return 0; } 

Обратите внимание, что это не совсем оптимально, так как это просто предполагает, что stty cooked – это поведение, которое вы хотите, когда программа выходит, вместо того, чтобы проверять, что такое исходные настройки терминала. Кроме того, поскольку вся специальная обработка пропускается в необработанном режиме, многие ключевые последовательности (такие как CTRL-C или CTRL-D ) на самом деле не будут работать, как вы ожидаете, их явно не будут обрабатывать в программе.

Вы можете управлять man stty для большего контроля над поведением терминала, в зависимости от того, чего вы хотите достичь.

Это зависит от вашей ОС, если вы находитесь в подобной среде с UNIX, флаг ICANON по умолчанию включен, поэтому вход буферизуется до следующего '\n' или EOF . Отключив канонический режим, вы сразу получите персонажей. Это также возможно на других платформах, но нет прямого межплатформенного решения.

EDIT: Я вижу, вы указали, что используете Ubuntu. Я только что опубликовал что-то подобное вчера, но имейте в виду, что это отключит многие по умолчанию поведение вашего терминала.

 #include #include  //termios, TCSANOW, ECHO, ICANON #include  //STDIN_FILENO int main(void){ int c; static struct termios oldt, newt; /*tcgetattr gets the parameters of the current terminal STDIN_FILENO will tell tcgetattr that it should write the settings of stdin to oldt*/ tcgetattr( STDIN_FILENO, &oldt); /*now the settings will be copied*/ newt = oldt; /*ICANON normally takes care that one line at a time will be processed that means it will return if it sees a "\n" or an EOF or an EOL*/ newt.c_lflag &= ~(ICANON); /*Those new settings will be set to STDIN TCSANOW tells tcsetattr to change attributes immediately. */ tcsetattr( STDIN_FILENO, TCSANOW, &newt); /*This is your part: I choose 'e' to end input. Notice that EOF is also turned off in the non-canonical mode*/ while((c=getchar())!= 'e') putchar(c); /*restore the old settings*/ tcsetattr( STDIN_FILENO, TCSANOW, &oldt); return 0; } 

Вы заметите, что каждый символ появляется дважды. Это связано с тем, что вход сразу возвращается к терминалу, а затем ваша программа возвращает его также с помощью putchar() . Если вы хотите отключить входной сигнал от выхода, вам также необходимо включить флаг ECHO. Вы можете сделать это, просто изменив соответствующую строку:

 newt.c_lflag &= ~(ICANON | ECHO); 

getchar () – стандартная функция, которая на многих платформах требует, чтобы вы нажимали ENTER, чтобы получить вход, потому что буферы платформы вводятся до тех пор, пока эта клавиша не будет нажата. Многие компиляторы / платформы поддерживают нестандартный getch (), который не заботится о ENTER (обходит буферизацию платформы, обрабатывает ENTER как просто еще один ключ).

I / O – это функция операционной системы. Во многих случаях операционная система не передает типизированный символ программе, пока не будет нажата клавиша ENTER. Это позволяет пользователю изменять входные данные (например, обратную опцию и повторный набор) перед отправкой в ​​программу. Для большинства целей это хорошо работает, представляет собой согласованный интерфейс для пользователя и освобождает программу от необходимости иметь дело с этим. В некоторых случаях желательно, чтобы программа получала символы от клавиш по мере их нажатия.

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

Кроме того, стандартный выход обычно буферизуется для повышения эффективности. Это выполняется библиотеками C, поэтому существует C-решение, которое должно fflush(stdout); после каждого написанного персонажа. После этого, отображаются ли символы немедленно, зависит от операционной системы, но все операционные системы, с которыми я знаком, будут отображать результат немедленно, так что это обычно не проблема.

Поскольку вы работаете над производным Unix (Ubuntu), вот один из способов сделать это – не рекомендуется, но он будет работать (пока вы можете точно набирать команды):

 echo "stty -g $(stty -g)" > restore-sanity stty cbreak ./your_program 

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

 sh restore-sanity 
  • Строка ‘echo’ сохраняет текущие настройки терминала в качестве сценария оболочки, который будет их восстанавливать.
  • Строка ‘stty’ отключает большую часть специальной обработки (поэтому Control-D не действует, например) и отправляет символы в программу, как только они будут доступны. Это означает, что вы больше не можете редактировать свой ввод.
  • Строка ‘sh’ восстанавливает исходные настройки терминала.

Вы можете экономить, если «stty sane» восстанавливает ваши настройки достаточно точно для ваших целей. Формат «-g» не переносится в разных версиях «stty» (поэтому то, что генерируется в Solaris 10, не будет работать на Linux или наоборот), но концепция работает повсеместно. Опция «stty sane» не универсальна, AFAIK (но находится в Linux).

Мне нравится, что Лукас отвечает, но я хотел бы кое-что уточнить. В termios.h есть встроенная функция termios.h cfmakeraw() которую человек описывает как:

 cfmakeraw() sets the terminal to something like the "raw" mode of the old Version 7 terminal driver: input is available character by character, echoing is disabled, and all special processing of terminal input and output characters is disabled. [...] 

Это в основном делает то же самое, что предлагает Лукас и многое другое, вы можете видеть точные флаги, которые он устанавливает на страницах man: termios (3) .

Случай использования

 int c = 0; static struct termios oldTermios, newTermios; tcgetattr(STDIN_FILENO, &oldTermios); newTermios = oldTermios; cfmakeraw(&newTermios); tcsetattr(STDIN_FILENO, TCSANOW, &newTermios); c = getchar(); tcsetattr(STDIN_FILENO, TCSANOW, &oldTermios); switch (c) { case 113: // q printf("\n\n"); exit(0); break; case 105: // i printf("insert\n"); break; default: break; 

По умолчанию библиотека C буферизует вывод до тех пор, пока не увидит возврат. Чтобы немедленно распечатать результаты, используйте fflush :

 while((c=getchar())!= EOF) { putchar(c); fflush(stdout); } 

Вы можете включить библиотеку «ncurses» и использовать getch() вместо getchar() .

да, вы можете сделать это и на windowsх, вот код ниже, используя библиотеку conio.h

 #include  //basic input/output #include  //provides non standard getch() function using namespace std; int main() { cout << "Password: "; string pass; while(true) { char ch = getch(); if(ch=='\r'){ //when a carriage return is found [enter] key cout << endl << "Your password is: " << pass < в #include  //basic input/output #include  //provides non standard getch() function using namespace std; int main() { cout << "Password: "; string pass; while(true) { char ch = getch(); if(ch=='\r'){ //when a carriage return is found [enter] key cout << endl << "Your password is: " << pass < 

У меня возникла эта проблема / вопрос в задании, над которым я сейчас работаю. Это также зависит от того, с какого входа вы захватываете. я использую

 /dev/tty 

для ввода ввода во время работы программы, поэтому для этого должен быть stream, связанный с командой.

На машине ubuntu мне нужно протестировать / настроить, это потребовало больше, чем просто

 system( "stty -raw" ); 

или

 system( "stty -icanon" ); 

Мне пришлось добавить флаг -file, а также путь к команде, например:

 system( "/bin/stty --file=/dev/tty -icanon" ); 

Сейчас все копакетично.

Давайте будем гением компьютера.