Как прочитать один символ из консоли?
У меня есть программа:
char getChar() {
return /*smth*/;
}
printf("INPUT: ");
char chr = getСhar();
printf("OUTPUT: %c", chr);
...и проблема: что должна возвращать getChar? Мне нужно, чтобы после нажатия кнопки на клавиатуре нажатый символ немедленно был прочитан. Вариант по сути 1 - getchar (не путать с getChar - getChar - моя функция, а getchar - функция из stdio.h). Но при его использовании я могу ввести более 1-го символа, например:
INPUT: qwerty1234567890
OUTPUT: q
Я знаю, что такая функция есть в .NET (Console.ReadKey), и, взглянув на её реализацию, понял, что здесь нужен WinAPI и функция ReadConsoleInput. Вот как её использую я (без проверок):
char getChar() {
INPUT_RECORD inputRecord; // запись о введённом символе
unsigned long readedCharCount; // кол-во прочитанных символов
ReadConsoleInput(
GetStdHandle(STD_INPUT_HANDLE), // возвращаем дескриптор ввода консоли
&inputRecord,
1,
&readedCharCount);
return inputRecord.Event.KeyEvent.uChar.AsciiChar; // извлекаем из записи нажатый символ
}
Но когда я запускаю программу выше (getchar -> getChar), происходит неописуемое. Если запускать по-шагово, то при входе в функцию ReadConsoleInput программа зависает и я не могу ввести ничего в консоль. Если же поставить breakpoint после данной функции, то консоль мне не даст ввести символ, и можно обнаружить, что inputRecord.EventType == 16, а должно равняться 1 (KEY_EVENT). Причём нет ни одного xxx_EVENT-макроса со значением 16! Как это понимать, и что я делаю не так?
Ответы (1 шт):
16 в INPUT_RECORD.EventType - это FOCUS_EVENT, что естественно, ведь при переключении с отладчика на консоль она первым делом получает фокус ввода. Нужно просто пропускать все ненужные события при чтении:
WORD ReadKey(HANDLE hInput) {
INPUT_RECORD ir; DWORD t;
while (ReadConsoleInput(hInput, &ir, 1, &t)) {
if (ir.EventType != KEY_EVENT) continue; // игнорируем все события, кроме KEY_EVENT
if (ir.Event.KeyEvent.bKeyDown) return ir.Event.KeyEvent.wVirtualKeyCode;
}
return 0; // возвращаем 0 в случае ошибки ReadConsoleInput
}