怎样清空键盘缓冲区?

7

我写的小游戏在上一个场景中可能会有过多的按键事件,导致进入下一个场景后这些按键仍然被获取并处理。我希望在切换到下个场景时将缓冲区内的按键都清空。

我搜索到了 fflush(stdin); 语句,但是貌似并没有用。以下是我的测试代码:

// win10 + vs2019
//
#include <easyx.h>
#include <stdio.h>
#include <conio.h>

int main()
{
	while (true)
	{
		printf("_kbhit() == %d\n", _kbhit());

		if (_kbhit())
		{
			// 清空键盘缓冲区(无效)
			fflush(stdin);
		}

		Sleep(1000);
	}
	return 0;
}

上面的代码执行以后,_kbhit() 返回 0,按任意键后,_kbhit() 会一直返回 1,表示键盘缓冲区里面还有按键,可见 fflush(stdin) 并没有清空键盘缓冲区。

请问有什么办法可以清空键盘缓冲区吗?

ava
BestAns

2019-11-20

8

有两个方法给你参考:

方法一,调用 _getch() 函数,结合循环,取走缓存里的所有按键。

	while (_kbhit())
	{
		_getch();
	}

方法二,调用 Windows API 清空控制台的输入缓存:

FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));

以上两种方法我都测试过了,直接替换掉你代码里面的 fflush(stdin) 就行。

关于控制台缓冲区

控制台的输入有两个环节:低级(底层)和高级。底层处理完输入以后,会将输入以“流”的形式发给高级处理。

scanf 属于相对高级的控制台输入函数,从输入流中获取内容。所以,针对输入流的清空操作,可以避免 scanf 收到过期的输入。

但是 getch 并不依赖于输入流,必须使用底层的控制台操作函数才可以。FlushConsoleInputBuffer 就是底层的控制台操作函数。

如果底层的输入已经处理完毕并以“流”的形式发给高级处理,那么清空底层的输入是无法清空输入流的。所以 FlushConsoleInputBuffer 对 scanf 造成的残留输入无效。

ava
慢羊羊

2019-11-20

我测试发现两种方法都对 wscanf_s 无效,楼下方法可用。 -  huidong  2022-8-20
@huidong scanf 和 getch 的缓冲级别不一样。 -  慢羊羊  2022-8-22
1

可以用

rewind(stdin);

方便些

ava
点缀星空

2021-12-10

在 vc6、vc2022 下,针对 _getch 均无效。 -  慢羊羊  2022-8-22
技术讨论社区