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")]