diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 7943e90..830bbb6 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -127,11 +127,6 @@ jobs:
UPDATE_CHANNEL: ${{ env.UPDATE_CHANNEL }}
run: .\build\build-complete.ps1 -Configuration Debug -ExeOnly -UpdateChannel $env:UPDATE_CHANNEL
- - name: Clean Debug output
- run: |
- $outDir = "Windows-Hinting\bin\Debug\net10.0-windows"
- Remove-Item "$outDir\xunit.*" -Force -ErrorAction SilentlyContinue
-
- name: Upload Debug artifact
uses: actions/upload-artifact@v7
with:
diff --git a/Windows-Hinting/Examples/HintOverlayClientExamples.cs b/Windows-Hinting/Examples/HintOverlayClientExamples.cs
deleted file mode 100644
index f1a9637..0000000
--- a/Windows-Hinting/Examples/HintOverlayClientExamples.cs
+++ /dev/null
@@ -1,238 +0,0 @@
-using System;
-using WindowsHinting.NamedPipeClient;
-
-namespace WindowsHinting.Examples
-{
- ///
- /// Example usage of the HintOverlayClient for controlling Windows-Hinting from external applications.
- ///
- internal static class HintOverlayClientExamples
- {
- ///
- /// Basic example: Toggle hints on/off
- ///
- public static void BasicToggleExample()
- {
- using var client = new HintOverlayClient();
-
- if (client.Toggle())
- {
- Console.WriteLine("Successfully toggled Windows-Hinting");
- }
- else
- {
- Console.WriteLine("Failed to connect to Windows-Hinting");
- }
- }
-
- ///
- /// Example: Select a specific hint and activate it
- ///
- public static void SelectHintExample()
- {
- using var client = new HintOverlayClient();
-
- // First, ensure hints are active
- client.Toggle();
-
- // Wait a moment for hints to load
- System.Threading.Thread.Sleep(500);
-
- // Select and activate hint "A"
- if (client.SelectHint("A"))
- {
- Console.WriteLine("Successfully selected hint A");
- }
- else
- {
- Console.WriteLine("Failed to select hint A");
- }
- }
-
- ///
- /// Example: Sequential hint selection (simulating user typing)
- ///
- public static void SequentialSelectionExample()
- {
- using var client = new HintOverlayClient();
-
- // Activate hints
- client.Toggle();
- System.Threading.Thread.Sleep(500);
-
- // Select hint with label "AB"
- if (client.SelectHint("AB"))
- {
- Console.WriteLine("Selected hint AB");
- }
- }
-
- ///
- /// Example: Toggle with automatic retry handling
- /// The client automatically handles connection retries
- ///
- public static void AutomaticRetryExample()
- {
- using var client = new HintOverlayClient();
-
- // This will work even if Windows-Hinting is starting up
- // The client will retry for up to 5 seconds automatically
- bool success = client.Toggle();
-
- if (success)
- {
- Console.WriteLine("Command sent (Windows-Hinting may have been starting)");
- }
- else
- {
- Console.WriteLine("Failed after 5 seconds of retrying");
- }
- }
-
- ///
- /// Example: Deactivate hints
- ///
- public static void DeactivateExample()
- {
- using var client = new HintOverlayClient();
-
- if (client.Deactivate())
- {
- Console.WriteLine("Successfully deactivated Windows-Hinting");
- }
- }
-
- ///
- /// Example: Error handling
- ///
- public static void ErrorHandlingExample()
- {
- using var client = new HintOverlayClient();
-
- try
- {
- if (!client.SelectHint("XYZ"))
- {
- Console.WriteLine("Failed to send command - Windows-Hinting not responding?");
- }
- else
- {
- Console.WriteLine("Command sent - check Windows-Hinting logs for result");
- }
- }
- catch (ArgumentException ex)
- {
- Console.WriteLine($"Invalid argument: {ex.Message}");
- }
- }
-
- ///
- /// Example: Integration with keyboard shortcuts
- /// Could be used by a global hotkey handler to control Windows-Hinting
- ///
- public static void KeyboardIntegrationExample()
- {
- using var client = new HintOverlayClient();
-
- // Hypothetical: You have a global hotkey handler that calls this
- // when user presses Ctrl+Shift+H to toggle hints
- var success = client.Toggle();
-
- // You could log the result
- if (!success)
- {
- Console.WriteLine("Warning: Unable to toggle Windows-Hinting");
- }
- }
-
- ///
- /// Example: UI Control Integration
- /// You could have a UI element that controls Windows-Hinting
- ///
- public static void UIControlExample()
- {
- using var client = new HintOverlayClient();
-
- // Example of button click handler
- // When user clicks "Toggle Hints" button
- Console.WriteLine("Toggle Hints button clicked");
-
- if (client.Toggle())
- {
- // Update UI to show success
- Console.WriteLine("Hints toggled successfully");
- }
- else
- {
- // Show error to user
- Console.WriteLine("Could not reach Windows-Hinting service");
- }
- }
-
- ///
- /// Example: Automated testing or scripting
- ///
- public static void AutomationExample()
- {
- using var client = new HintOverlayClient();
-
- // Test 1: Toggle ON
- client.Toggle();
- System.Threading.Thread.Sleep(1000);
-
- // Test 2: Select hint
- client.SelectHint("A");
- System.Threading.Thread.Sleep(1000);
-
- // Test 3: Toggle OFF
- client.Deactivate();
-
- Console.WriteLine("Automation test completed");
- }
-
- ///
- /// Example: Select a hint with a specific click action
- /// Actions: "LEFT" (left click), "RIGHT" (right click), "DOUBLE" (double click),
- /// "CTRL" (ctrl+click), "SHIFT" (shift+click), "MOVE" (mouse move), or null for default activation
- ///
- public static void ClickActionExample()
- {
- using var client = new HintOverlayClient();
-
- // First, ensure hints are active
- client.Toggle();
- System.Threading.Thread.Sleep(500);
-
- // Default activation (uses UI Automation invoke pattern)
- client.SelectHint("A");
-
- // Or equivalently
- client.SelectHint("A", null);
-
- // Left click the element
- client.Toggle();
- System.Threading.Thread.Sleep(500);
- client.SelectHint("A", "LEFT");
-
- // Right click the element (e.g., to open context menu)
- client.Toggle();
- System.Threading.Thread.Sleep(500);
- client.SelectHint("B", "RIGHT");
-
- // Double click the element
- client.Toggle();
- System.Threading.Thread.Sleep(500);
- client.SelectHint("C", "DOUBLE");
-
- // Ctrl+click the element (e.g., to open in new tab or multi-select)
- client.Toggle();
- System.Threading.Thread.Sleep(500);
- client.SelectHint("D", "CTRL");
-
- // Shift+click the element (e.g., to extend selection)
- client.Toggle();
- System.Threading.Thread.Sleep(500);
- client.SelectHint("E", "SHIFT");
- }
- }
-}
diff --git a/Windows-Hinting/HintController.cs b/Windows-Hinting/HintController.cs
index a73e78b..744c390 100644
--- a/Windows-Hinting/HintController.cs
+++ b/Windows-Hinting/HintController.cs
@@ -28,7 +28,6 @@ internal sealed class HintController : IDisposable
private readonly HintInputHandler _inputHandler;
private readonly TrayIconManager _trayIcon;
private readonly ElementActivatorChain _activatorChain;
- //private readonly NamedPipeService _namedPipeService;
private readonly WindowRuleRegistry _ruleRegistry;
private readonly MouseClickService _mouseClickService;
private readonly StartupService _startupService;
@@ -59,7 +58,6 @@ public HintController(
HintStateManager stateManager,
HintInputHandler inputHandler,
ElementActivatorChain activatorChain,
- //NamedPipeService namedPipeService,
MouseClickService mouseClickService,
StartupService startupService,
UpdateService updateService)
@@ -82,7 +80,6 @@ public HintController(
_stateManager = stateManager ?? throw new ArgumentNullException(nameof(stateManager));
_inputHandler = inputHandler ?? throw new ArgumentNullException(nameof(inputHandler));
_activatorChain = activatorChain ?? throw new ArgumentNullException(nameof(activatorChain));
- //_namedPipeService = namedPipeService ?? throw new ArgumentNullException(nameof(namedPipeService));
_mouseClickService = mouseClickService ?? throw new ArgumentNullException(nameof(mouseClickService));
_startupService = startupService ?? throw new ArgumentNullException(nameof(startupService));
_updateService = updateService ?? throw new ArgumentNullException(nameof(updateService));
@@ -130,12 +127,6 @@ public HintController(
_foregroundWindowHookService.ForegroundWindowChanged += OnForegroundWindowChanged;
- //_namedPipeService.CommandReceived += OnNamedPipeCommandReceived;
-
- // Start named pipe service
- // _logger.Debug("Starting named pipe service");
- //_namedPipeService.Start();
-
// Kick off the auto-update background loop (no-op if disabled in prefs).
_updateService.Initialize();
@@ -173,71 +164,6 @@ private void OnDisplaySettingsChanged(object? sender, EventArgs e)
_overlay.RebuildOverlays();
}
- private void OnNamedPipeCommandReceived(object? sender, NamedPipeCommand command)
- {
- _logger.Debug($"Processing named pipe command: {command.CommandType}");
-
- switch (command.CommandType)
- {
- case CommandType.Toggle:
- Toggle();
- break;
-
- case CommandType.ToggleTaskbar:
- ToggleTaskbar();
- break;
-
- case CommandType.Select:
- if (!string.IsNullOrEmpty(command.HintLabel))
- {
- SelectHintByLabel(command.HintLabel, command.Action);
- }
- break;
-
- case CommandType.Deactivate:
- _stateManager.Deactivate();
- break;
- }
- }
-
- private void SelectHintByLabel(string label, ClickAction action = ClickAction.Default)
- {
- _logger.Info($"Attempting to select hint with label: {label}, action: {action}");
-
- var hint = _stateManager.CurrentHints.FirstOrDefault(h =>
- h.Label.Equals(label, StringComparison.OrdinalIgnoreCase));
-
- if (hint == null)
- {
- _logger.Warning($"Hint with label '{label}' not found");
- return;
- }
-
- _logger.Info($"Activating hint: {hint.Label}, action: {action}");
-
- try
- {
- if (action == ClickAction.Default)
- {
- _activatorChain.TryActivate(hint.Element);
- }
- else
- {
- _mouseClickService.PerformClick(hint.Rect, action);
- }
- }
- catch (Exception ex)
- {
- _logger.Error($"Error activating hint '{label}'", ex);
- }
- finally
- {
- // Hide hints after activation
- _logger.Debug("Deactivating hints after direct selection");
- _stateManager.Deactivate();
- }
- }
-
public void Toggle()
{
using (PerformanceMetrics.Start("Toggle", _logger, LogLevel.Debug))
diff --git a/Windows-Hinting/NamedPipeClient/HintOverlayClient.cs b/Windows-Hinting/NamedPipeClient/HintOverlayClient.cs
deleted file mode 100644
index f951914..0000000
--- a/Windows-Hinting/NamedPipeClient/HintOverlayClient.cs
+++ /dev/null
@@ -1,131 +0,0 @@
-using System;
-using System.IO.Pipes;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace WindowsHinting.NamedPipeClient
-{
- ///
- /// Client for communicating with Windows-Hinting via named pipes.
- /// This client handles connection retries to support order-independent execution.
- ///
- public sealed class HintOverlayClient : IDisposable
- {
- private const string PipeName = "WindowsHinting_Pipe";
- private const int ConnectionTimeoutMs = 5000;
- private const int RetryDelayMs = 100;
- private const int MaxRetries = 50;
- private bool _disposed;
-
- ///
- /// Toggles the hint overlay on or off.
- ///
- /// True if the command was sent successfully, false otherwise.
- public bool Toggle()
- {
- return SendCommand("TOGGLE");
- }
-
- ///
- /// Selects a hint by its label and activates the associated element using the default action.
- ///
- /// The label of the hint to select (e.g., "A", "B", "AB", etc.)
- /// True if the command was sent successfully, false otherwise.
- public bool SelectHint(string hintLabel)
- {
- if (string.IsNullOrWhiteSpace(hintLabel))
- throw new ArgumentException("Hint label cannot be null or empty", nameof(hintLabel));
-
- return SendCommand($"SELECT {hintLabel}");
- }
-
- ///
- /// Selects a hint by its label and performs the specified click action.
- ///
- /// The label of the hint to select (e.g., "A", "B", "AB", etc.)
- /// The click action to perform: "LEFT", "RIGHT", "DOUBLE", "MOVE", "CTRL", "SHIFT", or null/empty for default activation.
- /// True if the command was sent successfully, false otherwise.
- public bool SelectHint(string hintLabel, string? action)
- {
- if (string.IsNullOrWhiteSpace(hintLabel))
- throw new ArgumentException("Hint label cannot be null or empty", nameof(hintLabel));
-
- if (string.IsNullOrWhiteSpace(action))
- return SendCommand($"SELECT {hintLabel}");
-
- return SendCommand($"SELECT {hintLabel} {action}");
- }
-
- ///
- /// Deactivates the hint overlay.
- ///
- /// True if the command was sent successfully, false otherwise.
- public bool Deactivate()
- {
- return SendCommand("DEACTIVATE");
- }
-
- ///
- /// Toggles the taskbar-only hint mode on or off.
- ///
- /// True if the command was sent successfully, false otherwise.
- public bool ToggleTaskbar()
- {
- return SendCommand("TOGGLETASKBAR");
- }
-
- private bool SendCommand(string command)
- {
- return SendCommandAsync(command).GetAwaiter().GetResult();
- }
-
- private async Task SendCommandAsync(string command)
- {
- int retryCount = 0;
-
- while (retryCount < MaxRetries)
- {
- try
- {
- using (var pipeClient = new NamedPipeClientStream(".", PipeName, PipeDirection.Out))
- {
- pipeClient.Connect(ConnectionTimeoutMs);
-
- using (var writer = new StreamWriter(pipeClient, Encoding.UTF8))
- {
- await writer.WriteLineAsync(command);
- await writer.FlushAsync();
- }
-
- return true;
- }
- }
- catch (TimeoutException)
- {
- // Server not ready yet, retry
- retryCount++;
- if (retryCount < MaxRetries)
- {
- await Task.Delay(RetryDelayMs);
- }
- }
- catch (Exception)
- {
- // Other errors, stop retrying
- return false;
- }
- }
-
- return false;
- }
-
- public void Dispose()
- {
- if (_disposed)
- return;
-
- _disposed = true;
- }
- }
-}
diff --git a/Windows-Hinting/ServiceCollectionExtensions.cs b/Windows-Hinting/ServiceCollectionExtensions.cs
index dbe447d..5039f86 100644
--- a/Windows-Hinting/ServiceCollectionExtensions.cs
+++ b/Windows-Hinting/ServiceCollectionExtensions.cs
@@ -40,7 +40,6 @@ public static IServiceCollection AddHintOverlayServices(this IServiceCollection
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
- //services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
diff --git a/Windows-Hinting/Services/NamedPipeService.cs b/Windows-Hinting/Services/NamedPipeService.cs
deleted file mode 100644
index c380fd1..0000000
--- a/Windows-Hinting/Services/NamedPipeService.cs
+++ /dev/null
@@ -1,218 +0,0 @@
-using System;
-using System.IO;
-using System.IO.Pipes;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using WindowsHinting.Logging;
-using WindowsHinting.Models;
-
-namespace WindowsHinting.Services
-{
- internal sealed class NamedPipeService : IDisposable
- {
- private const string PipeName = "WindowsHinting_Pipe";
- private const int MaxConnections = 10;
- private readonly ILogger _logger;
- private NamedPipeServerStream? _pipeServer;
- private CancellationTokenSource? _cancellationTokenSource;
- private Task? _listenerTask;
- private bool _disposed;
-
- public event EventHandler? CommandReceived;
-
- public NamedPipeService(ILogger logger)
- {
- _logger = logger ?? throw new ArgumentNullException(nameof(logger));
- }
-
- public void Start()
- {
- if (_cancellationTokenSource != null)
- {
- _logger.Warning("Named pipe service already started");
- return;
- }
-
- _logger.Info($"Starting named pipe server: {PipeName}");
- _cancellationTokenSource = new CancellationTokenSource();
- _listenerTask = ListenForConnectionsAsync(_cancellationTokenSource.Token);
- }
-
- public void Stop()
- {
- _logger.Info("Stopping named pipe service");
- _cancellationTokenSource?.Cancel();
- try
- {
- _listenerTask?.Wait(TimeSpan.FromSeconds(5));
- }
- catch (OperationCanceledException)
- {
- // Expected
- }
- _pipeServer?.Dispose();
- _pipeServer = null;
- }
-
- private async Task ListenForConnectionsAsync(CancellationToken cancellationToken)
- {
- try
- {
- while (!cancellationToken.IsCancellationRequested)
- {
- _pipeServer = new NamedPipeServerStream(
- PipeName,
- PipeDirection.In,
- MaxConnections,
- PipeTransmissionMode.Byte,
- PipeOptions.Asynchronous);
-
- try
- {
- _logger.Debug("Waiting for named pipe connection...");
- await _pipeServer.WaitForConnectionAsync(cancellationToken);
- _logger.Debug("Named pipe client connected");
-
- // Handle the client in a separate task
- _ = HandleClientAsync(_pipeServer, cancellationToken);
-
- // Create a new server for the next connection
- _pipeServer = null;
- }
- catch (OperationCanceledException)
- {
- throw;
- }
- catch (Exception ex)
- {
- _logger.Error($"Error in named pipe listener: {ex.Message}", ex);
- }
- }
- }
- catch (OperationCanceledException)
- {
- _logger.Debug("Named pipe listener cancelled");
- }
- catch (Exception ex)
- {
- _logger.Error($"Fatal error in named pipe listener: {ex.Message}", ex);
- }
- }
-
- private async Task HandleClientAsync(NamedPipeServerStream pipeServer, CancellationToken cancellationToken)
- {
- try
- {
- using (var reader = new StreamReader(pipeServer, Encoding.UTF8))
- {
- string? line;
- while ((line = await reader.ReadLineAsync(cancellationToken)) != null)
- {
- if (string.IsNullOrWhiteSpace(line))
- continue;
-
- _logger.Debug($"Received named pipe command: {line}");
-
- var command = ParseCommand(line);
- if (command != null)
- {
- CommandReceived?.Invoke(this, command);
- }
- }
- }
- }
- catch (OperationCanceledException)
- {
- _logger.Debug("Client handler cancelled");
- }
- catch (Exception ex)
- {
- _logger.Error($"Error handling named pipe client: {ex.Message}", ex);
- }
- finally
- {
- try
- {
- pipeServer.Close();
- }
- catch { }
- }
- }
-
- private NamedPipeCommand? ParseCommand(string line)
- {
- try
- {
- var parts = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
- if (parts.Length == 0)
- return null;
-
- string command = parts[0].ToUpperInvariant();
-
- return command switch
- {
- "TOGGLE" => new NamedPipeCommand { CommandType = CommandType.Toggle },
- "TOGGLETASKBAR" => new NamedPipeCommand { CommandType = CommandType.ToggleTaskbar },
- "SELECT" => parts.Length > 1 ? new NamedPipeCommand
- {
- CommandType = CommandType.Select,
- HintLabel = parts[1],
- Action = ParseClickAction(parts.Length > 2 ? parts[2] : null)
- } : null,
- "DEACTIVATE" => new NamedPipeCommand { CommandType = CommandType.Deactivate },
- _ => null
- };
- }
- catch (Exception ex)
- {
- _logger.Warning($"Error parsing named pipe command '{line}': {ex.Message}");
- return null;
- }
- }
-
- private static ClickAction ParseClickAction(string? value)
- {
- if (string.IsNullOrEmpty(value))
- return ClickAction.Default;
-
- return value.ToUpperInvariant() switch
- {
- "LEFT" => ClickAction.LeftClick,
- "RIGHT" => ClickAction.RightClick,
- "DOUBLE" => ClickAction.DoubleClick,
- "MOVE" => ClickAction.MouseMove,
- "CTRL" => ClickAction.CtrlClick,
- "SHIFT" => ClickAction.ShiftClick,
- _ => ClickAction.Default
- };
- }
-
- public void Dispose()
- {
- if (_disposed)
- return;
-
- _logger.Debug("Disposing NamedPipeService");
- Stop();
- _cancellationTokenSource?.Dispose();
- _pipeServer?.Dispose();
- _disposed = true;
- }
- }
-
- internal enum CommandType
- {
- Toggle,
- ToggleTaskbar,
- Select,
- Deactivate
- }
-
- internal sealed class NamedPipeCommand
- {
- public CommandType CommandType { get; set; }
- public string? HintLabel { get; set; }
- public ClickAction Action { get; set; } = ClickAction.Default;
- }
-}
diff --git a/Windows-Hinting/Windows-Hinting.csproj b/Windows-Hinting/Windows-Hinting.csproj
index 590e647..869ed8f 100644
--- a/Windows-Hinting/Windows-Hinting.csproj
+++ b/Windows-Hinting/Windows-Hinting.csproj
@@ -98,11 +98,6 @@
-
-
-
-
-
diff --git a/docs/architecture/phases/phase-00-dead-code-and-test-hygiene.md b/docs/architecture/phases/phase-00-dead-code-and-test-hygiene.md
index 35e8d5a..8b300bd 100644
--- a/docs/architecture/phases/phase-00-dead-code-and-test-hygiene.md
+++ b/docs/architecture/phases/phase-00-dead-code-and-test-hygiene.md
@@ -17,7 +17,7 @@ because of it, so later phases start from a clean baseline. No behavior change.
- `Windows-Hinting/Services/NamedPipeService.cs`
- `Windows-Hinting/NamedPipeClient/HintOverlayClient.cs` (and the `NamedPipeClient` folder)
- `Windows-Hinting/Examples/HintOverlayClientExamples.cs` (and the `Examples` folder)
- - The `NamedPipeCommand` / `CommandType` types (in `Windows-Hinting/Models/Models.cs`)
+ - The `NamedPipeCommand` / `CommandType` types (declared at the bottom of `NamedPipeService.cs`)
- The commented-out registration and wiring lines that referenced any of the above
2. **Remove orphaned test references.** Delete the `xunit.assert` / `xunit.v3.extensibility.core`
package references from `Windows-Hinting/Windows-Hinting.csproj` and the "Clean Debug output"