feat: Controller hotbars with cross layout, separate storage, and sync with game

- Add controller hotbars: 8 cross bars (L2/R2 style), separate from normal hotbars 1-8
- Controller bar slot data stored in config (not game StandardHotbars) so layouts can differ per mode
- Drag-and-drop on controller bars: from game, shift+drag rearrange, release outside to clear
- Independent controller bar keybinds with modifier+trigger combinations (e.g. L2+South)
- Optional 'Sync bar mode with game client': follow Character Config Mouse/Gamepad toggle (PadMode)
- Clone/copy actions: normal hotbars ↔ controller bars
- Restore controller bar layout button; deploy to devPlugins on Release build

Made-with: Cursor
This commit is contained in:
Jorg
2026-02-26 22:18:40 -06:00
parent 369a770162
commit f3e10f27d2
13 changed files with 1706 additions and 21 deletions
+7
View File
@@ -475,6 +475,9 @@ namespace HSUI.Helpers
// When leaving PvP, force load PvE hotbars so HSUI bars don't keep showing PvP actions.
ActionBarsManager.TryRestorePvEHotbarsAfterLeavePvP();
// Controller bar custom keybinds (when controller hotbars enabled)
ControllerBarKeybindExecutor.Process(framework);
// Keep WndProc hooked when: proxy mode (for mouseover) OR we need to block game drag
// release (so dropping on HSUI action bar doesn't execute the ability).
bool needHook = IsProxyEnabled || ShouldBlockGameDragRelease();
@@ -567,6 +570,7 @@ namespace HSUI.Helpers
_wndHandle = hWnd;
_wndProcDelegate = WndProcDetour;
_wndProcHandle = GCHandle.Alloc(_wndProcDelegate, GCHandleType.Normal); // Prevent GC of delegate while hooked
_wndProcPtr = Marshal.GetFunctionPointerForDelegate(_wndProcDelegate);
_imguiWndProcPtr = SetWindowLongPtr(hWnd, GWL_WNDPROC, _wndProcPtr);
@@ -593,6 +597,8 @@ namespace HSUI.Helpers
}
finally
{
if (_wndProcHandle.IsAllocated)
_wndProcHandle.Free();
_wndHandle = IntPtr.Zero;
_imguiWndProcPtr = IntPtr.Zero;
_wndProcPtr = IntPtr.Zero;
@@ -614,6 +620,7 @@ namespace HSUI.Helpers
private IntPtr _wndHandle = IntPtr.Zero;
private WndProcDelegate _wndProcDelegate = null!;
private GCHandle _wndProcHandle; // Keeps delegate alive while WndProc is hooked; freed in RestoreWndProc
private IntPtr _wndProcPtr = IntPtr.Zero;
private IntPtr _imguiWndProcPtr = IntPtr.Zero;