我试图从我的XBox 360控制器读取而不进行轮询。 (确切地说,我实际上使用的是Logitech F310,但我的Windows 10 PC将其视为XBox 360控制器。)我写了一些相当讨厌的HID代码,它使用重叠I / O来阻塞两个线程事件,表示存在准备从HID设备读取的报告,另一个指示UI线程已请求HID线程退出。这工作正常,但HID驱动程序的行为与XInput有所不同。特别是,它将两个触发器合并为一个值,只传递它们的差异(当玩家的手指离开控制时游戏期望HID值为0x80的好奇声称)。 XInput将它们视为两个不同的值,这是一个很大的改进。此外,XInput将帽子开关报告为四位,这意味着您实际上可以从中获得十个状态:未压缩,N,NE,E,SE,S,SW,W,NW和全向下(最后可能是难以成功使用,但至少如果你需要它就在那里;我一直用它来退出我的轮询循环。)
对我来说,XInput的缺点是,在控制器更改其中一个值或按钮之前,似乎无法阻止读取请求。作为HID设备,ReadFile调用将阻塞(更确切地说,WaitForMultipleEvents阻塞,直到有可用数据)。 XInput似乎预计会进行投票。对于一个自然被编写以随着它更新游戏状态(例如,对于每个显示的新视频帧可能一次)轮询控制器的游戏,这是有意义的。但是如果你想将控制器用于其他目的(我正在处理戏剧应用程序),你可能想要一个像HID API这样的纯异步系统。但是,同样,HID API结合了两个值触发器。
现在,当您使用XInput读取设备时,不仅可以获得所有控件的状态,还可以获得数据包编号。 MSDN表示数据包编号仅在控件状态发生变化时才会更改。这样,如果连续的数据包编号相同,则您不必在第一个之后进行任何处理,因为您知道控制器状态没有改变。但是你仍然在调查哪些对我来说有些粗俗。
然而,令我感到兴趣的是,当我在我的民意调查(100毫秒)之间放一个大的延迟时,我可以看到当值控制(触发器或操纵杆)被移动时,数据包数量会增加一个以上。我认为,这表明设备在不等待轮询的情况下发送数据包,并且每次轮询时我只获取最新的数据包。如果是这种情况,似乎我应该能够阻止直到发送数据包,并且仅在发生这种情况时做出反应,而不是必须进行轮询。但我找不到任何迹象表明这是一个选择。因为我可以使用HID API阻止,所以我不想在没有尝试的情况下放弃(包括在这里询问建议)。
没有为控制器编写我自己的驱动程序(我不确定是没有专有文档的选项),有没有人知道如何使用重叠I / O(或任何其他阻塞方法)来读取XBox 360控制器的方式是XInput,触发器是单独的值,帽子是四个按钮吗?
下面是我编写的一些代码,它读取控制器并显示数据包数在读取之间可以跳过多个:
#include <Windows.h>
#include <Xinput.h>
#include <stdio.h>
#define MAX_CONTROLLERS 4
int main()
{
DWORD userIndex;
XINPUT_STATE xs;
XINPUT_VIBRATION v;
XInputEnable(TRUE);
// Which one are we?
for (userIndex = 0; userIndex < XUSER_MAX_COUNT; ++userIndex)
if (XInputGetState(userIndex, &xs) == ERROR_SUCCESS)
break;
if (userIndex == XUSER_MAX_COUNT)
{
printf("Couldn't find an Xbox 360 controller.\n");
getchar();
return -1;
}
printf("Using controller #%1d.\n", userIndex);
while (TRUE)
{
DWORD res = XInputGetState(userIndex, &xs);
printf("%5d %6d: %3d %3d %3d %3d %3d %3d 0x%04X\n",
res,
xs.dwPacketNumber,
xs.Gamepad.bLeftTrigger & 0xFF,
xs.Gamepad.bRightTrigger & 0xFF,
xs.Gamepad.sThumbLX & 0xFF,
xs.Gamepad.sThumbLY & 0xFF,
xs.Gamepad.sThumbRX & 0xFF,
xs.Gamepad.sThumbRY & 0xFF,
xs.Gamepad.wButtons);
if (xs.Gamepad.wButtons == 0x000F) // mash down the hat
break;
Sleep(100);
}
getchar();
return 0;
}
请注意,DirectInput没有多大帮助,因为它还将触发器组合成一个值。
谢谢!
答案 0 :(得分:1)
不确定这有什么好处,但是你能编写一个定期轮询的线程,然后在状态发生变化时设置信号量(或其他信号)。然后你的主线程可以阻止等待来自轮询线程的信号。但是这个系统可能没有任何优势,因为在某些控制器上,无论你是否移动,拇指杆的值都会略有变化。 (噪音)你当然可以忽略小的变化,只在发生大的变化时发出信号。