## 🚀 Added (New Features)
• Quick Swap Feature:
• Users can now bind keyboard keys (both single keys and multi-key combinations, e.g., Alt+1 ) to switch to
specific operator sets.
• Auto-toggle capability: Pressing the hotkey switches to the target operator set (automatically changing side
if the operator is on standard Attackers/Defenders side). Pressing it again toggles back to the baseline
operator set.
• Added specificity filtering: Resolves overlapping hotkeys (e.g., pressing Alt+1 will only trigger the Alt+1
binding, successfully ignoring the individual 1 key binding).
• Added a dedicated Quick Swap Bindings editor inside the Settings panel to configure, save, and reload these
bindings visually.
## ⚙️ Updated (Refactoring & Architecture)
• Graceful Thread Shutdown: Updated RecoilEngine.cs to run with a CancellationToken linked to the main window
lifespan, matching HotkeyHandler.cs and preventing background thread leaks when exiting.
• State Management: Updated OperatorSets methods to protect the quick swap transition state, ensuring manual
adjustments (clicks or next/prev hotkeys) reset the quick-swap toggle baseline.
• Config Serialization: Updated MainWindow configuration generator to save new quick-swap parameters cleanly back
to init.config .
## 🛠️ Fixed (Bugs resolved)
• TabControl/Menu Text Colors: Fixed the styling on MainWindow.xaml tab headers. Unselected and hover states now
render in clear light greys, and active tabs in solid white, resolving dark-on-dark invisible text bugs.
• Dropdown Selection Visibility: Changed the text foreground color of TextColorComboBox in MainWindow.xaml from
black to white to make choices readable in dark mode.
• UI Console Text Color: Bound the console setting ( textColor ) to the actual WPF GUI log ( ConsoleOutput.
Foreground ), making the chosen color reflect in the application window.
──────
### 📂 File-Level Changes Summary
• helper.cs: Added helper.cs to safely parse combinations.
• ConfigLoader.cs: Added ConfigLoader.cs class and loading logic.
• OperatorSets.cs: Added OperatorSets.cs and state-tracking flags.
• HotkeyHandler.cs: Registered hotkey monitoring loops for multi-key patterns.
• RecoilEngine.cs: Integrated thread lifecycle cancellation.
• MainWindow.xaml: Styled menus, fixed dropdown contrast, and added Quick Swap bindings textbox.
• MainWindow.xaml.cs: Connected UI controls to backend quick-swap actions and applied dynamic log coloring.
This commit is contained in:
+51
-22
@@ -1,4 +1,4 @@
|
||||
using Lithium;
|
||||
using Lithium;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
@@ -25,36 +25,55 @@ namespace Lua
|
||||
return (GetAsyncKeyState(key) & 0x8000) != 0;
|
||||
}
|
||||
|
||||
public static void Start(MainWindow window)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (window.IsRecoilEnabled && IsDown(VK_LBUTTON) && IsDown(VK_RBUTTON))
|
||||
{
|
||||
HandleRecoilTick();
|
||||
}
|
||||
else
|
||||
{
|
||||
_remainderX = _remainderY = 0;
|
||||
_jitterActive = false;
|
||||
}
|
||||
private static CancellationTokenSource _cancellationSource;
|
||||
|
||||
Thread.Sleep(2);
|
||||
public static void Start(MainWindow window, CancellationToken cancellationToken = default)
|
||||
{
|
||||
_cancellationSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (!_cancellationSource.Token.IsCancellationRequested)
|
||||
{
|
||||
// FIX: Perform key checks once and reuse the results
|
||||
bool leftDown = IsDown(VK_LBUTTON);
|
||||
bool rightDown = IsDown(VK_RBUTTON);
|
||||
|
||||
if (window.IsRecoilEnabled && leftDown && rightDown)
|
||||
{
|
||||
HandleRecoilTick();
|
||||
}
|
||||
else
|
||||
{
|
||||
_remainderX = _remainderY = 0;
|
||||
_jitterActive = false;
|
||||
}
|
||||
|
||||
Thread.Sleep(2);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"RecoilEngine error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void HandleRecoilTick()
|
||||
{
|
||||
if (!IsDown(VK_LBUTTON)) return;
|
||||
try
|
||||
{
|
||||
string setName = OperatorSets.CurrentSet;
|
||||
|
||||
string setName = OperatorSets.CurrentSet;
|
||||
if (!OperatorSets.mergedSets.TryGetValue(setName, out var recoil)) return;
|
||||
|
||||
if (!OperatorSets.mergedSets.TryGetValue(setName, out var recoil)) return;
|
||||
int now = Environment.TickCount;
|
||||
|
||||
int now = Environment.TickCount;
|
||||
|
||||
HandleJitter(now);
|
||||
ApplyRecoil(recoil);
|
||||
HandleJitter(now);
|
||||
ApplyRecoil(recoil);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"HandleRecoilTick error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void HandleJitter(int now)
|
||||
@@ -103,5 +122,15 @@ namespace Lua
|
||||
|
||||
Utils.MoveMouse(ix, iy);
|
||||
}
|
||||
|
||||
public static void Stop()
|
||||
{
|
||||
try
|
||||
{
|
||||
_cancellationSource?.Cancel();
|
||||
_cancellationSource?.Dispose();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user