原因
因为 getch / getchar 是控制台函数,依赖控制台的形式。
新的 windows 升级后将 PowerShell 作为默认控制台,导致 easyx 无法获取到 cmd 的输入,从而导致这个问题。
方法一:恢复原来的 cmd 控制台
打开 win11 的系统设置 -> 隐私和安全性 -> 开发者选项,找到“终端”项,里面有三项:“让 Windows 决定(默认)、Windows 控制台主机、Windows 终端”,改为“Windows 控制台主机”即可。
方法二:替换 getch() 获取字符输入
可以将对应的获取按键语句修改为用 getmessage 实现,具体如下:
#include <graphics.h>
#include <conio.h>
#include <stdlib.h>
int main()
{
initgraph(640, 480);
ExMessage m;
do
{
m = getmessage(EX_CHAR);
switch (m.ch)
{
case 'a': // 画小圆
circle(rand() % 640, rand() % 480, 10);
break;
case 'b': // 画大圆
circle(rand() % 640, rand() % 480, 30);
break;
case 'c': // 退出
break;
}
} while (m.ch != 'c');
getmessage(EX_CHAR);
closegraph();
return 0;
}
补充 1:不显示控制台窗口
以上这样做,可以解决输入的问题,但是控制台的黑窗口仍然在。如果想彻底去掉控制台的黑窗口,需要创建 Win32 Application 类型的应用,而不是控制台类型的应用。具体可以看:https://codebus.cn/yangw/use-easyx-in-win32-application
重新创建项目后,代码也要将 main 对应的修改为 WinMain 格式,就可以彻底去掉控制台的黑窗口。
补充 2:实现更流畅的按键输入
在使用 getch() 输入字符时,如果长按某个按键,会遇到先接收一个字符,然后停顿一下,然后再接收一串字符。这是因为 getch() 获取的是字符,平时字符输入的时候就是这样响应的,所以会导致这样的效果。使用 getmessage(EX_CHAR) 仍然是获取字符消息,所以和 getch 效果一样。
如果需要更流畅的按键输入,可以获取按键消息。
按键消息与字符消息不同,对于字符消息,'A' 和 'a' 是不同的。对于按键消息,得到的是虚拟键码,'A' 和 'a' 对应的按键是一样的,没有区别。
同时,getmessage 是阻塞式的消息获取函数,如果没有新的消息,会阻断程序的执行。为了使控制上显得更流畅,可以使用非阻塞式的消息获取函数 peekmessage,该函数在获取到消息后返回 true,否则返回 false。
以下是一个例子,可以实现 a s d w 或方向键控制一个圆的移动(支持多个按键同时按下实现斜向移动),按 ESC 键退出程序。完整代码如下:
(可以根据需要,修改为 Win32 Application)
#include <graphics.h>
int main()
{
initgraph(640, 480);
BeginBatchDraw();
int x = 320, y = 240;
bool w = false, s = false, a = false, d = false; // 记录各按键的按下状态
bool exit = false;
ExMessage m;
while(!exit)
{
// 获取控制
while(peekmessage(&m, EX_KEY))
{
if (m.message == WM_KEYDOWN)
{
switch (m.vkcode)
{
case VK_UP:
case 'W': w = true; break;
case VK_DOWN:
case 'S': s = true; break;
case VK_LEFT:
case 'A': a = true; break;
case VK_RIGHT:
case 'D': d = true; break;
case VK_ESCAPE: exit = true; break;
}
}
if (m.message == WM_KEYUP)
{
switch (m.vkcode)
{
case VK_UP:
case 'W': w = false; break;
case VK_DOWN:
case 'S': s = false; break;
case VK_LEFT:
case 'A': a = false; break;
case VK_RIGHT:
case 'D': d = false; break;
}
}
}
// 计算数据
if (w) y--;
if (s) y++;
if (a) x--;
if (d) x++;
// 绘制
cleardevice();
circle(x, y, 20);
// 刷新屏幕并延时
FlushBatchDraw();
Sleep(10);
} while (m.vkcode != VK_ESCAPE);
EndBatchDraw();
closegraph();
return 0;
}
同时,也可以使用 Windows API 实现流畅的按键控制,请参考:https://codebus.cn/yangw/detect-combination-keys-and-advanced-key-handling