如何在Windows上使用c++访问底层硬件I/O函数
How can I access a low-level hardware I/O functions in C++ on Windows?
我正在用c++编写一个游戏,我需要检测用户何时按下一个键。通常,我会使用std::cin
,但我有一个图形窗口,使用graphics.h
,一个头文件,最初是由古老的Borland Turbo c++编译器提供的,但等效的在线可用。因此,我将使用函数inportb();
,函数定义如下:
inline unsigned char inportb(unsigned int port) {
unsigned char ret;
asm volatile ("inb %%dx,%%al":"=a"(ret):"d"(port));
return ret;
}
来源:inportb。
但是在Windows中,像这样的直接低级硬件I/O是受保护的,如果尝试这样做,程序将被杀死。因此,我需要通过高级函数或API访问该函数。
我的问题是:我该怎么做?
如果你试图在游戏循环中检测特定键的状态,GetAsyncKeyState将在那一刻确定特定状态。
if (GetAsyncKeyState(VK_LEFT) & 0x8000) != 0u)
{
// ...
}
该函数接受一个虚拟键代码(在本例中为左箭头键),获取状态,并在按位and操作后确定键是否按下,然后离开。
这些虚拟键代码可以在WinUser.h中找到。GetAsyncKeyState与GetKeyState的不同之处在于,GetKeyState不反映与硬件相关的中断级状态(这就是我在上面使用GetAsyncKeyState的原因)。如果您需要给定实例中的所有键状态(这种情况很少见),请考虑GetKeybardState。
然而,如果你正在等待一个键事件(WM_KEYDOWN, WM_CHAR, WM_KEYUP)发生,你必须在窗口过程中提供一个case来处理该事件。
LRESULT WindowProc(UINT const message, WPARAM const wparam, LPARAM const lparam)
{
switch(message)
{
// [ cases like WM_CREATE / WM_PAINT / WM_CLOSE / WM_DESTROY ]
case WM_KEYDOWN:
// handle event here
break;
case WM_CHAR:
// handle event here
break;
case WM_KEYUP:
// handle event here
break;
}
}
在Windows中有4种不同的方法来检测输入
- GetInputState()(及其周围的API)(假设您不需要支持Windows XP或以下版本)
- 您可以使用GetKeyState()(及其周围的API)进行轮询,但是您必须为想要检查的每个键执行此操作。您可以使用GetInputState()来检查是否有值得检查的东西,如果有太多的键要轮询。
- GetRawInputData()(及其周边API)。这将在XP中工作,但它是一个更丑陋的界面。而且,它只会得到连接到机器上的实际硬件的输入。因此,如果您远程会话到一台windows机器,它可能无法工作。您还需要弄清楚哪些原始设备连接到系统,弄清楚它们何时连接,何时分离。这个(RawInput) API支持所有这些,所以你可能会在编写游戏时使用它。
- 钩子函数,它允许你注册回调,当输入事件发生时调用。钩子是通过SetWindowsHookEx()(和周围的API)注册的。这是检测按键最有效,但最不可靠的方法。一些程序可以为相同的事件设置钩子,API希望每个回调都能足够快地返回,以便其他注册者也能及时得到通知。如果你没有足够快地返回,即使只有一次,你也不会被告知,但是你的钩子函数将不再被调用…即使你注销回调并重新注册它们也不会。让这些工作,并在没有用户干预的情况下继续工作,是优秀键盘记录程序的真正艺术所在。
几十年前我在Turbo c++上玩得很开心:-)但如果我是你,我会尝试使用除了C编译器之外的游戏引擎或库,比如这个SDL或Ogre(见https://en.wikipedia.org/wiki/List_of_game_engines有一个很长的列表)。
它们提供了一个带有键盘事件的事件循环。
或者至少你可能想使用Windows或跨平台框架,如微软提供的MSVC(它在某些用途上是免费的)或Qt(它甚至更免费,现在附带了一个方便的IDE)。
让你的游戏充满乐趣!
- "error: no matching function for call to"构造函数错误
- 什么时候调用组成单元对象的析构函数
- 继承函数的重载解析
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- C++模板来检查友元函数的存在
- 递归函数计算序列中的平方和(并输出过程)
- 对RValue对象调用的LValue ref限定成员函数
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 为什么使用 "this" 指针调用派生成员函数?
- 将对象数组的引用传递给函数
- 函数调用中参数的顺序重要吗
- 函数向量_指针有不同的原型,我可以构建一个吗
- 使用不带参数的函数访问结构元素
- 代码在main()中运行,但在函数中出现错误
- 内置函数可查看CPP中的成员变量
- 初级C++硬件.函数似乎不起作用
- 与g++-7.0中的constexpr函数不同的行为/访问硬件
- 如何在Windows上使用c++访问底层硬件I/O函数