5f993f98b8
Increase the hotkey and recoil loop sleep intervals to reduce CPU churn and smooth input handling. The hotkey loop now waits 15ms instead of 8ms, and the recoil loop waits 10ms instead of 2ms, which helps reduce jitter while keeping responsiveness stable. This also updates the packaged release artifact by replacing the older archive with Lithium-0.01.7z.
196 lines
6.2 KiB
C#
196 lines
6.2 KiB
C#
using Lua;
|
|
using System;
|
|
using System.Threading;
|
|
|
|
namespace Lithium
|
|
{
|
|
internal static class HotkeyHandler
|
|
{
|
|
// AA0041
|
|
private const int CAPSLOCK = 0x14;
|
|
|
|
// AA0042
|
|
private static bool _nextSetHeld, _prevSetHeld, _refreshHeld, _switchSideHeld, _capsHeld;
|
|
// AA0043
|
|
private static MainWindow _mainWindow;
|
|
|
|
// AA0044 - Added: Cancellation token for graceful shutdown
|
|
private static CancellationTokenSource _cancellationSource;
|
|
|
|
// AA0045 - Updated: Accept cancellation token
|
|
public static void Start(MainWindow window, CancellationToken cancellationToken = default)
|
|
{
|
|
_mainWindow = window;
|
|
_cancellationSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
|
|
|
try
|
|
{
|
|
while (!_cancellationSource.Token.IsCancellationRequested)
|
|
{
|
|
try
|
|
{
|
|
HandleToggleCapsLock();
|
|
HandleNextSet();
|
|
HandlePrevSet();
|
|
HandleRefresh();
|
|
HandleSwitchSide();
|
|
HandleQuickSwaps();
|
|
Thread.Sleep(15);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// Log error but continue running
|
|
System.Diagnostics.Debug.WriteLine($"HotkeyHandler error: {ex.Message}");
|
|
}
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
_cancellationSource?.Dispose();
|
|
}
|
|
}
|
|
|
|
// AA0046 - Static method to stop the handler gracefully
|
|
public static void Stop()
|
|
{
|
|
_cancellationSource?.Cancel();
|
|
}
|
|
|
|
// AA0047
|
|
private static void HandleToggleCapsLock()
|
|
{
|
|
bool capsDown = Utils.IsPressed(CAPSLOCK);
|
|
if (capsDown && !_capsHeld)
|
|
{
|
|
_capsHeld = true;
|
|
_mainWindow.SetRecoilEnabled(!_mainWindow.IsRecoilEnabled);
|
|
}
|
|
if (!capsDown) _capsHeld = false;
|
|
}
|
|
|
|
// AA0048
|
|
private static void HandleNextSet()
|
|
{
|
|
if (Utils.IsPressed(ConfigLoader.nextSetKey) && !_nextSetHeld)
|
|
{
|
|
_nextSetHeld = true;
|
|
_mainWindow.HandleNextSet();
|
|
}
|
|
else if (!Utils.IsPressed(ConfigLoader.nextSetKey))
|
|
{
|
|
_nextSetHeld = false;
|
|
}
|
|
}
|
|
|
|
// AA0049
|
|
private static void HandlePrevSet()
|
|
{
|
|
if (Utils.IsPressed(ConfigLoader.prevSetKey) && !_prevSetHeld)
|
|
{
|
|
_prevSetHeld = true;
|
|
_mainWindow.HandlePrevSet();
|
|
}
|
|
else if (!Utils.IsPressed(ConfigLoader.prevSetKey))
|
|
{
|
|
_prevSetHeld = false;
|
|
}
|
|
}
|
|
|
|
// AA0050
|
|
private static void HandleRefresh()
|
|
{
|
|
if (Utils.IsPressed(ConfigLoader.refreshKey) && !_refreshHeld)
|
|
{
|
|
_refreshHeld = true;
|
|
_mainWindow.HandleRefresh();
|
|
}
|
|
else if (!Utils.IsPressed(ConfigLoader.refreshKey))
|
|
{
|
|
_refreshHeld = false;
|
|
}
|
|
}
|
|
|
|
// AA0051
|
|
private static void HandleSwitchSide()
|
|
{
|
|
if (Utils.IsPressed(ConfigLoader.switchSideKey) && !_switchSideHeld)
|
|
{
|
|
_switchSideHeld = true;
|
|
_mainWindow.HandleSwitchSide();
|
|
}
|
|
else if (!Utils.IsPressed(ConfigLoader.switchSideKey))
|
|
{
|
|
_switchSideHeld = false;
|
|
}
|
|
}
|
|
|
|
private static void HandleQuickSwaps()
|
|
{
|
|
if (ConfigLoader.quickSwaps == null || ConfigLoader.quickSwaps.Count == 0) return;
|
|
|
|
// Find all bindings that are currently fully pressed
|
|
var activeBindings = new System.Collections.Generic.List<Lua.QuickSwapBinding>();
|
|
foreach (var qs in ConfigLoader.quickSwaps)
|
|
{
|
|
bool allPressed = true;
|
|
foreach (var k in qs.Keys)
|
|
{
|
|
if (!Lua.Utils.IsPressed(k))
|
|
{
|
|
allPressed = false;
|
|
break;
|
|
}
|
|
}
|
|
if (allPressed)
|
|
{
|
|
activeBindings.Add(qs);
|
|
}
|
|
}
|
|
|
|
// Filter out bindings that are subsets of other active bindings
|
|
var triggeredBindings = new System.Collections.Generic.List<Lua.QuickSwapBinding>();
|
|
foreach (var ab in activeBindings)
|
|
{
|
|
bool hasSuperset = false;
|
|
foreach (var other in activeBindings)
|
|
{
|
|
if (other != ab && other.Keys.Length > ab.Keys.Length)
|
|
{
|
|
bool isSubset = true;
|
|
foreach (var k in ab.Keys)
|
|
{
|
|
bool found = false;
|
|
foreach (var ok in other.Keys)
|
|
{
|
|
if (ok == k) { found = true; break; }
|
|
}
|
|
if (!found) { isSubset = false; break; }
|
|
}
|
|
if (isSubset) { hasSuperset = true; break; }
|
|
}
|
|
}
|
|
if (!hasSuperset)
|
|
{
|
|
triggeredBindings.Add(ab);
|
|
}
|
|
}
|
|
|
|
// Update held status and trigger actions
|
|
foreach (var qs in ConfigLoader.quickSwaps)
|
|
{
|
|
if (triggeredBindings.Contains(qs))
|
|
{
|
|
if (!qs.IsHeld)
|
|
{
|
|
qs.IsHeld = true;
|
|
_mainWindow.HandleQuickSwap(qs.TargetOperator);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
qs.IsHeld = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |