这个向导实际上做了什么?它会创建死区并将其存储在注册表中吗?它会将原始数据映射到某个地方的上限和下限吗?
这仅仅是软件校准吗?还是它会将数据发送回设备?
我想知道是否可以识别该向导的输出,以便可以从我的应用程序中进行校准。
答案1
通过我最近对 Windows 内置操纵杆控制器校准工具的探索,我可以确认 PS4 操纵杆上的以下行为(其他控制器的结果应该类似):
经过校准向导后,以下注册表将写入校准数据,
HKEY_CURRENT_USER\System\CurrentControlSet\Control\MediaProperties\PrivateProperties\DirectInput\<DEVICE_ID>\Calibration\0\Type\Axes\<NUM>
其中<NUM>
是轴编号。对于 PS4 操纵杆,Windows 读取六个轴,因此创建六个注册表项值。轴的编号如下:
- 0 (x) --> 左模拟摇杆水平运动。
- 1 (y)-->左模拟摇杆垂直运动。
- 2 (z)-->右模拟水平运动。
- 3(Rx)--> L2 触发器。
- 4(Ry)-->R2 触发器。
- 5(Rz)-->右模拟垂直运动。
注册表项的格式
Calibration
映射到 12 字节二进制值(编码为<MIN> <MID> <MAX>
)。例如,我的 Axis 0 (x) 的值为:<00 00 00 00> <80 00 00 00> <ff 00 00 00>,转换为- 最小轴 0 值 = <00 00 00 00> = 0(十进制)
- 中轴 0 值 = <80 00 00 00> = 128(十进制)
- 最大轴 0 值 <ff 00 00 00> = 255(十进制)
Windows 所做的校准是将物理值转换为校准范围(上面的最小值、中间值、最大值)。例如,假设我有缺陷的左模拟摇杆的水平移动(x 轴)读数为 10-100,而其范围应为 0-255。然后,我可以分别将最小值/最大值设置为 10 和 100,以校准有缺陷的模拟摇杆。
似乎没有针对死区的特定设置,因此我认为这是为上述应用程序留下的实现细节(例如,对于游戏,定义为游戏逻辑代码的一部分)。
由于校准设置存储在注册表中,因此校准在不同的机器之间不会持久。
对于您的特定情况,您可能需要考虑使用某些 Windows API 来读取值(例如 XInput、UWP API)。作为奖励,以下是使用 Windows XInput API 读取控制器输入的一些错误。
#pragma comment(lib,"XInput.lib")
#pragma comment(lib,"Xinput9_1_0.lib")
#include <iostream>
#include <roapi.h>
#include <Xinput.h>
XINPUT_STATE fetchAConnectedJoystick()
{
DWORD dwResult;
XINPUT_STATE state;
for (DWORD i=0; i < XUSER_MAX_COUNT; i++)
{
ZeroMemory(&state, sizeof(XINPUT_STATE));
// Simply get the state of the controller from XInput.
dwResult = XInputGetState(i, &state);
// Controller is connected
if(dwResult == ERROR_SUCCESS)
{
return state;
}
}
std::exit;
}
void printLeftAnalogStickReadings(XINPUT_STATE state)
{
float LX = state.Gamepad.sThumbLX;
float LY = state.Gamepad.sThumbLY;
std::cout << "(X=" << LX << ", Y=" << LY << ")\n";
}
int computeAdjustedMagnitude(XINPUT_STATE state)
{
int INPUT_DEADZONE = 42;
float LX = state.Gamepad.sThumbLX;
float LY = state.Gamepad.sThumbLY;
float magnitude = sqrt(LX*LX + LY*LY); // Determine how far the controller is pushed
// Determine the direction the controller is pushed
float normalizedLX = LX / magnitude;
float normalizedLY = LY / magnitude;
if (magnitude > INPUT_DEADZONE) // Check if the controller is outside a circular dead zone
{
if (magnitude > 32767) magnitude = 32767; // Clip the magnitude at its expected maximum value
magnitude -= INPUT_DEADZONE; // Adjust magnitude relative to the end of the dead zone
}
else // If the controller is in the deadzone zero out the magnitude
{
magnitude = 0.0;
}
return magnitude;
}
int main()
{
XINPUT_STATE state;
int sleepDuration = 100; // Milliseconds
int adjustedMag = 0;
while (true) {
state = fetchAConnectedJoystick();
printLeftAnalogStickReadings(state);
// adjustedMag = computeAdjustedMagnitude(state);
// std::this_thread::sleep_for(std::chrono::milliseconds(sleepDuration));
}
}
答案2
我相信校准信息存储在注册表中:
HKEY_CURRENT_USER\System\CurrentControlSet\Control\MediaProperties\PrivateProperties\DirectInput\<DEVICE>\Calibration
我不知道这些条目的格式是什么,但它不是人类可读的。