From 610ef3881de5f28c55bea482986e1c11722940ea Mon Sep 17 00:00:00 2001 From: Tyfon <29051038+tyfon7@users.noreply.github.com> Date: Fri, 19 Apr 2024 04:22:45 -0700 Subject: [PATCH] Proper key handling of Home/End, PageUp/PageDown --- Patches/ScrollPatches.cs | 230 +++++++++++++++++++++++++++++++++++++++ Plugin.cs | 1 + Settings.cs | 7 +- UIFixes.csproj | 9 ++ 4 files changed, 245 insertions(+), 2 deletions(-) create mode 100644 Patches/ScrollPatches.cs diff --git a/Patches/ScrollPatches.cs b/Patches/ScrollPatches.cs new file mode 100644 index 0000000..f88bc79 --- /dev/null +++ b/Patches/ScrollPatches.cs @@ -0,0 +1,230 @@ +using Aki.Reflection.Patching; +using EFT.UI; +using EFT.UI.Chat; +using EFT.UI.Ragfair; +using EFT.UI.Utilities.LightScroller; +using HarmonyLib; +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace UIFixes +{ + public class ScrollPatches + { + public static void Enable() + { + new SimpleStashPanelPatch().Enable(); + new TraderDealScreenPatch().Enable(); + new OfferViewListPatch().Enable(); + new MessagesContainerPatch().Enable(); + } + + protected static void HandleInput(ScrollRect scrollRect) + { + if (scrollRect != null) + { + Rect contentRect = scrollRect.content.rect; + Rect viewRect = scrollRect.RectTransform().rect; + float pageSize = viewRect.height / contentRect.height; + + if (Settings.UseHomeEnd.Value) + { + if (Input.GetKeyDown(KeyCode.Home)) + { + scrollRect.verticalNormalizedPosition = 1f; + } + if (Input.GetKeyDown(KeyCode.End)) + { + scrollRect.verticalNormalizedPosition = 0f; + } + } + + if (Settings.RebindPageUpDown.Value) + { + if (Input.GetKeyDown(KeyCode.PageUp)) + { + scrollRect.verticalNormalizedPosition = Math.Min(1f, scrollRect.verticalNormalizedPosition + pageSize); + } + if (Input.GetKeyDown(KeyCode.PageDown)) + { + scrollRect.verticalNormalizedPosition = Math.Max(0f, scrollRect.verticalNormalizedPosition - pageSize); + } + } + } + } + + protected static IEnumerable RemovePageUpDownHandling(IEnumerable instructions) + { + foreach (var instruction in instructions) + { + if (instruction.LoadsConstant((int)KeyCode.PageUp)) + { + yield return new CodeInstruction(instruction) + { + operand = 0 + }; + } + else if (instruction.LoadsConstant((int)KeyCode.PageDown)) + { + yield return new CodeInstruction(instruction) + { + operand = 0 + }; + } + else + { + yield return instruction; + } + } + } + + public class SimpleStashPanelPatch : ModulePatch + { + protected override MethodBase GetTargetMethod() + { + Type type = typeof(SimpleStashPanel); + return type.GetMethod("Update", BindingFlags.Public | BindingFlags.Instance); + } + + [PatchPrefix] + private static void Prefix(SimpleStashPanel __instance) + { + ScrollRect stashScroll = Traverse.Create(__instance).Field("_stashScroll").GetValue(); + HandleInput(stashScroll); + } + + [PatchTranspiler] + private static IEnumerable Transpiler(IEnumerable instructions) + { + if (Settings.RebindPageUpDown.Value) + { + return RemovePageUpDownHandling(instructions); + } + + return instructions; + } + } + + public class TraderDealScreenPatch : ModulePatch + { + protected override MethodBase GetTargetMethod() + { + Type type = typeof(TraderDealScreen); + return type.GetMethod("Update", BindingFlags.Public | BindingFlags.Instance); + } + + [PatchPrefix] + private static void Prefix(TraderDealScreen __instance) + { + ScrollRect traderScroll = Traverse.Create(__instance).Field("_traderScroll").GetValue(); + HandleInput(traderScroll); + } + + [PatchTranspiler] + private static IEnumerable Transpiler(IEnumerable instructions) + { + if (Settings.RebindPageUpDown.Value) + { + return RemovePageUpDownHandling(instructions); + } + + return instructions; + } + } + + public class OfferViewListPatch : ModulePatch + { + protected override MethodBase GetTargetMethod() + { + Type type = typeof(OfferViewList); + return type.GetMethod("Update", BindingFlags.Public | BindingFlags.Instance); + } + + [PatchPrefix] + private static void Prefix(OfferViewList __instance) + { + LightScroller scroller = Traverse.Create(__instance).Field("_scroller").GetValue(); + + // Different kind of scroller - I don't see a way to get the rects. + // New approach: faking scroll events + if (scroller != null) + { + if (Settings.UseHomeEnd.Value) + { + if (Input.GetKeyDown(KeyCode.Home)) + { + scroller.SetScrollPosition(0f); + } + if (Input.GetKeyDown(KeyCode.End)) + { + scroller.SetScrollPosition(1f); + } + } + + if (Settings.RebindPageUpDown.Value) + { + if (Input.GetKeyDown(KeyCode.PageUp)) + { + var eventData = new PointerEventData(EventSystem.current) + { + scrollDelta = new Vector2(0f, 25f) + }; + scroller.OnScroll(eventData); + } + if (Input.GetKeyDown(KeyCode.PageDown)) + { + var eventData = new PointerEventData(EventSystem.current) + { + scrollDelta = new Vector2(0f, -25f) + }; + scroller.OnScroll(eventData); + } + } + } + } + + [PatchTranspiler] + private static IEnumerable Transpiler(IEnumerable instructions) + { + if (Settings.RebindPageUpDown.Value) + { + return RemovePageUpDownHandling(instructions); + } + + return instructions; + } + } + + public class MessagesContainerPatch : ModulePatch + { + protected override MethodBase GetTargetMethod() + { + Type type = typeof(MessagesContainer); + return type.GetMethod("Update", BindingFlags.Public | BindingFlags.Instance); + } + + [PatchPrefix] + private static void Prefix(MessagesContainer __instance) + { + ScrollRect scroller = Traverse.Create(__instance).Field("_scroller").GetValue(); + HandleInput(scroller); + } + + [PatchTranspiler] + private static IEnumerable Transpiler(IEnumerable instructions) + { + if (Settings.RebindPageUpDown.Value) + { + return RemovePageUpDownHandling(instructions); + } + + return instructions; + } + } + } +} diff --git a/Plugin.cs b/Plugin.cs index b76160c..c745410 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -14,6 +14,7 @@ namespace UIFixes new EditBuildScreenPatch.ConfirmDiscardPatch().Enable(); new TransferConfirmPatch().Enable(); new MailReceiveAllPatch().Enable(); + ScrollPatches.Enable(); } } } diff --git a/Settings.cs b/Settings.cs index ba37b14..85d5a23 100644 --- a/Settings.cs +++ b/Settings.cs @@ -7,13 +7,16 @@ namespace UIFixes public static ConfigEntry WeaponPresetConfirmOnNavigate { get; set; } public static ConfigEntry WeaponPresetConfirmOnClose { get; set; } public static ConfigEntry TransferConfirmOnClose { get; set; } + public static ConfigEntry UseHomeEnd { get; set; } + public static ConfigEntry RebindPageUpDown { get; set; } public static void Init(ConfigFile config) { WeaponPresetConfirmOnNavigate = config.Bind("Weapon Presets", "Confirm on screen change", false, "Whether to confirm unsaved changes when you change screens without closing the preset"); WeaponPresetConfirmOnClose = config.Bind("Weapon Presets", "Confirm on close", true, "Whether to still confirm unsaved changes when you actually close the preset"); - TransferConfirmOnClose = config.Bind("Transfer items", "Confirm untransfered items", false, "Whether to pointlessly confirm that you're leaving the item transfer with literally no consequences"); - + TransferConfirmOnClose = config.Bind("Transfer Items", "Confirm untransfered items", false, "Whether to pointlessly confirm that you're leaving the item transfer with literally no consequences"); + UseHomeEnd = config.Bind("Keybinds", "Add support for Home and End", true, "Home and End will scroll to the top and bottom of lists"); + RebindPageUpDown = config.Bind("Keybinds", "Use normal PageUp and PageDown (requires restart)", true, "Changes PageUp and PageDown to simply page up and down, not scroll all the way to top and bottom"); } } } diff --git a/UIFixes.csproj b/UIFixes.csproj index a9029ce..81b8b48 100644 --- a/UIFixes.csproj +++ b/UIFixes.csproj @@ -16,12 +16,21 @@ ..\..\..\..\SPT\3.8.0\EscapeFromTarkov_Data\Managed\Assembly-CSharp.dll + + ..\..\..\..\SPT\3.8.0\EscapeFromTarkov_Data\Managed\Sirenix.Serialization.dll + ..\..\..\..\SPT\3.8.0\EscapeFromTarkov_Data\Managed\UnityEngine.dll ..\..\..\..\SPT\3.8.0\EscapeFromTarkov_Data\Managed\UnityEngine.CoreModule.dll + + ..\..\..\..\SPT\3.8.0\EscapeFromTarkov_Data\Managed\UnityEngine.InputLegacyModule.dll + + + ..\..\..\..\SPT\3.8.0\EscapeFromTarkov_Data\Managed\UnityEngine.UI.dll +