There is my code, a simple console program that consists of menu() function for now.
void menu() {
int k = 0;
HANDLE s_in = GetStdHandle(STD_INPUT_HANDLE);
DWORD dr;
INPUT_RECORD rec;
printf("Choose a num\n");
char vars[] = { '1. A', '2. B', '3. C' };
while (true)
{
for (int i = 0; i < sizeof(vars) / sizeof(vars[0]); i++) {
if (k == i) printf("%c [*]\n", vars[i]);
else printf("%c\n", vars[i]);
}
ReadConsoleInput(s_in, &rec, sizeof(INPUT_RECORD), &dr);
FlushConsoleInputBuffer(s_in);
if (rec.EventType == KEY_EVENT) {
if (rec.Event.KeyEvent.bKeyDown) {
switch (rec.Event.KeyEvent.wVirtualKeyCode) {
case VK_UP:
if (k > 0) k--;
break;
case VK_DOWN:
if (k < ((sizeof(vars) / sizeof(vars[0])) - 1)) k++;
break;
default:
printf("Use UP or DOWN arrows\n");
break;
}
}
}
}
}
int main()
{
menu();
}
Unfortunately, there is one problem that ruins everything. I'm using <windows.h> to read keyboard buttons from console, but ReadConsoleInput() function catches all states of button (pressed and released), so I'm getting double printed vars[] every every time I press a key (up and down arrows in this case). How can "key-ups" be ignored, and only "key-downs" can be catched?
Every time ReadConsoleInput
returns, you go through the if
and then go back to the beginning of the loop and print the "menu" (vars
). ReadConsoleInput
returns whenever a button is pressed or released. You can even see that pressing a button that isn't VK_UP
or VK_DOWN
will print "Use UP or DOWN arrows\n"
, but then releasing that button will not print this line.
A simple solution is to wrap ReadConsoleInput
in a loop to filter out the events you don't want.
do {
ReadConsoleInput(s_in, &rec, 1, &dr);
FlushConsoleInputBuffer(s_in);
} while (rec.EventType == KEY_EVENT && !rec.Event.KeyEvent.bKeyDown);
Probably a better solution is to move the menu printing outside of the loop and repeat it at the end of the keydown processing:
for (int i = 0; i < sizeof(vars) / sizeof(vars[0]); i++) {
if (k == i) printf("%c [*]\n", vars[i]);
else printf("%c\n", vars[i]);
}
while (true)
{
ReadConsoleInput(s_in, &rec, 1, &dr);
if (rec.EventType == KEY_EVENT) {
if (rec.Event.KeyEvent.bKeyDown) {
switch (rec.Event.KeyEvent.wVirtualKeyCode) {
case VK_UP:
if (k > 0) k--;
break;
case VK_DOWN:
if (k < ((sizeof(vars) / sizeof(vars[0])) - 1)) k++;
break;
default:
printf("Use UP or DOWN arrows\n");
break;
}
for (int i = 0; i < sizeof(vars) / sizeof(vars[0]); i++) {
if (k == i) printf("%c [*]\n", vars[i]);
else printf("%c\n", vars[i]);
}
}
}
}
The menu printing should really be a function at this point, so you don't have to repeat these lines of code. Note that this also eliminates the need for FlushConsoleInputBuffer
.