Калибровка игрового контроллера из кода

Я хочу воспроизвести процедуру калибровки из приложения C# WPF. В Интернете есть похожие приложения, например DIView:

Калибровка игрового контроллера из кода

и DXTweak:

Калибровка игрового контроллера из кода

Однако процедура утомительна, так как вас просят выбрать минимальное, среднее и максимальное значение для каждой оси.

У меня есть собственная плата джойстика, которая распознается Windows как игровой контроллер. Я могу читать его значения с помощью DirectInput или любых других библиотек. При использовании одного из этих двух приложений для калибровки джойстика я действительно могу получить результаты, когда опрашиваю значения с помощью DirectInput. Определенно есть способ сделать это с помощью кода.

Моей целью было бы разработать приложение для одновременной калибровки нескольких осей. Я считал, что DirectInput может справиться с такого рода задачами или что реестры Windows где-то их хранят. К сожалению, после нескольких часов поиска в Google результатов не хватило (пожалуйста, докажите, что я ошибаюсь!).

Обновлено:

В API DirectInput есть функции DeviceProperties.GetCalibrationPoints и DeviceProperties.SetCalibrationPoints, но я понятия не имею, как их использовать.

Вот документация.

Я пробовал получить точки калибровки следующим образом: MyDevice.GetCalibrationPoints(ParameterHow.ByUsage, MyDevice.DeviceInformation.Usage);, но я думаю, что делаю это неправильно, потому что получаю исключение -2147024894 (ERROR_FILE_NOT_FOUND).

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
1 093
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я нашел частичное решение, и мне оно не очень понравилось.

Следующий код CalibrationPoint[] points = mDevice.Properties.GetCalibrationPoints(ParameterHow.ByOffset, 0); предоставит вам массив из 2 объектов CalibrationPoints, соответствующих первой оси вашего контроллера. Вот как это будет выглядеть, если отобразить обе эти точки:

(0) ScalingValue: 0 RawData: 0 (1) ScalingValue: 10000 RawData: 4095

Что меня беспокоит, так это параметры. Я понял, что параметр ByOffset даст вам значения в их массиве значений где-то со смещением (как в обычном массиве), но мне пришлось выполнять итерацию с приращением 4 вместо 1, чтобы получить каждую ось. Я не мог найти способ заменить это, например, с помощью sizeof(CalibrationPoint), но я знаю, когда прекратить итерацию с количеством осей, доступных на моем устройстве.

Наконец, вы можете использовать эти две точки, изменив значения RawData, и передать их в качестве параметров функции SetCallibrationPoints для калибровки вашего контроллера.

Обновлено:

Я ошибся насчет последней части, вызов функции SetCalibrationPoint не подействовал ...

Ответ принят как подходящий

Хорошо, вот что я нашел с помощью реестров. Это немного долго, но у меня это работает.

Используя regedit, вы можете найти список устройств DirectInput, используя этот путь: Computer\HKEY_CURRENT_USER\System\CurrentControlSet\Control\MediaProperties\PrivateProperties\DirectInput

DirectInput registry

Выбрав желаемое устройство, вы в конечном итоге получите следующий путь: Computer\HKEY_CURRENT_USER\System\CurrentControlSet\Control\MediaProperties\PrivateProperties\DirectInput\YOUR_DEVICE_HERE\Calibration\0\Type\Axes. Если вы ничего не видите в этом реестре, это означает, что ваши оси еще не откалиброваны.

Используя C#, вы можете прочитать значения калибровки каждой оси в реестре, используя следующую функцию и преобразовав ее в массив байтов:

Byte[] Axis = Registry.GetValue(registry + '0', "Calibration", "EMPTY") as Byte[];

Вы можете изменить '0' для каждой оси.

Обязательно обрабатывайте исключения, если ваш реестр не существует, что означает, что ваш путь недействителен или что желаемая ось никогда ранее не калибровалась (и, следовательно, использует значения по умолчанию).

Я также заметил кое-что другое при использовании полученного массива, значения хранятся странным образом:

  • Массив имеет длину 12, значение мин калибровки сохраняется в первых 4 байтах, затем 4 средних байта для значения середина калибровки и 4 последних байта для Максимум.

  • Чтобы прочитать фактические значения для каждой части, вам нужно умножить второй байт для каждой части на 256 и добавить его к первому байту: int min = 256 * Axis[1] + Axis[0];

Наконец, если вы хотите записать свои собственные значения калибровки, вы можете просто использовать следующую функцию Registry.SetValue(regPath + '0', "Calibration", ByteArray);

Не забудьте изменить '0' для каждой оси и использовать тот же формат в массиве:

ByteArray[0] = (byte)(min % 256);
ByteArray[1] = (byte)(min / 256);
ByteArray[4] = (byte)(middle % 256);
ByteArray[5] = (byte)(middle / 256);
ByteArray[8] = (byte)(max % 256);
ByteArray[9] = (byte)(max / 256);

Другие вопросы по теме