From a43999bfa5142128bce15d59a433fec2bfa596fa Mon Sep 17 00:00:00 2001 From: Clansty Date: Fri, 24 Jan 2025 00:22:22 +0800 Subject: [PATCH] [+] ADX HID input --- AquaMai.Config/AquaMai.Config.csproj | 2 +- AquaMai.Mods/AquaMai.Mods.csproj | 13 +++ AquaMai.Mods/FodyWeavers.xml | 7 ++ AquaMai.Mods/FodyWeavers.xsd | 111 +++++++++++++++++++++++ AquaMai.Mods/GameSystem/HidInput.cs | 131 +++++++++++++++++++++++++++ 5 files changed, 263 insertions(+), 1 deletion(-) create mode 100644 AquaMai.Mods/FodyWeavers.xml create mode 100644 AquaMai.Mods/FodyWeavers.xsd create mode 100644 AquaMai.Mods/GameSystem/HidInput.cs diff --git a/AquaMai.Config/AquaMai.Config.csproj b/AquaMai.Config/AquaMai.Config.csproj index d80f92bd..1402de4a 100644 --- a/AquaMai.Config/AquaMai.Config.csproj +++ b/AquaMai.Config/AquaMai.Config.csproj @@ -47,7 +47,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/AquaMai.Mods/AquaMai.Mods.csproj b/AquaMai.Mods/AquaMai.Mods.csproj index b04c32a1..3811177a 100644 --- a/AquaMai.Mods/AquaMai.Mods.csproj +++ b/AquaMai.Mods/AquaMai.Mods.csproj @@ -125,4 +125,17 @@ + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/AquaMai.Mods/FodyWeavers.xml b/AquaMai.Mods/FodyWeavers.xml new file mode 100644 index 00000000..edfc8416 --- /dev/null +++ b/AquaMai.Mods/FodyWeavers.xml @@ -0,0 +1,7 @@ + + + + hidlibrary|Numerics + $AquaMai.Mods$_ + + diff --git a/AquaMai.Mods/FodyWeavers.xsd b/AquaMai.Mods/FodyWeavers.xsd new file mode 100644 index 00000000..968f9b5e --- /dev/null +++ b/AquaMai.Mods/FodyWeavers.xsd @@ -0,0 +1,111 @@ + + + + + + + + + + + + A regular expression matching the assembly names to include in merging. + + + + + A regular expression matching the assembly names to exclude from merging. + + + + + A regular expression matching the resource names to include in merging. + + + + + A regular expression matching the resource names to exclude from merging. + + + + + A switch to control whether the imported types are hidden (made private) or keep their visibility unchanged. Default is 'true' + + + + + A string that is used as prefix for the namespace of the imported types. + + + + + A switch to control whether to import the full assemblies or only the referenced types. Default is 'false' + + + + + A switch to enable compacting of the target assembly by skipping properties, events and unused methods. Default is 'false' + + + + + + A regular expression matching the assembly names to include in merging. + + + + + A regular expression matching the assembly names to exclude from merging. + + + + + A regular expression matching the resource names to include in merging. + + + + + A regular expression matching the resource names to exclude from merging. + + + + + A switch to control whether the imported types are hidden (made private) or keep their visibility unchanged. Default is 'true' + + + + + A string that is used as prefix for the namespace of the imported types. + + + + + A switch to control whether to import the full assemblies or only the referenced types. Default is 'false' + + + + + A switch to enable compacting of the target assembly by skipping properties, events and unused methods. Default is 'false' + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/AquaMai.Mods/GameSystem/HidInput.cs b/AquaMai.Mods/GameSystem/HidInput.cs new file mode 100644 index 00000000..77368dac --- /dev/null +++ b/AquaMai.Mods/GameSystem/HidInput.cs @@ -0,0 +1,131 @@ +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading; +using AMDaemon; +using AquaMai.Config.Attributes; +using HarmonyLib; +using HidLibrary; +using MelonLoader; +using UnityEngine; + +namespace AquaMai.Mods.GameSystem; + +[ConfigSection( + en: "Input using ADX HID firmware (do not enable if you are not using ADX's HID firmware, be sure to delete the existing HID related DLL when enabled)", + zh: "使用 ADX HID 固件的自定义输入(如果你没有使用 ADX 的 HID 固件,请不要启用。启用时请务必删除现有 HID 相关 DLL)")] +public class HidInput +{ + private static HidDevice adxController1P = null; + private static HidDevice adxController2P = null; + private static byte[] inputBuf1P = new byte[32]; + private static byte[] inputBuf2P = new byte[32]; + + private static void HidInputThread() + { + MelonLogger.Msg("[HidInput] ======= HID Input Start ======="); + + while (true) + { + if (adxController1P != null) + { + var report1P = adxController1P.Read(); + if (report1P.Status == HidDeviceData.ReadStatus.Success) + inputBuf1P = report1P.Data; + } + + if (adxController2P != null) + { + var report2P = adxController2P.Read(); + if (report2P.Status == HidDeviceData.ReadStatus.Success) + inputBuf2P = report2P.Data; + } + +#if DEBUG + MelonLogger.Msg("[HidInput] 1P: " + string.Join(",", inputBuf1P)); +#endif + // Thread.Sleep(10); // Sleep for a short time to avoid CPU overload + } + } + + public static void OnBeforePatch() + { + adxController1P = HidDevices.Enumerate(0x2E3C, 0x5750).FirstOrDefault(); + adxController2P = HidDevices.Enumerate(0x2E4C, 0x5750).FirstOrDefault(); + + if (adxController1P == null) + { + MelonLogger.Msg("[HidInput] Open HID 1P Failed"); + } + else + { + MelonLogger.Msg("[HidInput] Open HID 1P OK"); + } + + if (adxController2P == null) + { + MelonLogger.Msg("[HidInput] Open HID 2P Failed"); + } + else + { + MelonLogger.Msg("[HidInput] Open HID 2P OK"); + } + + if (adxController1P != null || adxController2P != null) + { + Thread hidThread = new Thread(HidInputThread); + hidThread.Start(); + } + } + + private static bool GetPushedByButton(int playerNo, InputId inputId) + { + if (inputId.Value == "test") return inputBuf1P[13] == 1 || inputBuf2P[13] == 1; + if (inputId.Value == "service") return inputBuf1P[11] == 1 || inputBuf2P[13] == 1; + if (inputId.Value == "select" && playerNo == 0) return inputBuf1P[10] == 1 || inputBuf2P[10] == 1; + if (inputId.Value == "select" && playerNo == 1) return inputBuf1P[12] == 1 || inputBuf2P[12] == 1; + + var buf = playerNo == 0 ? inputBuf1P : inputBuf2P; + if (inputId.Value == "button_01") return buf[5] == 1; + if (inputId.Value == "button_02") return buf[4] == 1; + if (inputId.Value == "button_03") return buf[3] == 1; + if (inputId.Value == "button_04") return buf[2] == 1; + if (inputId.Value == "button_05") return buf[9] == 1; + if (inputId.Value == "button_06") return buf[8] == 1; + if (inputId.Value == "button_07") return buf[7] == 1; + if (inputId.Value == "button_08") return buf[6] == 1; + return false; + } + + [HarmonyPatch] + public static class Hook + { + public static IEnumerable TargetMethods() + { + var jvsSwitch = typeof(IO.Jvs).GetNestedType("JvsSwitch", BindingFlags.NonPublic | BindingFlags.Public); + return [jvsSwitch.GetMethod("Execute")]; + } + + public static bool Prefix(int ____playerNo, InputId ____inputId, ref bool ____isStateOnOld2, ref bool ____isStateOnOld, ref bool ____isStateOn, ref bool ____isTriggerOn, ref bool ____isTriggerOff, KeyCode ____subKey) + { + var flag = GetPushedByButton(____playerNo, ____inputId); + // 不影响键盘 + if (!flag) return true; + + var isStateOnOld2 = ____isStateOnOld; + var isStateOnOld = ____isStateOn; + + if (isStateOnOld2 && !isStateOnOld) + { + return true; + } + + ____isStateOn = true; + ____isTriggerOn = !isStateOnOld; + ____isTriggerOff = false; + ____isStateOnOld2 = isStateOnOld2; + ____isStateOnOld = isStateOnOld; + return false; + } + } +} \ No newline at end of file