Как очистить буфер клавиатуры в c
Перейти к содержимому

Как очистить буфер клавиатуры в c

  • автор:

C # или .NET Flushing Keyboard Buffer

Как очистить буфер клавиатуры в С# с помощью Windows Forms?

У меня есть сканер штрих-кода, который действует как клавиатура. Если действительно длинный штрих-код сканируется и кнопка отмены нажата на форму, мне нужно, чтобы буфер клавиатуры был очищен. Поэтому мне нужно очистить и игнорировать все ожидающие ввода. Мне нужно очистить буфер, потому что, если штрих-код содержит пробелы, пробелы обрабатываются как нажатия кнопок, которые не нужны.

7 ответов

Я не уверен, что вы можете это сделать. Клавиши переходят в очередь событий для основного цикла событий. Любые действия, которые вы предпринимаете для отмены этих нажатий клавиш, будут помещены в очередь после нажатия клавиш.

Цикл событий будет только доходить до вашего действия отмены после обработки нажатий клавиш. Вы можете только отменить нажатия клавиш на основе какого-либо события, которое происходит в середине последовательности нажатия клавиш.

How to clear input buffer in C?

As the author of the above code have explained: The program will not work properly because at Line 1, when the user presses Enter, it will leave in the input buffer 2 character: Enter key (ASCII code 13) and \n (ASCII code 10) . Therefore, at Line 2, it will read the \n and will not wait for the user to enter a character.

OK, I got this. But my first question is: Why the second getchar() ( ch2 = getchar(); ) does not read the Enter key (13) , rather than \n character?

Next, the author proposed 2 ways to solve such probrems:

write a function like this:

This code worked actually. But I cannot explain myself how it works? Because in the while statement, we use getchar() != ‘\n’ , that means read any single character except ‘\n’ ? if so, in the input buffer still remains the ‘\n’ character?

18 Answers 18

The program will not work properly because at Line 1, when the user presses Enter, it will leave in the input buffer 2 character: Enter key (ASCII code 13) and \n (ASCII code 10). Therefore, at Line 2, it will read the \n and will not wait for the user to enter a character.

The behavior you see at line 2 is correct, but that’s not quite the correct explanation. With text-mode streams, it doesn’t matter what line-endings your platform uses (whether carriage return (0x0D) + linefeed (0x0A), a bare CR, or a bare LF). The C runtime library will take care of that for you: your program will see just ‘\n’ for newlines.

If you typed a character and pressed enter, then that input character would be read by line 1, and then ‘\n’ would be read by line 2. See I’m using scanf %c to read a Y/N response, but later input gets skipped. from the comp.lang.c FAQ.

As for the proposed solutions, see (again from the comp.lang.c FAQ):

which basically state that the only portable approach is to do:

Your getchar() != ‘\n’ loop works because once you call getchar() , the returned character already has been removed from the input stream.

Also, I feel obligated to discourage you from using scanf entirely: Why does everyone say not to use scanf ? What should I use instead?

You can do it (also) this way:

Ramy Al Zuhouri's user avatar

A portable way to clear up to the end of a line that you’ve already tried to read partially is:

This reads and discards characters until it gets \n which signals the end of the file. It also checks against EOF in case the input stream gets closed before the end of the line. The type of c must be int (or larger) in order to be able to hold the value EOF .

There is no portable way to find out if there are any more lines after the current line (if there aren’t, then getchar will block for input).

doesn’t read only the characters before the linefeed ( ‘\n’ ). It reads all the characters in the stream (and discards them) up to and including the next linefeed (or EOF is encountered). For the test to be true, it has to read the linefeed first; so when the loop stops, the linefeed was the last character read, but it has been read.

As for why it reads a linefeed instead of a carriage return, that’s because the system has translated the return to a linefeed. When enter is pressed, that signals the end of the line. but the stream contains a line feed instead since that’s the normal end-of-line marker for the system. That might be platform dependent.

Also, using fflush() on an input stream doesn’t work on all platforms; for example it doesn’t generally work on Linux.

Jonathan Leffler's user avatar

But I cannot explain myself how it works? Because in the while statement, we use getchar() != ‘\n’ , that means read any single character except ‘\n’ ?? if so, in the input buffer still remains the ‘\n’ character. Am I misunderstanding something??

The thing you may not realize is that the comparison happens after getchar() removes the character from the input buffer. So when you reach the ‘\n’ , it is consumed and then you break out of the loop.

where %*c accepts and ignores the newline

one more method instead of fflush(stdin) which invokes undefined behaviour you can write

don’t forget the semicolon after while loop

kapil's user avatar

