Convert desktop to EchoType Bridge: pipe injection via TIP
- Add EchoType to TextInjectionMode enum (becomes default) - Add WriteToEchoTypePipe(): write [UINT32 cch][WCHAR text] to \.\pipe\EchoType\pid_<PID> via NamedPipeClientStream - InsertText(): route to EchoType pipe when mode is EchoType - TrayApplicationContext: add 'EchoType (recommended)' to input mode menu - Update tray branding: 'EchoType Bridge' in tooltips and balloon tips - AppLogger: log to %LocalAppData%\EchoType\bridge.log The bridge keeps WebSocket server + UDP discovery + audio control unchanged. Text injection now goes through the EchoType TIP's composition-commit mechanism for atomic insertion, falling back to clipboard and SendInput as secondary options. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
namespace WirelessTextSyncer.Windows.Services;
|
||||
|
||||
using System.IO.Pipes;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace WirelessTextSyncer.Windows.Services;
|
||||
|
||||
public enum TextInjectionMode
|
||||
{
|
||||
EchoType,
|
||||
ClipboardPaste,
|
||||
SendInputTyping
|
||||
}
|
||||
@@ -22,7 +24,7 @@ public sealed class KeyboardInjectionService : IKeyboardInjectionService
|
||||
private const ushort VirtualKeyV = 0x56;
|
||||
private static readonly IntPtr EnglishKeyboardLayout = LoadKeyboardLayout("00000409", KlfActivate);
|
||||
|
||||
public TextInjectionMode Mode { get; set; } = TextInjectionMode.ClipboardPaste;
|
||||
public TextInjectionMode Mode { get; set; } = TextInjectionMode.EchoType;
|
||||
|
||||
public void InsertText(string text)
|
||||
{
|
||||
@@ -32,6 +34,12 @@ public sealed class KeyboardInjectionService : IKeyboardInjectionService
|
||||
}
|
||||
|
||||
AppLogger.Info($"Inserting text length: {text.Length}. Mode: {Mode}.");
|
||||
if (Mode == TextInjectionMode.EchoType)
|
||||
{
|
||||
WriteToEchoTypePipe(text);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Mode == TextInjectionMode.SendInputTyping)
|
||||
{
|
||||
TypeTextWithSendInput(text);
|
||||
@@ -41,6 +49,50 @@ public sealed class KeyboardInjectionService : IKeyboardInjectionService
|
||||
PasteTextViaClipboard(text);
|
||||
}
|
||||
|
||||
private static void WriteToEchoTypePipe(string text)
|
||||
{
|
||||
var fgWindow = GetForegroundWindow();
|
||||
if (fgWindow == IntPtr.Zero)
|
||||
{
|
||||
AppLogger.Error("EchoType pipe: no foreground window.");
|
||||
return;
|
||||
}
|
||||
|
||||
GetWindowThreadProcessId(fgWindow, out var pid);
|
||||
if (pid == 0)
|
||||
{
|
||||
AppLogger.Error("EchoType pipe: failed to get PID.");
|
||||
return;
|
||||
}
|
||||
|
||||
var pipeName = $@"EchoType\pid_{pid}";
|
||||
|
||||
try
|
||||
{
|
||||
using var pipe = new NamedPipeClientStream(".", pipeName, PipeDirection.Out);
|
||||
pipe.Connect(timeout: 2000);
|
||||
|
||||
var utf16 = System.Text.Encoding.Unicode.GetBytes(text);
|
||||
var cch = (uint)text.Length;
|
||||
var header = BitConverter.GetBytes(cch);
|
||||
|
||||
pipe.Write(header, 0, 4);
|
||||
pipe.Write(utf16, 0, utf16.Length);
|
||||
pipe.Flush();
|
||||
|
||||
AppLogger.Info($"EchoType pipe: sent {cch} chars to PID {pid}.");
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
AppLogger.Error(
|
||||
$"EchoType pipe: connection timeout for PID {pid}. Is EchoType the active IME in that app?");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AppLogger.Error($"EchoType pipe write failed for PID {pid}.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static void TypeTextWithSendInput(string text)
|
||||
{
|
||||
AppLogger.Info($"Falling back to SendInput text length: {text.Length}");
|
||||
|
||||
Reference in New Issue
Block a user