From 233f024d9898294f9d062abb47bfcb8652a04b24 Mon Sep 17 00:00:00 2001 From: Lesueur Benjamin Date: Fri, 12 Nov 2021 14:49:19 +0100 Subject: [PATCH] implemented NamedPipe --- ControllerHelper/ControllerHelper.Designer.cs | 53 +++++++ ControllerHelper/ControllerHelper.cs | 87 +++++++++++ ControllerHelper/ControllerHelper.csproj | 37 +++++ ControllerHelper/ControllerHelper.resx | 60 ++++++++ ControllerHelper/MouseHook.cs | 72 +++++++++ ControllerHelper/PipeClient.cs | 68 +++++++++ ControllerHelper/Program.cs | 27 ++++ .../Toast.png | Bin ControllerService.sln | 15 +- ControllerService/ControllerClient.cs | 64 ++------ ControllerService/ControllerService.cs | 136 +++++++++-------- ControllerService/ControllerService.csproj | 2 +- ControllerService/DS4Touch.cs | 54 +------ ControllerService/DSUServer.cs | 9 +- ControllerService/HidHide.cs | 8 +- ControllerService/PipeServer.cs | 143 ++++++++++++++++++ ControllerService/XInputController.cs | 15 +- ControllerService/install.cmd | 2 +- ControllerServiceClient/App.config | 6 - .../ControllerServiceClient.csproj | 44 ------ ControllerServiceClient/Program.cs | 77 ---------- .../Properties/AssemblyInfo.cs | 9 -- 22 files changed, 663 insertions(+), 325 deletions(-) create mode 100644 ControllerHelper/ControllerHelper.Designer.cs create mode 100644 ControllerHelper/ControllerHelper.cs create mode 100644 ControllerHelper/ControllerHelper.csproj create mode 100644 ControllerHelper/ControllerHelper.resx create mode 100644 ControllerHelper/MouseHook.cs create mode 100644 ControllerHelper/PipeClient.cs create mode 100644 ControllerHelper/Program.cs rename {ControllerServiceClient => ControllerHelper}/Toast.png (100%) create mode 100644 ControllerService/PipeServer.cs delete mode 100644 ControllerServiceClient/App.config delete mode 100644 ControllerServiceClient/ControllerServiceClient.csproj delete mode 100644 ControllerServiceClient/Program.cs delete mode 100644 ControllerServiceClient/Properties/AssemblyInfo.cs diff --git a/ControllerHelper/ControllerHelper.Designer.cs b/ControllerHelper/ControllerHelper.Designer.cs new file mode 100644 index 000000000..ed1f934ac --- /dev/null +++ b/ControllerHelper/ControllerHelper.Designer.cs @@ -0,0 +1,53 @@ + +namespace ControllerHelper +{ + partial class ControllerHelper + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // ControllerHelper + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(0, 0); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + this.Name = "ControllerHelper"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.Text = "ControllerHelper"; + this.WindowState = System.Windows.Forms.FormWindowState.Minimized; + this.Load += new System.EventHandler(this.ControllerHelper_Load); + this.ResumeLayout(false); + + } + + #endregion + } +} + diff --git a/ControllerHelper/ControllerHelper.cs b/ControllerHelper/ControllerHelper.cs new file mode 100644 index 000000000..6a11d0eab --- /dev/null +++ b/ControllerHelper/ControllerHelper.cs @@ -0,0 +1,87 @@ +using ControllerService; +using Microsoft.Toolkit.Uwp.Notifications; +using System; +using System.Runtime.InteropServices; +using System.Timers; +using System.Windows.Forms; +using Timer = System.Timers.Timer; + +namespace ControllerHelper +{ + public partial class ControllerHelper : Form + { + #region imports + [DllImport("User32.dll")] + static extern IntPtr GetForegroundWindow(); + [DllImport("user32.dll", SetLastError = true)] + static extern uint GetWindowThreadProcessId(IntPtr hWnd, out IntPtr lpdwProcessId); + #endregion + + private PipeClient PipeClient; + private Timer MonitorTimer; + private IntPtr CurrentProcess; + + private MouseHook m_Hook; + + public ControllerHelper() + { + InitializeComponent(); + this.Hide(); + } + + private void ControllerHelper_Load(object sender, EventArgs e) + { + // start the pipe client + PipeClient = new PipeClient("ControllerService", this); + PipeClient.Start(); + + // start mouse hook + m_Hook = new MouseHook(PipeClient); + m_Hook.Start(); + + // monitors processes + MonitorTimer = new Timer(1000) { Enabled = true, AutoReset = true }; + MonitorTimer.Elapsed += MonitorHelper; + } + + private void ControllerHelper_Closed(object sender, System.Windows.Forms.FormClosedEventArgs e) + { + PipeClient.Stop(); + } + + public void Kill() + { + Application.Exit(); + } + + private void MonitorHelper(object sender, ElapsedEventArgs e) + { + IntPtr hWnd = GetForegroundWindow(); + IntPtr processId; + + if (GetWindowThreadProcessId(hWnd, out processId) == 0) + return; + + if (processId != CurrentProcess) + { + PipeMessage message = new PipeMessage { Code = PipeCode.CODE_PROCESS, args = new string[] { processId.ToString() } }; + PipeClient.SendMessage(message); + + CurrentProcess = processId; + } + } + + public void SendToast(string title, string content) + { + string url = "file:///" + AppDomain.CurrentDomain.BaseDirectory + "Toast.png"; + var uri = new Uri(url); + + new ToastContentBuilder() + .AddText(title) + .AddText(content) + .AddAppLogoOverride(uri, ToastGenericAppLogoCrop.Circle) + .SetToastDuration(ToastDuration.Short) + .Show(); + } + } +} diff --git a/ControllerHelper/ControllerHelper.csproj b/ControllerHelper/ControllerHelper.csproj new file mode 100644 index 000000000..e0c1b95ea --- /dev/null +++ b/ControllerHelper/ControllerHelper.csproj @@ -0,0 +1,37 @@ + + + + WinExe + net5.0-windows10.0.19041.0 + false + false + true + true + ControllerHelper + ControllerHelper + Copyright © 2021 + $(SolutionDir)bin\ + + + full + + + pdbonly + + + + + + + + + + + + + + PreserveNewest + + + + \ No newline at end of file diff --git a/ControllerHelper/ControllerHelper.resx b/ControllerHelper/ControllerHelper.resx new file mode 100644 index 000000000..f298a7be8 --- /dev/null +++ b/ControllerHelper/ControllerHelper.resx @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/ControllerHelper/MouseHook.cs b/ControllerHelper/MouseHook.cs new file mode 100644 index 000000000..fdcdfe568 --- /dev/null +++ b/ControllerHelper/MouseHook.cs @@ -0,0 +1,72 @@ +using ControllerService; +using Gma.System.MouseKeyHook; +using System.Threading; +using System.Timers; +using System.Windows.Forms; +using Timer = System.Timers.Timer; + +namespace ControllerHelper +{ + public class MouseHook + { + private IKeyboardMouseEvents m_Events; + private Thread m_Hook; + private Timer m_Timer; + + private PipeClient client; + + public MouseHook(PipeClient client) + { + this.client = client; + + // send MouseUp after 50ms interval + m_Timer = new Timer() { Enabled = false, Interval = 50, AutoReset = false }; + m_Timer.Elapsed += SendMouseUp; + + m_Hook = new Thread(Subscribe) { IsBackground = true }; + } + + public void Start() + { + m_Hook.Start(); + } + + private void Subscribe() + { + m_Events = Hook.GlobalEvents(); + m_Events.MouseMoveExt += OnMouseMove; + m_Events.MouseDownExt += OnMouseDown; + m_Events.MouseUpExt += OnMouseUp; + Application.Run(); + } + + private void SendMouseUp(object sender, ElapsedEventArgs e) + { + client.SendMessage(new PipeMessage { Code = PipeCode.CODE_CURSOR_UP }); + } + + private void OnMouseDown(object sender, MouseEventExtArgs e) + { + m_Timer.Stop(); + client.SendMessage(new PipeMessage { Code = PipeCode.CODE_CURSOR_DOWN }); + } + + private void OnMouseMove(object sender, MouseEventExtArgs e) + { + short TouchX = (short)(e.X); + short TouchY = (short)(e.Y); + client.SendMessage(new PipeMessage { Code = PipeCode.CODE_CURSOR_MOVE, args = new string[] { TouchX.ToString(), TouchY.ToString() } }); + } + + private void OnMouseUp(object sender, MouseEventExtArgs e) + { + m_Timer.Start(); + } + + internal void Stop() + { + m_Events.Dispose(); + m_Hook = null; + } + } +} diff --git a/ControllerHelper/PipeClient.cs b/ControllerHelper/PipeClient.cs new file mode 100644 index 000000000..1721a2fe3 --- /dev/null +++ b/ControllerHelper/PipeClient.cs @@ -0,0 +1,68 @@ +using ControllerService; +using NamedPipeWrapper; +using System; +using System.Windows.Forms; + +namespace ControllerHelper +{ + public class PipeClient + { + private readonly NamedPipeClient client; + private readonly ControllerHelper helper; + + public PipeClient(string pipeName, ControllerHelper helper) + { + this.helper = helper; + + client = new NamedPipeClient(pipeName); + client.AutoReconnect = true; + + client.Disconnected += OnClientDisconnected; + client.ServerMessage += OnServerMessage; + client.Error += OnError; + } + + private void OnClientDisconnected(NamedPipeConnection connection) + { + client.Stop(); + helper.Kill(); + } + + public void Start() + { + if (client == null) + return; + + client.Start(); + } + + public void Stop() + { + if (client == null) + return; + + client.Stop(); + } + + private void OnServerMessage(NamedPipeConnection connection, PipeMessage message) + { + switch (message.Code) + { + case PipeCode.CODE_TOAST: + helper.SendToast(message.args[0], message.args[1]); + break; + } + } + + private void OnError(Exception exception) + { + client.Stop(); + helper.Kill(); + } + + public void SendMessage(PipeMessage message) + { + client.PushMessage(message); + } + } +} diff --git a/ControllerHelper/Program.cs b/ControllerHelper/Program.cs new file mode 100644 index 000000000..bbde1d1a7 --- /dev/null +++ b/ControllerHelper/Program.cs @@ -0,0 +1,27 @@ +using System; +using System.Diagnostics; +using System.Linq; +using System.Windows.Forms; + +namespace ControllerHelper +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + String thisprocessname = Process.GetCurrentProcess().ProcessName; + + if (Process.GetProcesses().Count(p => p.ProcessName == thisprocessname) > 1) + return; + + Application.SetHighDpiMode(HighDpiMode.SystemAware); + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new ControllerHelper()); + } + } +} diff --git a/ControllerServiceClient/Toast.png b/ControllerHelper/Toast.png similarity index 100% rename from ControllerServiceClient/Toast.png rename to ControllerHelper/Toast.png diff --git a/ControllerService.sln b/ControllerService.sln index e6b877397..e3cc57699 100644 --- a/ControllerService.sln +++ b/ControllerService.sln @@ -3,9 +3,12 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.31702.278 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControllerService", "ControllerService\ControllerService.csproj", "{6B7B570E-8C8B-4189-9C98-B3BBFE630615}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControllerService", "ControllerService\ControllerService.csproj", "{6B7B570E-8C8B-4189-9C98-B3BBFE630615}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControllerServiceClient", "ControllerServiceClient\ControllerServiceClient.csproj", "{15236FBC-7E2A-4BE9-9A0E-9F4A75348892}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControllerHelper", "ControllerHelper\ControllerHelper.csproj", "{3BB6F372-E910-4A27-810B-64152F163709}" + ProjectSection(ProjectDependencies) = postProject + {6B7B570E-8C8B-4189-9C98-B3BBFE630615} = {6B7B570E-8C8B-4189-9C98-B3BBFE630615} + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -17,10 +20,10 @@ Global {6B7B570E-8C8B-4189-9C98-B3BBFE630615}.Debug|Any CPU.Build.0 = Debug|Any CPU {6B7B570E-8C8B-4189-9C98-B3BBFE630615}.Release|Any CPU.ActiveCfg = Release|Any CPU {6B7B570E-8C8B-4189-9C98-B3BBFE630615}.Release|Any CPU.Build.0 = Release|Any CPU - {15236FBC-7E2A-4BE9-9A0E-9F4A75348892}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {15236FBC-7E2A-4BE9-9A0E-9F4A75348892}.Debug|Any CPU.Build.0 = Debug|Any CPU - {15236FBC-7E2A-4BE9-9A0E-9F4A75348892}.Release|Any CPU.ActiveCfg = Release|Any CPU - {15236FBC-7E2A-4BE9-9A0E-9F4A75348892}.Release|Any CPU.Build.0 = Release|Any CPU + {3BB6F372-E910-4A27-810B-64152F163709}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3BB6F372-E910-4A27-810B-64152F163709}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3BB6F372-E910-4A27-810B-64152F163709}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3BB6F372-E910-4A27-810B-64152F163709}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ControllerService/ControllerClient.cs b/ControllerService/ControllerClient.cs index a6214e055..60638f5b7 100644 --- a/ControllerService/ControllerClient.cs +++ b/ControllerService/ControllerClient.cs @@ -106,65 +106,16 @@ static extern bool ReadFile( [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern uint WaitForSingleObject(IntPtr hProcess, uint dwMilliseconds); - public static int GetProcessIdByPath() - { - IntPtr read = new IntPtr(); - IntPtr write = new IntPtr(); - IntPtr read2 = new IntPtr(); - IntPtr write2 = new IntPtr(); - SECURITY_ATTRIBUTES saAttr = new SECURITY_ATTRIBUTES(); - saAttr.nLength = Marshal.SizeOf(typeof(SECURITY_ATTRIBUTES)); - saAttr.bInheritHandle = 1; - saAttr.lpSecurityDescriptor = IntPtr.Zero; - - CreatePipe(ref read, ref write, ref saAttr, 0); - CreatePipe(ref read2, ref write2, ref saAttr, 0); - - int STARTF_USESTDHANDLES = 0x00000100; - si = new STARTUPINFO(); - si.cb = Marshal.SizeOf(typeof(STARTUPINFO)); - si.hStdOutput = write; - si.hStdError = write; - si.hStdInput = read2; - si.lpDesktop = "Winsta0\\default"; - si.dwFlags = STARTF_USESTDHANDLES; - - IntPtr hToken; - bool err = WTSQueryUserToken(WTSGetActiveConsoleSessionId(), out hToken); - - string cmdLine = "-g"; - if (CreateProcessAsUser(hToken, ControllerService.CurrentPathClient, $@"""{ControllerService.CurrentPathClient}"" {cmdLine}", IntPtr.Zero, IntPtr.Zero, true, 0x08000000, IntPtr.Zero, IntPtr.Zero, ref si, out pi)) - { - uint ret = WaitForSingleObject(pi.hProcess, 2000); //wait for the child process exit. - if (ret == 0) - { - byte[] title = new byte[10]; - uint reads = 0; - CloseHandle(write); - err = ReadFile(read, title, 10, out reads, IntPtr.Zero); - string result = System.Text.Encoding.UTF8.GetString(title).Replace("\0", "").Replace("\r", "").Replace("\n", ""); - - int ProcessId; - int.TryParse(result, out ProcessId); - return ProcessId; - } - } - CloseHandle(read2); - CloseHandle(write2); - CloseHandle(read); - - return 0; - } - public static bool SendToast(string title, string content) + public static bool CreateHelper() { si = new STARTUPINFO(); IntPtr hToken; bool err = WTSQueryUserToken(WTSGetActiveConsoleSessionId(), out hToken); - string cmdLine = $"-t \"{title}\" \"{content}\""; - if (CreateProcessAsUser(hToken, ControllerService.CurrentPathClient, $@"""{ControllerService.CurrentPathClient}"" {cmdLine}", IntPtr.Zero, IntPtr.Zero, true, 0x08000000, IntPtr.Zero, IntPtr.Zero, ref si, out pi)) + string cmdLine = ""; + if (CreateProcessAsUser(hToken, ControllerService.CurrentPathHelper, $@"""{ControllerService.CurrentPathHelper}"" {cmdLine}", IntPtr.Zero, IntPtr.Zero, true, 0x08000000, IntPtr.Zero, IntPtr.Zero, ref si, out pi)) { uint ret = WaitForSingleObject(pi.hProcess, 2000); //wait for the child process exit. if (ret == 0) @@ -187,6 +138,15 @@ public static byte NormalizeInput(short input) public class Utils { + public static string Between(string STR, string FirstString, string LastString) + { + string FinalString; + int Pos1 = STR.IndexOf(FirstString) + FirstString.Length; + int Pos2 = STR.IndexOf(LastString, Pos1); + FinalString = STR.Substring(Pos1, Pos2 - Pos1); + return FinalString; + } + public static string GetMainModuleFilepath(int processId) { string wmiQueryString = "SELECT ProcessId, ExecutablePath FROM Win32_Process WHERE ProcessId = " + processId; diff --git a/ControllerService/ControllerService.cs b/ControllerService/ControllerService.cs index e9b1d755a..8ac0f8385 100644 --- a/ControllerService/ControllerService.cs +++ b/ControllerService/ControllerService.cs @@ -11,7 +11,6 @@ using System.Threading; using System.Threading.Tasks; using System.Timers; -using static ControllerService.ControllerClient; using Timer = System.Timers.Timer; namespace ControllerService @@ -19,19 +18,19 @@ namespace ControllerService public class ControllerService : IHostedService { // controllers vars - private static XInputController PhysicalController; - private static IDualShock4Controller VirtualController; - private static XInputGirometer Gyrometer; - private static XInputAccelerometer Accelerometer; - private static DS4Touch DS4Touch; + public XInputController PhysicalController; + private IDualShock4Controller VirtualController; + private XInputGirometer Gyrometer; + private XInputAccelerometer Accelerometer; + + private static PipeServer PipeServer; private static DSUServer DSUServer; public static HidHide Hidder; - public static string CurrentPath, CurrentPathCli, CurrentPathProfiles, CurrentPathClient, CurrentPathDep; + public static string CurrentPath, CurrentPathCli, CurrentPathProfiles, CurrentPathHelper, CurrentPathDep; - private static int CurrenthProcess; - private static Timer UpdateMonitor; + private static Timer MonitorTimer; public static ProfileManager CurrentManager; public static Assembly CurrentAssembly; @@ -51,7 +50,7 @@ public ControllerService(ILogger logger) CurrentPath = AppDomain.CurrentDomain.BaseDirectory; CurrentPathCli = @"C:\Program Files\Nefarius Software Solutions e.U\HidHideCLI\HidHideCLI.exe"; CurrentPathProfiles = Path.Combine(CurrentPath, "profiles"); - CurrentPathClient = Path.Combine(CurrentPath, "ControllerServiceClient.exe"); + CurrentPathHelper = Path.Combine(CurrentPath, "ControllerHelper.exe"); CurrentPathDep = Path.Combine(CurrentPath, "dependencies"); // initialize log @@ -63,12 +62,15 @@ public ControllerService(ILogger logger) throw new InvalidOperationException(); } - if (!File.Exists(CurrentPathClient)) + if (!File.Exists(CurrentPathHelper)) { - logger.LogError("CurrentPathClient is missing. Application will stop."); + logger.LogError("Controller Helper is missing. Application will stop."); throw new InvalidOperationException(); } + // initialize PipeServer and PipeClient + PipeServer = new PipeServer("ControllerService", this, logger); + // initialize HidHide Hidder = new HidHide(CurrentPathCli, logger); Hidder.RegisterApplication(Process.GetCurrentProcess().MainModule.FileName); @@ -120,65 +122,67 @@ public ControllerService(ILogger logger) if (Accelerometer.sensor == null) logger.LogWarning("No Accelerometer detected."); - // initialize DS4Touch - DS4Touch = new DS4Touch(); - // initialize DSUClient - DSUServer = new DSUServer(); - - // monitor processes and settings - UpdateMonitor = new Timer(1000) { Enabled = false, AutoReset = true }; - UpdateMonitor.Elapsed += MonitorProcess; + DSUServer = new DSUServer(logger); - SendToast("DualShock 4 Controller", "Virtual device is now connected"); + // monitors processes and settings + MonitorTimer = new Timer(1000) { Enabled = false, AutoReset = true }; + MonitorTimer.Elapsed += MonitorHelper; } - private void MonitorProcess(object sender, ElapsedEventArgs e) + public void UpdateProcess(int ProcessId) { - int ProcessId = GetProcessIdByPath(); - if (ProcessId != CurrenthProcess) + try { - try + Process CurrentProcess = Process.GetProcessById(ProcessId); + string ProcessPath = Utils.GetMainModuleFilepath(ProcessId); + string ProcessName = Path.GetFileName(ProcessPath); + + if (CurrentManager.profiles.ContainsKey(ProcessName)) { - Process CurrentProcess = Process.GetProcessById(ProcessId); - string ProcessPath = Utils.GetMainModuleFilepath(ProcessId); - string ProcessName = Path.GetFileName(ProcessPath); - - if (CurrentManager.profiles.ContainsKey(ProcessName)) - { - // muting process - Profile CurrentProfile = CurrentManager.profiles[ProcessName]; - PhysicalController.muted = CurrentProfile.whitelisted; - PhysicalController.accelerometer.multiplier = CurrentProfile.accelerometer; - PhysicalController.gyrometer.multiplier = CurrentProfile.gyrometer; - logger.LogInformation($"Profile {CurrentProfile.name} applied."); - } - else - { - PhysicalController.muted = false; - PhysicalController.accelerometer.multiplier = 1.0f; - PhysicalController.gyrometer.multiplier = 1.0f; - } + // muting process + Profile CurrentProfile = CurrentManager.profiles[ProcessName]; + PhysicalController.muted = CurrentProfile.whitelisted; + PhysicalController.accelerometer.multiplier = CurrentProfile.accelerometer; + PhysicalController.gyrometer.multiplier = CurrentProfile.gyrometer; + logger.LogInformation($"Profile {CurrentProfile.name} applied."); + } + else + { + PhysicalController.muted = false; + PhysicalController.accelerometer.multiplier = 1.0f; + PhysicalController.gyrometer.multiplier = 1.0f; } - catch (Exception) { } - - CurrenthProcess = ProcessId; } + catch (Exception) { } + } + + private void MonitorHelper(object sender, ElapsedEventArgs e) + { + // check if PipeServer is connected + if (PipeServer.connected) + return; + + // check if Controller Service Helper is running + Process[] pname = Process.GetProcessesByName("ControllerHelper"); + if (pname.Length != 0) + return; + + // start Controller Service Helper + ControllerClient.CreateHelper(); + + logger.LogInformation("Controller Helper has started."); } public async Task StartAsync(CancellationToken cancellationToken) { // start the DSUClient - if (DSUServer != null) - { - logger.LogInformation($"DSU Server has started. Listening to port: {26760}"); - DSUServer.Start(26760); - PhysicalController.SetDSUServer(DSUServer); - } + DSUServer.Start(26760); + PhysicalController.SetDSUServer(DSUServer); - // start monitoring processes - UpdateMonitor.Enabled = true; - UpdateMonitor.Start(); + // start PipeServer + PipeServer.Start(); + MonitorTimer.Start(); // turn on the cloaking Hidder.SetCloaking(true); @@ -188,12 +192,14 @@ public async Task StartAsync(CancellationToken cancellationToken) VirtualController.Connect(); logger.LogInformation($"Virtual {VirtualController.GetType().Name} connected."); - PhysicalController.SetTouch(DS4Touch); PhysicalController.SetVirtualController(VirtualController); PhysicalController.SetGyroscope(Gyrometer); PhysicalController.SetAccelerometer(Accelerometer); logger.LogInformation($"Virtual {VirtualController.GetType().Name} attached to {PhysicalController.GetType().Name} {PhysicalController.index}."); + + // send notification + PipeServer.SendMessage(new PipeMessage { Code = PipeCode.CODE_TOAST, args = new string[] { "DualShock 4 Controller", "Virtual device is now connected" } }); } public Task StopAsync(CancellationToken cancellationToken) @@ -204,6 +210,9 @@ public Task StopAsync(CancellationToken cancellationToken) { VirtualController.Disconnect(); logger.LogInformation($"Virtual {VirtualController.GetType().Name} disconnected."); + + // send notification + PipeServer.SendMessage(new PipeMessage { Code = PipeCode.CODE_TOAST, args = new string[] { "DualShock 4 Controller", "Virtual device is now disconnected" } }); } } catch (Exception) { } @@ -215,16 +224,15 @@ public Task StopAsync(CancellationToken cancellationToken) } if (Hidder != null) + { Hidder.SetCloaking(false); + logger.LogInformation($"Uncloaking {PhysicalController.GetType().Name}"); + } - if (UpdateMonitor.Enabled) - UpdateMonitor.Stop(); - - DS4Touch.Stop(); - - logger.LogInformation($"Uncloaking {PhysicalController.GetType().Name}"); + if (MonitorTimer.Enabled) + MonitorTimer.Stop(); - SendToast("DualShock 4 Controller", "Virtual device is now disconnected"); + PipeServer.Stop(); return Task.CompletedTask; } diff --git a/ControllerService/ControllerService.csproj b/ControllerService/ControllerService.csproj index 91c9ca320..0ec7c4dc8 100644 --- a/ControllerService/ControllerService.csproj +++ b/ControllerService/ControllerService.csproj @@ -80,8 +80,8 @@ all - + diff --git a/ControllerService/DS4Touch.cs b/ControllerService/DS4Touch.cs index 65ceed8b6..17e5d91b0 100644 --- a/ControllerService/DS4Touch.cs +++ b/ControllerService/DS4Touch.cs @@ -1,23 +1,9 @@ -using Gma.System.MouseKeyHook; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Timers; -using System.Windows.Forms; -using System.Timers; -using Timer = System.Timers.Timer; +using System.Windows.Forms; namespace ControllerService { public class DS4Touch { - private IKeyboardMouseEvents m_Events; - private Thread m_Hook; - private Timer m_Timer; - private float RatioWidth; private float RatioHeight; @@ -53,30 +39,9 @@ public DS4Touch() // default values TrackPadTouch0.RawTrackingNum = TOUCH0_ID; TrackPadTouch1.RawTrackingNum = TOUCH1_ID; - - // send MouseUp after 50ms (needed ?) - m_Timer = new Timer() { Enabled = false, Interval = 50, AutoReset = false }; - m_Timer.Elapsed += SendMouseUp; - - m_Hook = new Thread(Subscribe) { IsBackground = true }; - m_Hook.Start(); - } - - private void Subscribe() - { - m_Events = Hook.GlobalEvents(); - m_Events.MouseMoveExt += OnMouseMove; - m_Events.MouseDownExt += OnMouseDown; - m_Events.MouseUpExt += OnMouseUp; - Application.Run(); } - private void OnMouseUp(object sender, MouseEventExtArgs e) - { - m_Timer.Start(); - } - - private void SendMouseUp(object sender, ElapsedEventArgs e) + public void OnMouseUp() { TouchDown = false; @@ -87,10 +52,9 @@ private void SendMouseUp(object sender, ElapsedEventArgs e) TouchPacketCounter++; } - private void OnMouseDown(object sender, MouseEventExtArgs e) + public void OnMouseDown() { TouchDown = true; - m_Timer.Stop(); TrackPadTouch0.RawTrackingNum = TOUCH0_ID; TrackPadTouch0.X = TouchX; @@ -101,10 +65,10 @@ private void OnMouseDown(object sender, MouseEventExtArgs e) TrackPadTouch1.Y = TouchY; } - private void OnMouseMove(object sender, MouseEventExtArgs e) + public void OnMouseMove(short X, short Y) { - TouchX = (short)(e.X * RatioWidth); - TouchY = (short)(e.Y * RatioHeight); + TouchX = (short)(X * RatioWidth); + TouchY = (short)(Y * RatioHeight); if (!TouchDown) return; @@ -123,11 +87,5 @@ private void OnMouseMove(object sender, MouseEventExtArgs e) TouchPacketCounter++; } - - internal void Stop() - { - m_Events.Dispose(); - m_Hook = null; - } } } diff --git a/ControllerService/DSUServer.cs b/ControllerService/DSUServer.cs index f80dd8682..458e4e06c 100644 --- a/ControllerService/DSUServer.cs +++ b/ControllerService/DSUServer.cs @@ -1,4 +1,5 @@ using Force.Crc32; +using Microsoft.Extensions.Logging; using SharpDX.XInput; using System; using System.Collections.Generic; @@ -95,8 +96,12 @@ void GetPadDetailForIdx(int padIdx, ref DualShockPadMeta meta) meta = padMeta; } - public DSUServer() + private readonly ILogger logger; + + public DSUServer(ILogger logger) { + this.logger = logger; + PadMacAddress = new PhysicalAddress(new byte[] { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }); portInfoGet = GetPadDetailForIdx; @@ -485,6 +490,8 @@ public void Start(int port) BatteryTimer.Enabled = true; BatteryTimer.Start(); + + logger.LogInformation($"DSU Server has started. Listening to port: {26760}"); } public void Stop() diff --git a/ControllerService/HidHide.cs b/ControllerService/HidHide.cs index bba4ba7e8..9118d3e90 100644 --- a/ControllerService/HidHide.cs +++ b/ControllerService/HidHide.cs @@ -48,7 +48,7 @@ public List GetRegisteredApplications() break; // --app-reg \"C:\\Program Files\\Nefarius Software Solutions e.U\\HidHideCLI\\HidHideCLI.exe\" - string path = ControllerClient.Between(standard_output, "--app-reg \"", "\""); + string path = Utils.Between(standard_output, "--app-reg \"", "\""); whitelist.Add(path); } return whitelist; @@ -91,7 +91,7 @@ public void GetDevices() } catch (Exception) { - string tempString = ControllerClient.Between(jsonString, "symbolicLink", ","); + string tempString = Utils.Between(jsonString, "symbolicLink", ","); root = new RootDevice { friendlyName = "Unknown", @@ -130,8 +130,8 @@ internal void HideDevices() { foreach (Device d in devices.Where(a => a.gamingDevice)) { - string VID = ControllerClient.Between(d.deviceInstancePath.ToLower(), "vid_", "&"); - string PID = ControllerClient.Between(d.deviceInstancePath.ToLower(), "pid_", "&"); + string VID = Utils.Between(d.deviceInstancePath.ToLower(), "vid_", "&"); + string PID = Utils.Between(d.deviceInstancePath.ToLower(), "pid_", "&"); string query = $"SELECT * FROM Win32_PnPEntity WHERE DeviceID LIKE \"%VID_{VID}&PID_{PID}%\""; diff --git a/ControllerService/PipeServer.cs b/ControllerService/PipeServer.cs new file mode 100644 index 000000000..832bc28cd --- /dev/null +++ b/ControllerService/PipeServer.cs @@ -0,0 +1,143 @@ +using Microsoft.Extensions.Logging; +using NamedPipeWrapper; +using System; +using System.Collections.Generic; +using System.IO.Pipes; +using System.Security.AccessControl; +using System.Timers; +using Timer = System.Timers.Timer; + +namespace ControllerService +{ + [Serializable] + public class PipeMessage + { + public PipeCode Code; + public string[] args = new string[] { }; + } + + public enum PipeCode + { + CODE_HELLO = 0, + CODE_PROCESS = 1, + CODE_TOAST = 2, + CODE_CURSOR_UP = 3, + CODE_CURSOR_DOWN = 4, + CODE_CURSOR_MOVE = 5 + } + + public class PipeServer + { + private readonly NamedPipeServer server; + private readonly ILogger logger; + private readonly ControllerService service; + + private List m_queue; + private Timer m_timer; + + public bool connected; + + public PipeServer(string pipeName, ControllerService service, ILogger logger) + { + this.service = service; + this.logger = logger; + + m_queue = new List(); + + // monitors processes and settings + m_timer = new Timer(1000) { Enabled = false, AutoReset = true }; + m_timer.Elapsed += SendMessageQueue; + + PipeSecurity ps = new PipeSecurity(); + ps.AddAccessRule(new PipeAccessRule("Users", PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, AccessControlType.Allow)); + ps.AddAccessRule(new PipeAccessRule("SYSTEM", PipeAccessRights.FullControl, AccessControlType.Allow)); + + server = new NamedPipeServer(pipeName, ps); + server.ClientConnected += OnClientConnected; + server.ClientDisconnected += OnClientDisconnected; + server.ClientMessage += OnClientMessage; + server.Error += OnError; + } + + public void Start() + { + if (server == null) + return; + + server.Start(); + + logger.LogInformation($"Pipe Server has started."); + } + + public void Stop() + { + if (server == null) + return; + + server.Stop(); + } + + private void OnClientConnected(NamedPipeConnection connection) + { + connected = true; + logger.LogInformation("Client {0} is now connected!", connection.Id); + connection.PushMessage(new PipeMessage { Code = PipeCode.CODE_HELLO }); + } + + private void OnClientDisconnected(NamedPipeConnection connection) + { + connected = false; + logger.LogInformation("Client {0} disconnected", connection.Id); + } + + private void OnClientMessage(NamedPipeConnection connection, PipeMessage message) + { + logger.LogDebug("Client {0} opcode: {1} says: {2}", connection.Id, message.Code, string.Join(" ", message.args)); + + switch (message.Code) + { + case PipeCode.CODE_PROCESS: + service.UpdateProcess(int.Parse(message.args[0])); + break; + case PipeCode.CODE_CURSOR_UP: + service.PhysicalController.touch.OnMouseUp(); + break; + case PipeCode.CODE_CURSOR_DOWN: + service.PhysicalController.touch.OnMouseDown(); + break; + case PipeCode.CODE_CURSOR_MOVE: + service.PhysicalController.touch.OnMouseMove(short.Parse(message.args[0]), short.Parse(message.args[1])); + break; + } + } + + private void OnError(Exception exception) + { + logger.LogError("ERROR: {0}", exception); + } + + public void SendMessage(PipeMessage message) + { + if (!connected) + { + m_queue.Add(message); + m_timer.Start(); + return; + } + + server.PushMessage(message); + } + + private void SendMessageQueue(object sender, ElapsedEventArgs e) + { + if (!connected) + return; + + foreach (PipeMessage m in m_queue) + server.PushMessage(m); + + m_queue.Clear(); + m_timer.Stop(); + } + } +} diff --git a/ControllerService/XInputController.cs b/ControllerService/XInputController.cs index 7d619dbc8..014f8ead3 100644 --- a/ControllerService/XInputController.cs +++ b/ControllerService/XInputController.cs @@ -1,7 +1,6 @@ using Nefarius.ViGEm.Client.Targets; using Nefarius.ViGEm.Client.Targets.DualShock4; using SharpDX.XInput; -using System; using System.Diagnostics; using System.Numerics; using System.Timers; @@ -63,13 +62,11 @@ public XInputController(UserIndex _idx) // initialize timers UpdateTimer = new Timer(10) { Enabled = false, AutoReset = true }; UpdateTimer.Elapsed += UpdateController; - } - public void SetTouch(DS4Touch _touch) - { - touch = _touch; + // initialize touch + touch = new DS4Touch(); } - + public void SetVirtualController(IDualShock4Controller _controller) { vcontroller = _controller; @@ -215,12 +212,6 @@ private unsafe void UpdateController(object sender, ElapsedEventArgs e) (byte)(byte.MaxValue - ControllerHelper.NormalizeInput(gamepad.RightThumbY)); } - /* - 0x00: No data for T-PAD[1] - 0x01: Set data for 2 current touches - 0x02: set data for previous touches at [44-51] - */ - unchecked { outDS4Report.bTouchPacketsN = 0x01; diff --git a/ControllerService/install.cmd b/ControllerService/install.cmd index 0ae27e8b2..1ff91a8bd 100644 --- a/ControllerService/install.cmd +++ b/ControllerService/install.cmd @@ -21,7 +21,7 @@ sc.exe delete "ControllerService" :MISSING echo Installing Controller Service echo. -sc.exe create "ControllerService" binpath= "%cd%\ControllerService.exe" start= auto DisplayName= "Controller Service" +sc.exe create "ControllerService" binpath= "%cd%\ControllerService.exe" start= "auto" DisplayName= "Controller Service" sc.exe description "ControllerService" "Provides gyroscope and accelerometer support to the AYA NEO 2020, 2021 models through a virtual DualShock 4 controller. If the service is enabled, embedded controller will be cloaked to applications outside the whitelist. If the service is disabled, embedded controller will be uncloaked and virtual DualShock 4 controller disabled." echo Starting Controller Service diff --git a/ControllerServiceClient/App.config b/ControllerServiceClient/App.config deleted file mode 100644 index 731f6de6c..000000000 --- a/ControllerServiceClient/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/ControllerServiceClient/ControllerServiceClient.csproj b/ControllerServiceClient/ControllerServiceClient.csproj deleted file mode 100644 index b7dd836ea..000000000 --- a/ControllerServiceClient/ControllerServiceClient.csproj +++ /dev/null @@ -1,44 +0,0 @@ - - - {15236FBC-7E2A-4BE9-9A0E-9F4A75348892} - Exe - net461 - false - false - true - ControllerServiceClient - ControllerServiceClient - Copyright © 2021 - $(SolutionDir)bin\ - - - full - - - pdbonly - - - - - - - - - - Always - - - - - all - - - all - - - - - - - - \ No newline at end of file diff --git a/ControllerServiceClient/Program.cs b/ControllerServiceClient/Program.cs deleted file mode 100644 index 853d7b02c..000000000 --- a/ControllerServiceClient/Program.cs +++ /dev/null @@ -1,77 +0,0 @@ -using Microsoft.Toolkit.Uwp.Notifications; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text.RegularExpressions; - -namespace ControllerServiceClient -{ - class Program - { - [DllImport("User32.dll")] - static extern IntPtr GetForegroundWindow(); - [DllImport("user32.dll", SetLastError = true)] - static extern uint GetWindowThreadProcessId(IntPtr hWnd, out IntPtr lpdwProcessId); - - static void Main(string[] args) - { - var re = new Regex("(?<=\")[^\"]*(?=\")|[^\" ]+"); - var strings = re.Matches(args[0]).Cast().Select(m => m.Value).ToArray(); - - if (args.Length == 0) - { - Console.WriteLine("Invalid args"); - return; - } - - List args2 = new List(); - if (args.Length > 1) - args2.AddRange(args); - else - args2.AddRange(strings.Where(a => a != " ")); - - var command = args2[0]; - - switch (command) - { - case "-g": // get foreground process id - PushProcessId(); - break; - case "-t" when args2.Count == 3: - SendToast(args2[1], args2[2]); // send toast notification - break; - default: - Console.WriteLine("Invalid command"); - break; - } - return; - } - - static void SendToast(string title, string content) - { - string url = "file:///" + AppDomain.CurrentDomain.BaseDirectory + "Toast.png"; - var uri = new Uri(url); - - new ToastContentBuilder() - .AddText(title) - .AddText(content) - // .AddInlineImage(uri) - .AddAppLogoOverride(uri, ToastGenericAppLogoCrop.Circle) - .SetToastDuration(ToastDuration.Short) - .Show(); - } - - static void PushProcessId() - { - IntPtr hWnd = GetForegroundWindow(); - IntPtr processId; - - if (GetWindowThreadProcessId(hWnd, out processId) == 0) - return; - - Console.WriteLine(processId); - - } - } -} diff --git a/ControllerServiceClient/Properties/AssemblyInfo.cs b/ControllerServiceClient/Properties/AssemblyInfo.cs deleted file mode 100644 index 3abd1e3cf..000000000 --- a/ControllerServiceClient/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Runtime.InteropServices; - -// L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly -// aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de -// COM, affectez la valeur true à l'attribut ComVisible sur ce type. -[assembly: ComVisible(false)] - -// Le GUID suivant est pour l'ID de la typelib si ce projet est exposé à COM -[assembly: Guid("15236fbc-7e2a-4be9-9a0e-9f4a75348892")]