scanf is a strange function, and there’s a classic line from the movie WarGames that’s relevant: "The only winning move is not to play".

If you find yourself needing to "flush input", you have already lost. The winning move is not to search desperately for some magic way to flush the nettlesome input: instead, what you need to do is to do input in some different (better) way, that doesn’t involve leaving unread input on the input stream, and having it sit there and cause problems, such that you have to try to flush it instead.

There are basically three cases:

You are reading input using scanf , and it is leaving the user’s newline on the input stream, and that stray newline is wrongly getting read by a later call to getchar or fgets . (This is the case you were initially asking about.)

You are reading input using scanf , and it is leaving the user’s newline on the input stream, and that stray newline is wrongly getting read by a later call to scanf("%c") .

You are reading numeric input using scanf , and the user is typing non-numeric text, and the non-numeric text is getting left on the input stream, meaning that the next call to scanf fails on it also.

In all three cases, it may seem like the right thing to do is to "flush" the offending input. And you can try, but it’s cumbersome at best and impossible at worst. In the end I believe that trying to flush input is the wrong approach, and that there are better ways, depending on which case you were worried about:

In case 1, the better solution is, do not mix calls to scanf with other input functions. Either do all your input with scanf , or do all your input with getchar and/or fgets . To do all your input with scanf , you can replace calls to getchar with scanf("%c") — but see point 2. Theoretically you can replace calls to fgets with scanf("%[^\n]%*c") , although this has all sorts of further problems and I do not recommend it. To do all your input with fgets even though you wanted/needed some of scanf ‘s parsing, you can read lines using fgets and then parse them after the fact using sscanf .

In case 2, the better solution is, never use scanf("%c") . Use scanf(" %c") instead. The magic extra space makes all the difference. (There’s a long explanation of what that extra space does and why it helps, but it’s beyond the scope of this answer.)

And in case 3, I’m afraid that there simply is no good solution. scanf has many problems, and one of its many problems is that its error handling is terrible. If you want to write a simple program that reads numeric input, and if you can assume that the user will always type proper numeric input when prompted to, then scanf("%d") can be an adequate — barely adequate — input method. But perhaps your goal is to do better. Perhaps you’d like to prompt the user for some numeric input, and check that the user did in fact enter numeric input, and if not, print an error message and ask the user to try again. In that case, I believe that for all intents and purposes you cannot meet this goal based around scanf . You can try, but it’s like putting a onesie on a squirming baby: after getting both legs and one arm in, while you’re trying to get the second arm in, one leg will have wriggled out. It is just far too much work to try to read and validate possibly-incorrect numeric input using scanf . It is far, far easier to do it some other way.

You will notice a theme running through all three cases I listed: they all began with "You are reading input using scanf . ". There’s a certain inescapable conclusion here. See this other question: What can I use for input conversion instead of scanf?

Now, I realize I still haven’t answered the question you actually asked. When people ask, "How do I do X?", it can be really frustrating when all the answers are, "You shouldn’t want to do X." If you really, really want to flush input, then besides the other answers people have given you here, two other good questions full of relevant answers are:

Очистка буфера клавиатуры C # или .NET

Как очистить буфер клавиатуры в C # с помощью Windows Forms?

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

7 ответов

Я не уверен, что ты сможешь это сделать. Нажатия клавиш попадают в очередь событий для основного цикла событий. Любое действие, которое вы предпримете для отмены этих нажатий клавиш, будет помещено в очередь после нажатия клавиш.

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

Установите для KeyPreview в форме значение true , затем перехватите событие KeyPress и установите для e.Handled значение true , если была нажата отмена.

ИЗМЕНИТЬ : перехватить событие KeyPress формы .

Console.KeyAvailable вызвал у меня исключение, потому что у консоли не было фокуса.

Однако сообщение об исключении было полезным. Он предложил использовать Console.In.Peek() для чтения в этом случае.

Я подумал, что стоит упомянуть здесь как альтернативное решение и для потомков.

Отключите форму и принудительно выполните всю обработку с помощью DoEvents, пока она отключена. Элементы управления должны отклонять любые комбинации клавиш, потому что они отключены. Затем снова включите форму.

Русские Блоги

На самом деле, многие большие парни писали в блогах об очистке области кеширования, и я все это устрою.
СпасибоЮжэ_АнфилдБольшинство сообщений в блоге
благодаритьФиолетовые слезыБольшинство сообщений в блоге
благодаритьКитайская сеть на языке C
Теперь перейдем к основной теме, сначала разберемся с буферной областью.

Каталог статей

Буферная область

