このウィザードは実際には何を行いますか? デッドゾーンを作成してレジストリに保存しますか? 生のデータを上限と下限のどこかにマッピングしますか?
これはソフトウェアによるキャリブレーションのみですか、それともデータをデバイスに送り返しますか?
このウィザードの出力を識別して、アプリケーション内からキャリブレーションを利用できるようにできるかどうか知りたいです。
答え1
Windows に組み込まれているジョイスティック コントローラーのキャリブレーション ツールを最近調べたところ、PS4 ジョイスティックで次の動作を確認できました (他のコントローラーでも結果は同様になるはずです)。
キャリブレーション ウィザードを実行すると、次のレジストリにキャリブレーション済みデータが書き込まれます。
HKEY_CURRENT_USER\System\CurrentControlSet\Control\MediaProperties\PrivateProperties\DirectInput\<DEVICE_ID>\Calibration\0\Type\Axes\<NUM>
ここで、 は<NUM>
軸番号です。PS4 ジョイスティックの場合、Windows は 6 つの軸を読み取るため、6 つのレジストリ キー値が作成されます。軸の番号は次のとおりです。
- 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 (10 進数)
- 中央軸 0 の値 = <80 00 00 00> = 128 (10 進数)
- 軸 0 の最大値 <ff 00 00 00> = 255 (10 進数)
Windows が行うキャリブレーションは、物理値をキャリブレーションされた範囲 (上から最小値、中間値、最大値) に変換することです。たとえば、故障した左アナログ スティックの水平移動 (X 軸) が 0 ~ 255 の範囲であるべきところ、10 ~ 100 と表示されるとします。この場合、故障したアナログ スティックをキャリブレーションするために、最小値と最大値をそれぞれ 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
エントリの形式がどのようなものかはわかりませんが、人間が読める形式ではありません。