這個嚮導實際上是做什麼的?它是否會創建死區並將其儲存在註冊表中?它是否將原始資料對應到某處的上限和下限?
這僅僅是軟體校準還是將資料傳回裝置?
我想知道是否可以識別該嚮導的輸出,以便可以在我的應用程式中進行校準。
答案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>
)。例如,我的軸 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)。作為獎勵,這裡是我的一些 bug,它使用 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
我不知道條目的格式是什麼,但它不是人類可讀的。