Буфер на языке C также называется кешем, это часть пространства памяти.
Другими словами, в области памяти зарезервирован определенный объем дискового пространства. Эти пространства хранения используются для буферизации входных или выходных данных. Эта часть зарезервированного пространства называется буфером.
Буфер языка C делится на три типа: 1. Полный буфер 2. Строчный буфер 3. Без буфера.
буфер делится на входной буфер и выходной буфер в зависимости от того, соответствует ли он устройству ввода или устройству вывода.

Например, когда мы обычно хотим прочитать информацию с диска, мы сначала помещаем данные в буферную область, а после чтения мы снова считываем информацию с диска.
Область кэша, ее смысл — это область между высокоскоростным ЦП и низкоскоростным устройством. Эта область заставляет ЦП работать более эффективно.

Полностью буферизованный
Когда стандартный буфер ввода-вывода заполнен, выполняется фактическая операция ввода-вывода. Типичным представителем полной буферизации является чтение и запись файлов на диск.

Буфер строки
Когда во вводе и выводе встречается символ новой строки, выполняется фактическая операция ввода-вывода. В это время символы, которые мы вводим, сначала сохраняются в буфере, а затем выполняется фактическая операция ввода-вывода при нажатии клавиши ввода для переноса. Типичными представителями являются стандартный ввод (stdin) и стандартный вывод (stdout).

Без буфера
То есть буферизация не выполняется. Стандартное условие ошибки stderr является типичным представителем, которое позволяет сразу отображать информацию об ошибке в кратчайшие сроки.

Большинство систем по умолчанию используют следующие типы кеша:
Стандартные ошибки не кэшируются.
Если это поток с терминальными устройствами, они буферизуются по строкам, в противном случае они полностью буферизуются.

Входные и выходные потоки, которые мы часто используем, характеристики текущего кэша ANSI C следующие: stdin и stdout — это кеши строк; stderr не кэшируется.

Теперь, когда мы это понимаем, перейдем к основной теме.
Это связано с тем, что иногда вы вводите символ после ввода символа. Если вы не очистите буфер, последний символ все еще будет в вашем буфере! Это вызвало ошибку!

Очистить буфер

1. Используйте функцию fflush ().

Функция fflush () сбрасывает информацию в потоке. Эта функция обычно используется для обработки файлов на диске. При очистке буфера чтения-записи данные в выходном буфере должны быть немедленно записаны физически. Функция fflush () содержится вstdio.hЗаголовочный файл.
Возвращаемое значение функции: при успешном обновлении возвращается 0, а при сбое — EOF. Он также возвращает 0, если буфер отсутствует или открыт только для чтения.
Также обратите внимание: если fflush возвращает EOF, данные могли быть потеряны из-за ошибок записи.
Пример использования: fflush (stdin) обновляет стандартный буфер ввода, fflush (stdout) обновляет буфер стандартного вывода. printf (". "); Добавьте затем fflush (stdout); может повысить эффективность печати
Пример кода:


При выполнении этой программы мы обнаружим, что после того, как мы введем первый символ и нажмем ‘\ n’, программа завершится, потому что мы не очистили буфер. Функция getchar () получила ‘\ n’, что, в конце концов, привело к остановке программы.
Далее мы будем использовать функцию fflush ().


Здесь мы видим, что когда функция fflush () используется для очистки буферной области входного потока, функция getchar может нормально принимать символы.

2. Используйте оператор while ((ch = getchar ())! = ‘\ N’ && ch! = EOF);

Этот метод можно назвать универсальной очисткой буферного кеша.
Пример кода:

Здесь мы еще не очистили буферную область, в результате функция getchar () все еще получает ‘\ n’, что приводит к остановке программы.
Затем мы используем оператор while ((ch = getchar ())! = ‘\ n’ && ch! = EOF);

Добавлен оператор while ((ch = getchar ())! = EOF && ch! = ‘\ N’); для завершения очистки буферной области
Фактически, иногда мы инкапсулируем этот оператор в функцию, что делает программу более переносимой.

3. Используйте инструкцию scanf ("% * [^ \ n]"); scanf ("% * c");

Принцип такой:
Первое, что нужно понять, это то, что, когда буфер необходимо очистить, последний символ в буфере должен быть символом новой строки \ n, потому что входной буфер находится в режиме строкового буфера, и пользователь нажимает Клавиша Enter сгенерирует символ новой строки, завершит ввод, а затем войдет в функцию для начала чтения.

scanf("%*[^\n]") ; Очистить все символы перед символом новой строки, scanf("%*c") ; Очистить последние оставшиеся символы новой строки.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *