diff --git a/Patches/AimToggleHoldPatches.cs b/Patches/AimToggleHoldPatches.cs new file mode 100644 index 0000000..2a1a14a --- /dev/null +++ b/Patches/AimToggleHoldPatches.cs @@ -0,0 +1,72 @@ +using Comfort.Common; +using EFT.InputSystem; +using HarmonyLib; +using SPT.Reflection.Patching; +using System.Collections.Generic; +using System.Reflection; + +namespace UIFixes +{ + public static class AimToggleHoldPatches + { + public static void Enable() + { + new AddStatesPatch().Enable(); + new UpdateInputPatch().Enable(); + + Settings.ToggleOrHoldAim.SettingChanged += (_, _) => + { + // Will "save" control settings, running GClass1911.UpdateInput, which will set (or unset) toggle/hold behavior + Singleton.Instance.Control.Controller.method_3(); + }; + } + + public class AddStatesPatch : ModulePatch + { + private static FieldInfo StateMachineArray; + + protected override MethodBase GetTargetMethod() + { + StateMachineArray = AccessTools.Field(typeof(GClass1911), "keyCombinationState_1"); + return AccessTools.Constructor(typeof(GClass1912), [typeof(EGameKey), typeof(ECommand), typeof(ECommand), typeof(int)]); + } + + [PatchPostfix] + public static void Postfix(GClass1912 __instance, EGameKey gameKey, ECommand disableCommand, GClass1911.KeyCombinationState[] ___keyCombinationState_1) + { + if (!Settings.ToggleOrHoldAim.Value || gameKey != EGameKey.Aim) + { + return; + } + + List states = new(___keyCombinationState_1) + { + new ToggleHoldIdleState(__instance), + new ToggleHoldClickOrHoldState(__instance), + new ToggleHoldHoldState(__instance, disableCommand) + }; + + StateMachineArray.SetValue(__instance, states.ToArray()); + } + } + + public class UpdateInputPatch : ModulePatch + { + protected override MethodBase GetTargetMethod() + { + return AccessTools.Method(typeof(GClass1911), nameof(GClass1911.UpdateInput)); + } + + [PatchPostfix] + public static void Postfix(GClass1911 __instance) + { + if (!Settings.ToggleOrHoldAim.Value || __instance.GameKey != EGameKey.Aim) + { + return; + } + + __instance.method_0((GClass1911.EKeyState)ToggleHoldState.Idle); + } + } + } +} diff --git a/Plugin.cs b/Plugin.cs index 902ed61..4380b8c 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -57,6 +57,7 @@ namespace UIFixes LoadMultipleMagazinesPatches.Enable(); new PutToolsBackPatch().Enable(); new RebindGrenadesPatch().Enable(); + AimToggleHoldPatches.Enable(); } public static bool InRaid() diff --git a/Settings.cs b/Settings.cs index cb9ef57..7efbb35 100644 --- a/Settings.cs +++ b/Settings.cs @@ -50,6 +50,7 @@ namespace UIFixes public static ConfigEntry RestoreAsyncScrollPositions { get; set; } // Advanced // Input + public static ConfigEntry ToggleOrHoldAim { get; set; } public static ConfigEntry UseHomeEnd { get; set; } public static ConfigEntry RebindPageUpDown { get; set; } public static ConfigEntry MouseScrollMulti { get; set; } @@ -176,14 +177,23 @@ namespace UIFixes new ConfigurationManagerAttributes { IsAdvanced = true }))); // Input + configEntries.Add(ToggleOrHoldAim = config.Bind( + InputSection, + "Use Toggle/Hold Aiming", + false, + new ConfigDescription( + "Tap the aim key to toggle aiming, or hold the aim key for continuous aiming", + null, + new ConfigurationManagerAttributes { }))); + configEntries.Add(UseHomeEnd = config.Bind( InputSection, "Enable Home/End Keys", true, new ConfigDescription( "Use the Home and End keys to scroll to the top and bottom of inventories", - null, - new ConfigurationManagerAttributes { }))); + null, + new ConfigurationManagerAttributes { }))); configEntries.Add(RebindPageUpDown = config.Bind( InputSection, diff --git a/ToggleHold.cs b/ToggleHold.cs new file mode 100644 index 0000000..0b98793 --- /dev/null +++ b/ToggleHold.cs @@ -0,0 +1,86 @@ +using EFT.InputSystem; + +namespace UIFixes +{ + public enum ToggleHoldState + { + Idle = 13, + ClickOrHold = 14, + Holding = 15 + } + + public class ToggleHoldIdleState(GClass1911 keyCombination) : GClass1911.KeyCombinationState(keyCombination) + { + public override ECommand GetCommand(float deltaTime) + { + if (!CanProcess()) + { + return ECommand.None; + } + + HandleKeys(false); + KeyCombination.method_0((GClass1911.EKeyState)ToggleHoldState.ClickOrHold); + return GetCommandInternal(); + } + + protected bool CanProcess() + { + return GetKeysStatus(out EKeyPress ekeyPress) && (ekeyPress == EKeyPress.Down); + } + } + + public class ToggleHoldClickOrHoldState(GClass1911 keyCombination) : GClass1911.KeyCombinationState(keyCombination) + { + public override void Enter() + { + timer = KeyCombination.DoubleClickTimeout; + } + + public override ECommand GetCommand(float deltaTime) + { + if (GetKeysStatus(out EKeyPress ekeyPress)) + { + if (ekeyPress == EKeyPress.Hold) + { + HandleKeys(false); + if (LongEnough(deltaTime)) + { + KeyCombination.method_0((GClass1911.EKeyState)ToggleHoldState.Holding); + } + + return ECommand.None; + } + } + + UnhandleKeys(null); + KeyCombination.method_0((GClass1911.EKeyState)ToggleHoldState.Idle); + return ECommand.None; + } + + private bool LongEnough(float deltaTime) + { + timer -= deltaTime; + return timer <= 0f; + } + + private float timer; + } + + public class ToggleHoldHoldState(GClass1911 keyCombination, ECommand disableCommand) : GClass1911.KeyCombinationState(keyCombination) + { + private readonly ECommand disableCommand = disableCommand; + + public override ECommand GetCommand(float deltaTime) + { + if (GetKeysStatus(out EKeyPress ekeyPress) && ekeyPress == EKeyPress.Hold) + { + HandleKeys(false); + return ECommand.None; + } + + UnhandleKeys(null); + KeyCombination.method_0((GClass1911.EKeyState)ToggleHoldState.Idle); + return disableCommand; + } + } +}