diff --git a/ControllerCommon/ControllerCommon.csproj b/ControllerCommon/ControllerCommon.csproj
index 7b92e6012..4576200dc 100644
--- a/ControllerCommon/ControllerCommon.csproj
+++ b/ControllerCommon/ControllerCommon.csproj
@@ -14,16 +14,16 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
+
@@ -37,9 +37,9 @@
-
-
-
+
+
+
@@ -47,6 +47,9 @@
..\Resources\Nefarius.Utilities.DeviceManagement.dll
+
+ ..\Resources\neptune-hidapi.net.dll
+
@@ -64,4 +67,16 @@
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+
diff --git a/ControllerCommon/ControllerEx.cs b/ControllerCommon/ControllerEx.cs
deleted file mode 100644
index dbc352681..000000000
--- a/ControllerCommon/ControllerEx.cs
+++ /dev/null
@@ -1,163 +0,0 @@
-using Nefarius.Utilities.DeviceManagement.PnP;
-using PInvoke;
-using SharpDX.XInput;
-using System;
-using System.Collections.Generic;
-using System.Runtime.InteropServices;
-using System.Timers;
-using static ControllerCommon.Utils.DeviceUtils;
-
-namespace ControllerCommon
-{
- public struct PnPDeviceEx
- {
- public int deviceIndex;
- public PnPDevice deviceUSB;
- public PnPDevice deviceHID;
- public string path;
- public bool isVirtual;
- public DateTimeOffset arrivalDate;
- }
-
- public class ControllerEx
- {
- private PnPDeviceEx deviceEx;
- public Controller Controller;
- public string Manufacturer, DeviceDesc;
- public UserIndex UserIndex;
-
- private XInputCapabilitiesEx CapabilitiesEx;
-
- public bool isVirtual;
- public string ProductId, VendorId, XID;
-
- public string deviceInstancePath = "";
- public string baseContainerDeviceInstancePath = "";
-
- private Vibration IdentifyVibration = new Vibration() { LeftMotorSpeed = ushort.MaxValue, RightMotorSpeed = ushort.MaxValue };
- private Timer IdentifyTimer;
-
- [DllImport("hid.dll", EntryPoint = "HidD_GetAttributes")]
- static internal extern bool HidD_GetAttributes(IntPtr hidDeviceObject, ref Attributes attributes);
-
- [StructLayout(LayoutKind.Sequential)]
- public struct Attributes
- {
- public int Size;
- public ushort VendorID;
- public ushort ProductID;
- public short VersionNumber;
- }
-
- public ControllerEx(UserIndex index)
- {
- this.Controller = new Controller(index);
- this.UserIndex = index;
-
- // initialize timers
- IdentifyTimer = new Timer(200) { AutoReset = false };
- IdentifyTimer.Elapsed += IdentifyTimer_Tick;
-
- // pull data from xinput
- CapabilitiesEx = new XInputCapabilitiesEx();
-
- if (XInputGetCapabilitiesEx(1, (int)UserIndex, 0, ref CapabilitiesEx) == 0)
- {
- ProductId = CapabilitiesEx.ProductId.ToString("X4");
- VendorId = CapabilitiesEx.VendorId.ToString("X4");
- }
- }
-
- public ControllerEx(UserIndex index, ref List devices) : this(index)
- {
- if (ProductId is null || VendorId is null)
- return;
-
- foreach (PnPDeviceEx deviceEx in devices)
- {
- // get attributes
- Attributes device_attributes = new Attributes();
- GetHidAttributes(deviceEx.path, out device_attributes);
-
- if (device_attributes.ProductID != CapabilitiesEx.ProductId || device_attributes.VendorID != CapabilitiesEx.VendorId)
- continue;
-
- // update current device
- this.deviceEx = deviceEx;
- isVirtual = deviceEx.isVirtual;
-
- // update HID
- deviceInstancePath = deviceEx.deviceUSB.DeviceId;
- baseContainerDeviceInstancePath = deviceEx.deviceHID.DeviceId;
-
- DeviceDesc = deviceEx.deviceUSB.GetProperty(DevicePropertyKey.Device_DeviceDesc);
- Manufacturer = deviceEx.deviceUSB.GetProperty(DevicePropertyKey.Device_Manufacturer);
-
- devices.Remove(deviceEx);
- break;
- }
- }
-
- private bool GetHidAttributes(string path, out Attributes attributes)
- {
- attributes = new Attributes();
-
- using var handle = Kernel32.CreateFile(path,
- Kernel32.ACCESS_MASK.GenericRight.GENERIC_READ |
- Kernel32.ACCESS_MASK.GenericRight.GENERIC_WRITE,
- Kernel32.FileShare.FILE_SHARE_READ | Kernel32.FileShare.FILE_SHARE_WRITE,
- IntPtr.Zero, Kernel32.CreationDisposition.OPEN_EXISTING,
- Kernel32.CreateFileFlags.FILE_ATTRIBUTE_NORMAL
- | Kernel32.CreateFileFlags.FILE_FLAG_NO_BUFFERING
- | Kernel32.CreateFileFlags.FILE_FLAG_WRITE_THROUGH,
- Kernel32.SafeObjectHandle.Null
- );
-
- var ret = HidD_GetAttributes(handle.DangerousGetHandle(), ref attributes);
-
- if (!ret) return false;
-
- return true;
- }
-
- public override string ToString()
- {
- return DeviceDesc;
- }
-
- public State GetState()
- {
- return Controller.GetState();
- }
-
- public bool IsConnected()
- {
- return Controller.IsConnected;
- }
-
- public ushort GetPID()
- {
- return CapabilitiesEx.ProductId;
- }
-
- public ushort GetVID()
- {
- return CapabilitiesEx.VendorId;
- }
-
- public void Identify()
- {
- if (!Controller.IsConnected)
- return;
-
- Controller.SetVibration(IdentifyVibration);
- IdentifyTimer.Stop();
- IdentifyTimer.Start();
- }
-
- private void IdentifyTimer_Tick(object sender, EventArgs e)
- {
- Controller.SetVibration(new Vibration());
- }
- }
-}
diff --git a/ControllerCommon/Controllers/DInputController.cs b/ControllerCommon/Controllers/DInputController.cs
new file mode 100644
index 000000000..8c863595e
--- /dev/null
+++ b/ControllerCommon/Controllers/DInputController.cs
@@ -0,0 +1,65 @@
+using ControllerCommon.Managers;
+using SharpDX.DirectInput;
+using SharpDX.XInput;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+
+namespace ControllerCommon.Controllers
+{
+ public class DInputController : IController
+ {
+ protected Joystick Controller;
+ protected JoystickState State = new();
+ protected JoystickState prevState = new();
+
+ public DInputController(Joystick joystick, PnPDetails details)
+ {
+ Controller = joystick;
+ UserIndex = joystick.Properties.JoystickId;
+
+ Details = details;
+ Details.isHooked = true;
+
+ // Set BufferSize in order to use buffered data.
+ joystick.Properties.BufferSize = 128;
+ }
+
+ public override string ToString()
+ {
+ return Controller.Information.ProductName;
+ }
+
+ public override void UpdateReport()
+ {
+ // update states
+ prevState = State;
+
+ base.UpdateReport();
+ }
+
+ public override bool IsConnected()
+ {
+ return (bool)(!Controller?.IsDisposed);
+ }
+
+ public override void Plug()
+ {
+ // Acquire the joystick
+ Controller.Acquire();
+
+ base.Plug();
+ }
+
+ public override void Unplug()
+ {
+ // Acquire the joystick
+ Controller.Unacquire();
+
+ base.Unplug();
+ }
+ }
+}
diff --git a/ControllerCommon/Controllers/DS4Controller.cs b/ControllerCommon/Controllers/DS4Controller.cs
new file mode 100644
index 000000000..c5e5abe17
--- /dev/null
+++ b/ControllerCommon/Controllers/DS4Controller.cs
@@ -0,0 +1,139 @@
+using ControllerCommon.Managers;
+using SharpDX.DirectInput;
+using SharpDX.XInput;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+
+namespace ControllerCommon.Controllers
+{
+ public class DS4Controller : DInputController
+ {
+ public DS4Controller(Joystick joystick, PnPDetails details) : base (joystick, details)
+ {
+ if (!IsConnected())
+ return;
+
+ UpdateTimer.Tick += (sender, e) => UpdateReport();
+ }
+
+ public override string ToString()
+ {
+ return Controller.Information.ProductName;
+ }
+
+ public override void UpdateReport()
+ {
+ // skip if controller isn't connected
+ if (!IsConnected())
+ return;
+
+ // Poll events from joystick
+ Controller.Poll();
+
+ // update gamepad state
+ State = Controller.GetCurrentState();
+
+ if (prevState.GetHashCode() == State.GetHashCode() && prevInjectedButtons == InjectedButtons)
+ return;
+
+ Inputs.Buttons = InjectedButtons;
+
+ // todo: implement loop
+ if (State.Buttons[0])
+ Inputs.Buttons |= ControllerButtonFlags.B3;
+ if (State.Buttons[1])
+ Inputs.Buttons |= ControllerButtonFlags.B1;
+ if (State.Buttons[2])
+ Inputs.Buttons |= ControllerButtonFlags.B2;
+ if (State.Buttons[3])
+ Inputs.Buttons |= ControllerButtonFlags.B4;
+
+ if (State.Buttons[8])
+ Inputs.Buttons |= ControllerButtonFlags.Back;
+ if (State.Buttons[9])
+ Inputs.Buttons |= ControllerButtonFlags.Start;
+
+ if (State.Buttons[6])
+ Inputs.Buttons |= ControllerButtonFlags.LeftTrigger;
+ if (State.Buttons[7])
+ Inputs.Buttons |= ControllerButtonFlags.RightTrigger;
+
+ if (State.Buttons[10])
+ Inputs.Buttons |= ControllerButtonFlags.LeftThumb;
+ if (State.Buttons[11])
+ Inputs.Buttons |= ControllerButtonFlags.RightThumb;
+
+ if (State.Buttons[4])
+ Inputs.Buttons |= ControllerButtonFlags.LeftShoulder;
+ if (State.Buttons[5])
+ Inputs.Buttons |= ControllerButtonFlags.RightShoulder;
+
+ if (State.Buttons[12])
+ Inputs.Buttons |= ControllerButtonFlags.Special;
+ if (State.Buttons[13]) // TouchpadClick
+ Inputs.Buttons |= ControllerButtonFlags.Special;
+
+ switch(State.PointOfViewControllers[0])
+ {
+ case 0:
+ Inputs.Buttons |= ControllerButtonFlags.DPadUp;
+ break;
+ case 4500:
+ Inputs.Buttons |= ControllerButtonFlags.DPadUp;
+ Inputs.Buttons |= ControllerButtonFlags.DPadRight;
+ break;
+ case 9000:
+ Inputs.Buttons |= ControllerButtonFlags.DPadRight;
+ break;
+ case 13500:
+ Inputs.Buttons |= ControllerButtonFlags.DPadRight;
+ Inputs.Buttons |= ControllerButtonFlags.DPadDown;
+ break;
+ case 18000:
+ Inputs.Buttons |= ControllerButtonFlags.DPadDown;
+ break;
+ case 22500:
+ Inputs.Buttons |= ControllerButtonFlags.DPadLeft;
+ Inputs.Buttons |= ControllerButtonFlags.DPadDown;
+ break;
+ case 27000:
+ Inputs.Buttons |= ControllerButtonFlags.DPadLeft;
+ break;
+ case 31500:
+ Inputs.Buttons |= ControllerButtonFlags.DPadUp;
+ Inputs.Buttons |= ControllerButtonFlags.DPadLeft;
+ break;
+ }
+
+ Inputs.RightTrigger = State.RotationY * byte.MaxValue / ushort.MaxValue;
+ Inputs.LeftTrigger = State.RotationX * byte.MaxValue / ushort.MaxValue;
+
+ Inputs.LeftThumbX = Math.Clamp(State.X - short.MaxValue, short.MinValue, short.MaxValue);
+ Inputs.LeftThumbY = Math.Clamp(-State.Y + short.MaxValue, short.MinValue, short.MaxValue);
+
+ Inputs.RightThumbX = Math.Clamp(State.Z - short.MaxValue, short.MinValue, short.MaxValue);
+ Inputs.RightThumbY = Math.Clamp(-State.RotationZ + short.MaxValue, short.MinValue, short.MaxValue);
+
+ base.UpdateReport();
+ }
+
+ public override bool IsConnected()
+ {
+ return (bool)(!Controller?.IsDisposed);
+ }
+
+ public override void Plug()
+ {
+ base.Plug();
+ }
+
+ public override void Unplug()
+ {
+ base.Unplug();
+ }
+ }
+}
diff --git a/ControllerCommon/Controllers/IController.cs b/ControllerCommon/Controllers/IController.cs
new file mode 100644
index 000000000..6bdeb0107
--- /dev/null
+++ b/ControllerCommon/Controllers/IController.cs
@@ -0,0 +1,175 @@
+using ControllerCommon.Managers;
+using PrecisionTiming;
+using System;
+
+namespace ControllerCommon.Controllers
+{
+ [Flags]
+ public enum ControllerButtonFlags : ulong
+ {
+ None = 0,
+
+ DPadUp = 1,
+ DPadDown = 2,
+ DPadLeft = 4,
+ DPadRight = 8,
+
+ Start = 16,
+ Back = 32,
+
+ LeftThumb = 64,
+ RightThumb = 128,
+
+ LeftShoulder = 256,
+ RightShoulder = 512,
+
+ LeftTrigger = 1024,
+ RightTrigger = 2048,
+
+ B1 = 4096,
+ B2 = 8192,
+ B3 = 16384,
+ B4 = 32768,
+ B5 = 65536,
+ B6 = 131072,
+ B7 = 262144,
+ B8 = 524288,
+
+ LStickUp = 1048576,
+ LStickDown = 2097152,
+ LStickLeft = 4194304,
+ LStickRight = 8388608,
+
+ RStickUp = 16777216,
+ RStickDown = 33554432,
+ RStickLeft = 67108864,
+ RStickRight = 134217728,
+
+ Special = 268435456,
+ OEM1 = 536870912,
+ OEM2 = 1073741824,
+ OEM3 = 2147483648,
+ OEM4 = 4294967296,
+ OEM5 = 8589934592
+ }
+
+ [Serializable]
+ public class ControllerInput
+ {
+ public ControllerButtonFlags Buttons;
+ public float LeftThumbX, LeftThumbY;
+ public float RightThumbX, RightThumbY;
+ public float LeftTrigger;
+ public float RightTrigger;
+ public int Timestamp;
+ }
+
+ public abstract class IController
+ {
+ public ControllerInput Inputs = new();
+
+ public ControllerButtonFlags InjectedButtons;
+ public ControllerButtonFlags prevInjectedButtons;
+
+ protected int UserIndex;
+ protected double VibrationStrength = 100.0d;
+
+ public const short UPDATE_INTERVAL = 5;
+
+ protected PnPDetails Details;
+ protected PrecisionTimer UpdateTimer;
+
+ public event UpdatedEventHandler Updated;
+ public delegate void UpdatedEventHandler(ControllerInput Inputs);
+
+ protected IController()
+ {
+ UpdateTimer = new PrecisionTimer();
+ UpdateTimer.SetInterval(UPDATE_INTERVAL);
+ UpdateTimer.SetAutoResetMode(true);
+ }
+
+ public virtual void UpdateReport()
+ {
+ // update states
+ Inputs.Timestamp = Environment.TickCount;
+ prevInjectedButtons = InjectedButtons;
+
+ Updated?.Invoke(Inputs);
+ }
+
+ public bool IsVirtual()
+ {
+ return Details.isVirtual;
+ }
+
+ public bool IsGaming()
+ {
+ return Details.isGaming;
+ }
+
+ public string GetInstancePath()
+ {
+ return Details.deviceInstancePath;
+ }
+
+ public string GetContainerInstancePath()
+ {
+ return Details.baseContainerDeviceInstancePath;
+ }
+
+ public override string ToString()
+ {
+ return Details.DeviceDesc;
+ }
+
+ public void InjectButton(ControllerButtonFlags button, bool IsKeyDown, bool IsKeyUp)
+ {
+ if (button == ControllerButtonFlags.None)
+ return;
+
+ if (IsKeyDown)
+ InjectedButtons |= button;
+ else if (IsKeyUp)
+ InjectedButtons &= ~button;
+
+ LogManager.LogDebug("Injecting {0} (IsKeyDown:{1}) (IsKeyUp:{2}) to {3}", button, IsKeyDown, IsKeyUp, ToString());
+ }
+
+ public void SetVibrationStrength(double value)
+ {
+ VibrationStrength = value;
+ }
+
+ public virtual bool IsConnected()
+ {
+ return false;
+ }
+
+ public virtual async void Rumble()
+ { }
+
+ public virtual void Plug()
+ {
+ InjectedButtons = ControllerButtonFlags.None;
+ UpdateTimer.Start();
+ }
+
+ public virtual void Unplug()
+ {
+ UpdateTimer.Stop();
+ }
+
+ public virtual void Hide()
+ {
+ HidHide.HidePath(Details.deviceInstancePath);
+ HidHide.HidePath(Details.baseContainerDeviceInstancePath);
+ }
+
+ public virtual void Unhide()
+ {
+ HidHide.UnhidePath(Details.deviceInstancePath);
+ HidHide.UnhidePath(Details.baseContainerDeviceInstancePath);
+ }
+ }
+}
diff --git a/ControllerCommon/Controllers/NetpuneController.cs b/ControllerCommon/Controllers/NetpuneController.cs
new file mode 100644
index 000000000..a9acd725a
--- /dev/null
+++ b/ControllerCommon/Controllers/NetpuneController.cs
@@ -0,0 +1,101 @@
+using ControllerCommon.Managers;
+using neptune_hidapi.net;
+using SharpDX.DirectInput;
+using System;
+using System.Threading.Tasks;
+
+namespace ControllerCommon.Controllers
+{
+ public class NetpuneController : IController
+ {
+ private NeptuneController Controller = new();
+ private JoystickState State = new();
+ private JoystickState prevState = new();
+
+ private bool isConnected = false;
+
+ public NetpuneController(PnPDetails details)
+ {
+ Details = details;
+ Details.isHooked = true;
+ }
+
+ public override string ToString()
+ {
+ // localize me
+ return "Steam Deck Controller";
+ }
+
+ public override void UpdateReport()
+ {
+ // skip if controller isn't connected
+ if (!IsConnected())
+ return;
+
+ base.UpdateReport();
+ }
+
+ public override bool IsConnected()
+ {
+ return isConnected;
+ }
+
+ public override async void Rumble()
+ {
+ base.Rumble();
+ }
+
+ public override void Plug()
+ {
+ try
+ {
+ Controller.Open();
+ isConnected = true;
+ }
+ catch (Exception)
+ {
+ return;
+ }
+
+ Controller.OnControllerInputReceived = input => Task.Run(() => OnControllerInputReceived(input));
+
+ PipeClient.ServerMessage += OnServerMessage;
+ base.Plug();
+ }
+
+ private void OnControllerInputReceived(NeptuneControllerInputEventArgs input)
+ {
+ }
+
+ public override void Unplug()
+ {
+ try
+ {
+ Controller.Close();
+ isConnected = false;
+ }
+ catch (Exception)
+ {
+ return;
+ }
+
+ PipeClient.ServerMessage -= OnServerMessage;
+ base.Unplug();
+ }
+
+ private void OnServerMessage(PipeMessage message)
+ {
+ switch (message.code)
+ {
+ case PipeCode.SERVER_VIBRATION:
+ {
+ PipeClientVibration e = (PipeClientVibration)message;
+
+ ushort LeftMotorSpeed = (ushort)((e.LargeMotor * ushort.MaxValue / byte.MaxValue) * VibrationStrength);
+ ushort RightMotorSpeed = (ushort)((e.SmallMotor * ushort.MaxValue / byte.MaxValue) * VibrationStrength);
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/ControllerCommon/Controllers/XInputController.cs b/ControllerCommon/Controllers/XInputController.cs
new file mode 100644
index 000000000..1cf4f585b
--- /dev/null
+++ b/ControllerCommon/Controllers/XInputController.cs
@@ -0,0 +1,306 @@
+using ControllerCommon.Managers;
+using SharpDX.XInput;
+using System;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+
+namespace ControllerCommon.Controllers
+{
+ public class XInputController : IController
+ {
+ [StructLayout(LayoutKind.Explicit)]
+ protected struct XInputGamepad
+ {
+ [MarshalAs(UnmanagedType.I2)]
+ [FieldOffset(0)]
+ public short wButtons;
+
+ [MarshalAs(UnmanagedType.I1)]
+ [FieldOffset(2)]
+ public byte bLeftTrigger;
+
+ [MarshalAs(UnmanagedType.I1)]
+ [FieldOffset(3)]
+ public byte bRightTrigger;
+
+ [MarshalAs(UnmanagedType.I2)]
+ [FieldOffset(4)]
+ public short sThumbLX;
+
+ [MarshalAs(UnmanagedType.I2)]
+ [FieldOffset(6)]
+ public short sThumbLY;
+
+ [MarshalAs(UnmanagedType.I2)]
+ [FieldOffset(8)]
+ public short sThumbRX;
+
+ [MarshalAs(UnmanagedType.I2)]
+ [FieldOffset(10)]
+ public short sThumbRY;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ protected struct XInputVibration
+ {
+ [MarshalAs(UnmanagedType.I2)]
+ public ushort LeftMotorSpeed;
+
+ [MarshalAs(UnmanagedType.I2)]
+ public ushort RightMotorSpeed;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ protected struct XInputCapabilities
+ {
+ [MarshalAs(UnmanagedType.I1)]
+ [FieldOffset(0)]
+ byte Type;
+
+ [MarshalAs(UnmanagedType.I1)]
+ [FieldOffset(1)]
+ public byte SubType;
+
+ [MarshalAs(UnmanagedType.I2)]
+ [FieldOffset(2)]
+ public short Flags;
+
+ [FieldOffset(4)]
+ public XInputGamepad Gamepad;
+
+ [FieldOffset(16)]
+ public XInputVibration Vibration;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ protected struct XInputCapabilitiesEx
+ {
+ public XInputCapabilities Capabilities;
+ [MarshalAs(UnmanagedType.U2)]
+ public ushort VendorId;
+ [MarshalAs(UnmanagedType.U2)]
+ public ushort ProductId;
+ [MarshalAs(UnmanagedType.U2)]
+ public UInt16 REV;
+ [MarshalAs(UnmanagedType.U4)]
+ public UInt32 XID;
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ protected struct XInputStateSecret
+ {
+ public uint eventCount;
+ public XInputStateButtons wButtons;
+ public byte bLeftTrigger;
+ public byte bRightTrigger;
+ public short sThumbLX;
+ public short sThumbLY;
+ public short sThumbRX;
+ public short sThumbRY;
+ }
+
+ [Flags]
+ protected enum XInputStateButtons : ushort
+ {
+ None = 0,
+ Xbox = 1024
+ }
+
+ #region imports
+ [DllImport("xinput1_4.dll", EntryPoint = "#108")]
+ protected static extern int XInputGetCapabilitiesEx
+ (
+ int a1, // [in] unknown, should probably be 1
+ int dwUserIndex, // [in] Index of the gamer associated with the device
+ int dwFlags, // [in] Input flags that identify the device type
+ ref XInputCapabilitiesEx pCapabilities // [out] Receives the capabilities
+ );
+
+ [DllImport("xinput1_3.dll", EntryPoint = "#100")]
+ protected static extern int XInputGetStateSecret13(int playerIndex, out XInputStateSecret struc);
+ [DllImport("xinput1_4.dll", EntryPoint = "#100")]
+ protected static extern int XInputGetStateSecret14(int playerIndex, out XInputStateSecret struc);
+ #endregion
+
+ private Controller Controller;
+ private Gamepad Gamepad;
+ private Gamepad prevGamepad;
+
+ private XInputStateSecret State;
+ private XInputStateSecret prevState;
+
+ private Vibration Vibration = new Vibration() { LeftMotorSpeed = ushort.MaxValue, RightMotorSpeed = ushort.MaxValue };
+
+ public XInputController(int index)
+ {
+ Controller = new Controller((UserIndex)index);
+ UserIndex = index;
+
+ if (!IsConnected())
+ return;
+
+ // pull data from xinput
+ var CapabilitiesEx = new XInputCapabilitiesEx();
+
+ if (XInputGetCapabilitiesEx(1, UserIndex, 0, ref CapabilitiesEx) == 0)
+ {
+ var ProductId = CapabilitiesEx.ProductId.ToString("X4");
+ var VendorId = CapabilitiesEx.VendorId.ToString("X4");
+
+ Details = SystemManager.GetDetails(CapabilitiesEx.VendorId, CapabilitiesEx.ProductId).FirstOrDefault();
+ Details.isHooked = true;
+ }
+
+ UpdateTimer.Tick += (sender, e) => UpdateReport();
+ }
+
+ public override string ToString()
+ {
+ return Details.DeviceDesc;
+ }
+
+ public override void UpdateReport()
+ {
+ // skip if controller isn't connected
+ if (!IsConnected())
+ return;
+
+ // update gamepad state
+ Gamepad = Controller.GetState().Gamepad;
+
+ // update secret state
+ XInputGetStateSecret13(UserIndex, out State);
+
+ if (prevGamepad.GetHashCode() == Gamepad.GetHashCode() && State.wButtons == prevState.wButtons && prevInjectedButtons == InjectedButtons)
+ return;
+
+ Inputs.Buttons = InjectedButtons;
+
+ if (Gamepad.Buttons.HasFlag(GamepadButtonFlags.A))
+ Inputs.Buttons |= ControllerButtonFlags.B1;
+ if (Gamepad.Buttons.HasFlag(GamepadButtonFlags.B))
+ Inputs.Buttons |= ControllerButtonFlags.B2;
+ if (Gamepad.Buttons.HasFlag(GamepadButtonFlags.X))
+ Inputs.Buttons |= ControllerButtonFlags.B3;
+ if (Gamepad.Buttons.HasFlag(GamepadButtonFlags.Y))
+ Inputs.Buttons |= ControllerButtonFlags.B4;
+
+ if (Gamepad.Buttons.HasFlag(GamepadButtonFlags.Start))
+ Inputs.Buttons |= ControllerButtonFlags.Start;
+ if (Gamepad.Buttons.HasFlag(GamepadButtonFlags.Back))
+ Inputs.Buttons |= ControllerButtonFlags.Back;
+
+ if (Gamepad.LeftTrigger > 0)
+ Inputs.Buttons |= ControllerButtonFlags.LeftTrigger;
+ if (Gamepad.RightTrigger > 0)
+ Inputs.Buttons |= ControllerButtonFlags.RightTrigger;
+
+ if (Gamepad.Buttons.HasFlag(GamepadButtonFlags.LeftThumb))
+ Inputs.Buttons |= ControllerButtonFlags.LeftThumb;
+ if (Gamepad.Buttons.HasFlag(GamepadButtonFlags.RightThumb))
+ Inputs.Buttons |= ControllerButtonFlags.RightThumb;
+
+ if (Gamepad.Buttons.HasFlag(GamepadButtonFlags.LeftShoulder))
+ Inputs.Buttons |= ControllerButtonFlags.LeftShoulder;
+ if (Gamepad.Buttons.HasFlag(GamepadButtonFlags.RightShoulder))
+ Inputs.Buttons |= ControllerButtonFlags.RightShoulder;
+
+ if (Gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadUp))
+ Inputs.Buttons |= ControllerButtonFlags.DPadUp;
+ if (Gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadDown))
+ Inputs.Buttons |= ControllerButtonFlags.DPadDown;
+ if (Gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadLeft))
+ Inputs.Buttons |= ControllerButtonFlags.DPadLeft;
+ if (Gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadRight))
+ Inputs.Buttons |= ControllerButtonFlags.DPadRight;
+
+ // Left Stick
+ if (Gamepad.LeftThumbX < -Gamepad.LeftThumbDeadZone)
+ Inputs.Buttons |= ControllerButtonFlags.LStickLeft;
+ else if (Gamepad.LeftThumbX > Gamepad.LeftThumbDeadZone)
+ Inputs.Buttons |= ControllerButtonFlags.LStickRight;
+
+ if (Gamepad.LeftThumbY < -Gamepad.LeftThumbDeadZone)
+ Inputs.Buttons |= ControllerButtonFlags.LStickDown;
+ else if (Gamepad.LeftThumbY > Gamepad.LeftThumbDeadZone)
+ Inputs.Buttons |= ControllerButtonFlags.LStickUp;
+
+ Inputs.LeftThumbX = Gamepad.LeftThumbX;
+ Inputs.LeftThumbY = Gamepad.LeftThumbY;
+
+ // Right Stick
+ if (Gamepad.RightThumbX < -Gamepad.RightThumbDeadZone)
+ Inputs.Buttons |= ControllerButtonFlags.RStickLeft;
+ else if (Gamepad.RightThumbX > Gamepad.RightThumbDeadZone)
+ Inputs.Buttons |= ControllerButtonFlags.RStickRight;
+
+ if (Gamepad.RightThumbY < -Gamepad.RightThumbDeadZone)
+ Inputs.Buttons |= ControllerButtonFlags.RStickDown;
+ else if (Gamepad.RightThumbY > Gamepad.RightThumbDeadZone)
+ Inputs.Buttons |= ControllerButtonFlags.RStickUp;
+
+ Inputs.RightThumbX = Gamepad.RightThumbX;
+ Inputs.RightThumbY = Gamepad.RightThumbY;
+
+ if (State.wButtons.HasFlag(XInputStateButtons.Xbox))
+ Inputs.Buttons |= ControllerButtonFlags.Special;
+
+ Inputs.LeftTrigger = Gamepad.LeftTrigger;
+ Inputs.RightTrigger = Gamepad.RightTrigger;
+
+ // update states
+ prevGamepad = Gamepad;
+ prevState = State;
+
+ base.UpdateReport();
+ }
+
+ public override bool IsConnected()
+ {
+ return (bool)(Controller?.IsConnected);
+ }
+
+ public override async void Rumble()
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ Controller.SetVibration(Vibration);
+ await Task.Delay(100);
+ Controller.SetVibration(new Vibration());
+ await Task.Delay(100);
+ }
+ base.Rumble();
+ }
+
+ public override void Plug()
+ {
+ PipeClient.ServerMessage += OnServerMessage;
+ base.Plug();
+ }
+
+ public override void Unplug()
+ {
+ PipeClient.ServerMessage -= OnServerMessage;
+ base.Unplug();
+ }
+
+ private void OnServerMessage(PipeMessage message)
+ {
+ switch (message.code)
+ {
+ case PipeCode.SERVER_VIBRATION:
+ {
+ PipeClientVibration e = (PipeClientVibration)message;
+
+ ushort LeftMotorSpeed = (ushort)((e.LargeMotor * ushort.MaxValue / byte.MaxValue) * VibrationStrength);
+ ushort RightMotorSpeed = (ushort)((e.SmallMotor * ushort.MaxValue / byte.MaxValue) * VibrationStrength);
+
+ Vibration vibration = new Vibration() { LeftMotorSpeed = LeftMotorSpeed, RightMotorSpeed = RightMotorSpeed };
+ Controller.SetVibration(vibration);
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/ControllerCommon/Devices/AOKZOEA1.cs b/ControllerCommon/Devices/AOKZOEA1.cs
index f4d8b29e0..1fc9b6ea2 100644
--- a/ControllerCommon/Devices/AOKZOEA1.cs
+++ b/ControllerCommon/Devices/AOKZOEA1.cs
@@ -35,7 +35,7 @@ public AOKZOEA1() : base()
// Home
listeners.Add(new DeviceChord("Home key",
- new List() { KeyCode.LWin, KeyCode.D},
+ new List() { KeyCode.LWin, KeyCode.D },
new List() { KeyCode.LWin, KeyCode.D }
));
@@ -50,13 +50,13 @@ public AOKZOEA1() : base()
new List() { KeyCode.LControl, KeyCode.LWin, KeyCode.LMenu },
new List() { KeyCode.LControl, KeyCode.LWin, KeyCode.LMenu }
));
-
+
// Home + Keyboard
listeners.Add(new DeviceChord("Home + Keyboard",
new List() { KeyCode.RAlt, KeyCode.RControlKey, KeyCode.Delete },
new List() { KeyCode.Delete, KeyCode.RControlKey, KeyCode.RAlt }
));
-
+
// Home + Turbo
listeners.Add(new DeviceChord("Home + Turbo",
new List() { KeyCode.LWin, KeyCode.Snapshot },
diff --git a/ControllerCommon/Devices/AYANEOAIR.cs b/ControllerCommon/Devices/AYANEOAIR.cs
index 8420f68ee..22b0e5a81 100644
--- a/ControllerCommon/Devices/AYANEOAIR.cs
+++ b/ControllerCommon/Devices/AYANEOAIR.cs
@@ -35,22 +35,26 @@ public AYANEOAIR() : base()
listeners.Add(new DeviceChord("Custom Key Top Right",
new List() { KeyCode.RControlKey, KeyCode.LWin, KeyCode.F10 },
- new List() { KeyCode.F10, KeyCode.LWin, KeyCode.RControlKey }
+ new List() { KeyCode.F10, KeyCode.LWin, KeyCode.RControlKey },
+ false, Controllers.ControllerButtonFlags.OEM3
));
listeners.Add(new DeviceChord("Custom Key Top Left",
new List() { KeyCode.RControlKey, KeyCode.LWin, KeyCode.F11 },
- new List() { KeyCode.F11, KeyCode.LWin, KeyCode.RControlKey }
+ new List() { KeyCode.F11, KeyCode.LWin, KeyCode.RControlKey },
+ false, Controllers.ControllerButtonFlags.OEM4
));
listeners.Add(new DeviceChord("Custom Key Big",
new List() { KeyCode.RControlKey, KeyCode.LWin, KeyCode.F12 },
- new List() { KeyCode.F12, KeyCode.LWin, KeyCode.RControlKey }
+ new List() { KeyCode.F12, KeyCode.LWin, KeyCode.RControlKey },
+ false, Controllers.ControllerButtonFlags.OEM1
));
listeners.Add(new DeviceChord("Custom Key Small",
new List() { KeyCode.LWin, KeyCode.D },
- new List() { KeyCode.LWin, KeyCode.D }
+ new List() { KeyCode.LWin, KeyCode.D },
+ false, Controllers.ControllerButtonFlags.OEM2
));
}
}
diff --git a/ControllerCommon/Devices/AYANEOAIRLite.cs b/ControllerCommon/Devices/AYANEOAIRLite.cs
index 70034d8d5..9949867df 100644
--- a/ControllerCommon/Devices/AYANEOAIRLite.cs
+++ b/ControllerCommon/Devices/AYANEOAIRLite.cs
@@ -35,22 +35,26 @@ public AYANEOAIRLite() : base()
listeners.Add(new DeviceChord("Custom Key Top Right",
new List() { KeyCode.RControlKey, KeyCode.LWin, KeyCode.F10 },
- new List() { KeyCode.F10, KeyCode.LWin, KeyCode.RControlKey }
+ new List() { KeyCode.F10, KeyCode.LWin, KeyCode.RControlKey },
+ false, Controllers.ControllerButtonFlags.OEM3
));
listeners.Add(new DeviceChord("Custom Key Top Left",
new List() { KeyCode.RControlKey, KeyCode.LWin, KeyCode.F11 },
- new List() { KeyCode.F11, KeyCode.LWin, KeyCode.RControlKey }
+ new List() { KeyCode.F11, KeyCode.LWin, KeyCode.RControlKey },
+ false, Controllers.ControllerButtonFlags.OEM4
));
listeners.Add(new DeviceChord("Custom Key Big",
new List() { KeyCode.RControlKey, KeyCode.LWin, KeyCode.F12 },
- new List() { KeyCode.F12, KeyCode.LWin, KeyCode.RControlKey }
+ new List() { KeyCode.F12, KeyCode.LWin, KeyCode.RControlKey },
+ false, Controllers.ControllerButtonFlags.OEM1
));
listeners.Add(new DeviceChord("Custom Key Small",
new List() { KeyCode.LWin, KeyCode.D },
- new List() { KeyCode.LWin, KeyCode.D }
+ new List() { KeyCode.LWin, KeyCode.D },
+ false, Controllers.ControllerButtonFlags.OEM2
));
}
}
diff --git a/ControllerCommon/Devices/AYANEOAIRPro.cs b/ControllerCommon/Devices/AYANEOAIRPro.cs
index e950efb58..053fa8ea7 100644
--- a/ControllerCommon/Devices/AYANEOAIRPro.cs
+++ b/ControllerCommon/Devices/AYANEOAIRPro.cs
@@ -35,22 +35,26 @@ public AYANEOAIRPro() : base()
listeners.Add(new DeviceChord("Custom Key Top Right",
new List() { KeyCode.RControlKey, KeyCode.LWin, KeyCode.F10 },
- new List() { KeyCode.F10, KeyCode.LWin, KeyCode.RControlKey }
+ new List() { KeyCode.F10, KeyCode.LWin, KeyCode.RControlKey },
+ false, Controllers.ControllerButtonFlags.OEM3
));
listeners.Add(new DeviceChord("Custom Key Top Left",
new List() { KeyCode.RControlKey, KeyCode.LWin, KeyCode.F11 },
- new List() { KeyCode.F11, KeyCode.LWin, KeyCode.RControlKey }
+ new List() { KeyCode.F11, KeyCode.LWin, KeyCode.RControlKey },
+ false, Controllers.ControllerButtonFlags.OEM4
));
listeners.Add(new DeviceChord("Custom Key Big",
new List() { KeyCode.RControlKey, KeyCode.LWin, KeyCode.F12 },
- new List() { KeyCode.F12, KeyCode.LWin, KeyCode.RControlKey }
+ new List() { KeyCode.F12, KeyCode.LWin, KeyCode.RControlKey },
+ false, Controllers.ControllerButtonFlags.OEM1
));
listeners.Add(new DeviceChord("Custom Key Small",
new List() { KeyCode.LWin, KeyCode.D },
- new List() { KeyCode.LWin, KeyCode.D }
+ new List() { KeyCode.LWin, KeyCode.D },
+ false, Controllers.ControllerButtonFlags.OEM2
));
}
}
diff --git a/ControllerCommon/Devices/Device.cs b/ControllerCommon/Devices/Device.cs
index 40de4c876..44f466e4d 100644
--- a/ControllerCommon/Devices/Device.cs
+++ b/ControllerCommon/Devices/Device.cs
@@ -66,7 +66,7 @@ public static Device GetDefault()
switch (ManufacturerName)
{
case "AOKZOE":
- {
+ {
switch (ProductName)
{
case "AOKZOE A1 AR07":
diff --git a/ControllerCommon/Devices/DeviceChord.cs b/ControllerCommon/Devices/DeviceChord.cs
index 6d304bbfc..a3b5f2eeb 100644
--- a/ControllerCommon/Devices/DeviceChord.cs
+++ b/ControllerCommon/Devices/DeviceChord.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using ControllerCommon.Controllers;
+using System.Collections.Generic;
using System.Linq;
using WindowsInput.Events;
@@ -7,18 +8,28 @@ namespace ControllerCommon.Devices
public class DeviceChord
{
public string name;
+ public bool silenced;
+ public ControllerButtonFlags button;
+
public Dictionary> chords = new Dictionary>()
{
{ true, new List() },
{ false, new List() }
};
- public DeviceChord(string name, List chordDown, List chordUP)
+ public DeviceChord(string name, List chordDown, List chordUP, bool silenced = false, ControllerButtonFlags button = ControllerButtonFlags.None)
{
this.name = name;
+ this.silenced = silenced;
+ this.button = button;
this.chords[true].AddRange(chordDown);
this.chords[false].AddRange(chordUP);
}
+
+ public string GetChord(bool IsKeyDown)
+ {
+ return string.Join(" | ", chords[IsKeyDown].OrderBy(key => key).ToList());
+ }
}
}
diff --git a/ControllerCommon/Devices/GPDWinMax2AMD.cs b/ControllerCommon/Devices/GPDWinMax2AMD.cs
index b1b71ddd9..626113007 100644
--- a/ControllerCommon/Devices/GPDWinMax2AMD.cs
+++ b/ControllerCommon/Devices/GPDWinMax2AMD.cs
@@ -33,19 +33,23 @@ public GPDWinMax2AMD() : base()
{ 'Z', 'Y' },
};
+ // Disabled this one as Win Max 2 also sends an Xbox guide input when Menu key is pressed.
listeners.Add(new DeviceChord("Menu",
new List() { KeyCode.LButton | KeyCode.XButton2 },
- new List() { KeyCode.LButton | KeyCode.XButton2 }
+ new List() { KeyCode.LButton | KeyCode.XButton2 },
+ true
));
listeners.Add(new DeviceChord("Bottom button left",
new List() { KeyCode.D9 },
- new List() { KeyCode.D9 }
+ new List() { KeyCode.D9 },
+ false, Controllers.ControllerButtonFlags.OEM1
));
listeners.Add(new DeviceChord("Bottom button right",
new List() { KeyCode.D0 },
- new List() { KeyCode.D0 }
+ new List() { KeyCode.D0 },
+ false, Controllers.ControllerButtonFlags.OEM2
));
}
}
diff --git a/ControllerCommon/Devices/GPDWinMax2Intel.cs b/ControllerCommon/Devices/GPDWinMax2Intel.cs
index e0a07b2f7..f2c5c8756 100644
--- a/ControllerCommon/Devices/GPDWinMax2Intel.cs
+++ b/ControllerCommon/Devices/GPDWinMax2Intel.cs
@@ -32,19 +32,23 @@ public GPDWinMax2Intel() : base()
{ 'Z', 'Y' },
};
+ // Disabled this one as Win Max 2 also sends an Xbox guide input when Menu key is pressed.
listeners.Add(new DeviceChord("Menu",
new List() { KeyCode.LButton | KeyCode.XButton2 },
- new List() { KeyCode.LButton | KeyCode.XButton2 }
+ new List() { KeyCode.LButton | KeyCode.XButton2 },
+ true
));
listeners.Add(new DeviceChord("Bottom button left",
new List() { KeyCode.D9 },
- new List() { KeyCode.D9 }
+ new List() { KeyCode.D9 },
+ false, Controllers.ControllerButtonFlags.OEM1
));
listeners.Add(new DeviceChord("Bottom button right",
new List() { KeyCode.D0 },
- new List() { KeyCode.D0 }
+ new List() { KeyCode.D0 },
+ false, Controllers.ControllerButtonFlags.OEM2
));
}
}
diff --git a/ControllerCommon/Devices/OneXPlayerMiniAMD.cs b/ControllerCommon/Devices/OneXPlayerMiniAMD.cs
index 3b7232e5c..eca94d0d9 100644
--- a/ControllerCommon/Devices/OneXPlayerMiniAMD.cs
+++ b/ControllerCommon/Devices/OneXPlayerMiniAMD.cs
@@ -33,19 +33,23 @@ public OneXPlayerMiniAMD() : base()
{ 'Z', 'Y' },
};
- listeners.Add(new DeviceChord("Menu",
+ // unused
+ listeners.Add(new DeviceChord("Fan",
new List() { KeyCode.LButton | KeyCode.XButton2 },
- new List() { KeyCode.LButton | KeyCode.XButton2 }
+ new List() { KeyCode.LButton | KeyCode.XButton2 },
+ false, Controllers.ControllerButtonFlags.OEM5
));
- listeners.Add(new DeviceChord("Keyboard key",
+ listeners.Add(new DeviceChord("Keyboard",
new List() { KeyCode.LWin, KeyCode.RControlKey, KeyCode.O },
- new List() { KeyCode.O, KeyCode.RControlKey, KeyCode.LWin }
+ new List() { KeyCode.O, KeyCode.RControlKey, KeyCode.LWin },
+ false, Controllers.ControllerButtonFlags.OEM2
));
- listeners.Add(new DeviceChord("Function key",
+ listeners.Add(new DeviceChord("Function",
new List() { KeyCode.LWin, KeyCode.D },
- new List() { KeyCode.D, KeyCode.LWin }
+ new List() { KeyCode.D, KeyCode.LWin },
+ false, Controllers.ControllerButtonFlags.OEM3
));
listeners.Add(new DeviceChord("Function + Volume Up",
@@ -56,11 +60,13 @@ public OneXPlayerMiniAMD() : base()
// dirty implementation from OneX...
listeners.Add(new DeviceChord("Function + Fan",
new List() { KeyCode.LWin, KeyCode.Snapshot },
- new List() { KeyCode.Snapshot, KeyCode.LWin }
+ new List() { KeyCode.Snapshot, KeyCode.LWin },
+ false, Controllers.ControllerButtonFlags.OEM1
));
listeners.Add(new DeviceChord("Function + Fan",
new List() { KeyCode.LWin, KeyCode.Snapshot },
- new List() { KeyCode.Snapshot, KeyCode.Snapshot, KeyCode.LWin }
+ new List() { KeyCode.Snapshot, KeyCode.Snapshot, KeyCode.LWin },
+ false, Controllers.ControllerButtonFlags.OEM1
));
}
}
diff --git a/ControllerCommon/Devices/OneXPlayerMiniIntel.cs b/ControllerCommon/Devices/OneXPlayerMiniIntel.cs
index aa7dfd435..9f410a12d 100644
--- a/ControllerCommon/Devices/OneXPlayerMiniIntel.cs
+++ b/ControllerCommon/Devices/OneXPlayerMiniIntel.cs
@@ -34,34 +34,41 @@ public OneXPlayerMiniIntel() : base()
{ 'Z', 'Y' },
};
- listeners.Add(new DeviceChord("Menu",
+ // unused
+ listeners.Add(new DeviceChord("Fan",
new List() { KeyCode.LButton | KeyCode.XButton2 },
- new List() { KeyCode.LButton | KeyCode.XButton2 }
+ new List() { KeyCode.LButton | KeyCode.XButton2 },
+ false, Controllers.ControllerButtonFlags.OEM5
));
- listeners.Add(new DeviceChord("Keyboard key",
+ listeners.Add(new DeviceChord("Keyboard",
new List() { KeyCode.LWin, KeyCode.RControlKey, KeyCode.O },
- new List() { KeyCode.O, KeyCode.RControlKey, KeyCode.LWin }
+ new List() { KeyCode.O, KeyCode.RControlKey, KeyCode.LWin },
+ false, Controllers.ControllerButtonFlags.OEM2
));
- listeners.Add(new DeviceChord("Function key",
+ listeners.Add(new DeviceChord("Function",
new List() { KeyCode.LWin, KeyCode.D },
- new List() { KeyCode.D, KeyCode.LWin }
+ new List() { KeyCode.D, KeyCode.LWin },
+ false, Controllers.ControllerButtonFlags.OEM3
));
listeners.Add(new DeviceChord("Function + Volume Up",
new List() { KeyCode.F1 },
- new List() { KeyCode.F1, KeyCode.F1 }
+ new List() { KeyCode.F1, KeyCode.F1 },
+ false, Controllers.ControllerButtonFlags.OEM4
));
// dirty implementation from OneX...
listeners.Add(new DeviceChord("Function + Fan",
new List() { KeyCode.LWin, KeyCode.Snapshot },
- new List() { KeyCode.Snapshot, KeyCode.LWin }
+ new List() { KeyCode.Snapshot, KeyCode.LWin },
+ false, Controllers.ControllerButtonFlags.OEM1
));
listeners.Add(new DeviceChord("Function + Fan",
new List() { KeyCode.LWin, KeyCode.Snapshot },
- new List() { KeyCode.Snapshot, KeyCode.Snapshot, KeyCode.LWin }
+ new List() { KeyCode.Snapshot, KeyCode.Snapshot, KeyCode.LWin },
+ false, Controllers.ControllerButtonFlags.OEM1
));
}
}
diff --git a/ControllerCommon/HidHide.cs b/ControllerCommon/HidHide.cs
index d451f3428..b31dbdfc8 100644
--- a/ControllerCommon/HidHide.cs
+++ b/ControllerCommon/HidHide.cs
@@ -8,26 +8,16 @@
namespace ControllerCommon
{
- public class HidHide
+ public static class HidHide
{
- private Process process;
+ private static Process process;
- // The name of the key must include a valid root.
- const string userRoot = @"HKEY_LOCAL_MACHINE";
- const string subkey = @"SOFTWARE\Nefarius Software Solutions e.U.\HidHide";
- const string keyName = userRoot + "\\" + subkey;
-
- private readonly string key = (string)Registry.GetValue(keyName,
- "Path",
- "");
-
- public HidHide()
+ static HidHide()
{
// verifying HidHide is installed
- string path = null;
-
- if (key != null)
- path = Path.Combine(key, "x64", "HidHideCLI.exe");
+ string path = RegistryUtils.GetHKLM(@"SOFTWARE\Nefarius Software Solutions e.U.\HidHide", "Path");
+ if (!string.IsNullOrEmpty(path))
+ path = Path.Combine(path, "x64", "HidHideCLI.exe");
if (!File.Exists(path))
{
@@ -49,7 +39,7 @@ public HidHide()
};
}
- public List GetRegisteredApplications()
+ public static List GetRegisteredApplications()
{
process.StartInfo.Arguments = $"--app-list";
process.Start();
@@ -69,7 +59,7 @@ public List GetRegisteredApplications()
return whitelist;
}
- public List GetRegisteredDevices()
+ public static List GetRegisteredDevices()
{
process.StartInfo.Arguments = $"--dev-list";
process.Start();
@@ -89,7 +79,7 @@ public List GetRegisteredDevices()
return devices;
}
- public void UnregisterApplication(string path)
+ public static void UnregisterApplication(string path)
{
process.StartInfo.Arguments = $"--app-unreg \"{path}\"";
process.Start();
@@ -97,7 +87,7 @@ public void UnregisterApplication(string path)
process.StandardOutput.ReadToEnd();
}
- public void RegisterApplication(string path)
+ public static void RegisterApplication(string path)
{
process.StartInfo.Arguments = $"--app-reg \"{path}\"";
process.Start();
@@ -105,49 +95,17 @@ public void RegisterApplication(string path)
process.StandardOutput.ReadToEnd();
}
- /* private void ListDevices()
- {
- process.StartInfo.Arguments = $"--dev-gaming";
- process.Start();
- process.WaitForExit();
-
- string jsonString = process.StandardOutput.ReadToEnd();
-
- if (jsonString == "" || jsonString == " [ ] \r\n\r\n")
- return;
-
- try
- {
- jsonString = jsonString.Replace("\"friendlyName\" : ", "\"friendlyName\" : \"");
- jsonString = jsonString.Replace("[ {", "{");
- jsonString = jsonString.Replace(" } ] } ] ", " } ] }");
- jsonString = jsonString.Replace(@"\", @"\\");
- root = JsonSerializer.Deserialize(jsonString);
- }
- catch (Exception)
- {
- string tempString = CommonUtils.Between(jsonString, "symbolicLink", ",");
- root = new RootDevice
- {
- friendlyName = "Unknown",
- devices = new List() { new Device() { gamingDevice = true, deviceInstancePath = tempString } }
- };
- }
-
- devices = root.devices;
- } */
-
- public void SetCloaking(bool status, string ProductName)
+ public static void SetCloaking(bool status)
{
process.StartInfo.Arguments = status ? $"--cloak-on" : $"--cloak-off";
process.Start();
process.WaitForExit();
process.StandardOutput.ReadToEnd();
- LogManager.LogInformation("{0} cloak status set to {1}", ProductName, status);
+ LogManager.LogInformation("Cloak status set to {0}", status);
}
- public void UnregisterController(string deviceInstancePath)
+ public static void UnhidePath(string deviceInstancePath)
{
LogManager.LogInformation("HideDevice unhiding DeviceID: {0}", deviceInstancePath);
process.StartInfo.Arguments = $"--dev-unhide \"{deviceInstancePath}\"";
@@ -156,7 +114,7 @@ public void UnregisterController(string deviceInstancePath)
process.StandardOutput.ReadToEnd();
}
- public void RegisterController(string deviceInstancePath)
+ public static void HidePath(string deviceInstancePath)
{
LogManager.LogInformation("HideDevice hiding DeviceID: {0}", deviceInstancePath);
process.StartInfo.Arguments = $"--dev-hide \"{deviceInstancePath}\"";
@@ -164,13 +122,5 @@ public void RegisterController(string deviceInstancePath)
process.WaitForExit();
process.StandardOutput.ReadToEnd();
}
-
- public void UnHideDevice(string deviceInstancePath)
- {
- process.StartInfo.Arguments = $"--dev-unhide \"{deviceInstancePath}\"";
- process.Start();
- process.WaitForExit();
- process.StandardOutput.ReadToEnd();
- }
}
}
diff --git a/ControllerCommon/JoyShockLibrary.dll b/ControllerCommon/JoyShockLibrary.dll
new file mode 100644
index 000000000..b2712de43
Binary files /dev/null and b/ControllerCommon/JoyShockLibrary.dll differ
diff --git a/ControllerCommon/Managers/Hid/Attributes.cs b/ControllerCommon/Managers/Hid/Attributes.cs
new file mode 100644
index 000000000..62c4a2e36
--- /dev/null
+++ b/ControllerCommon/Managers/Hid/Attributes.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace ControllerCommon.Managers.Hid
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Attributes
+ {
+ public int Size;
+ public ushort VendorID;
+ public ushort ProductID;
+ public short VersionNumber;
+ }
+
+ public static class GetAttributes
+ {
+ [DllImport("hid.dll", EntryPoint = "HidD_GetAttributes")]
+ static internal extern bool HidD_GetAttributes(IntPtr hidDeviceObject, ref Attributes attributes);
+
+ public static Attributes? Get(IntPtr handle)
+ {
+ var deviceAttributes = new Attributes();
+ deviceAttributes.Size = Marshal.SizeOf(deviceAttributes);
+ if (HidD_GetAttributes(handle, ref deviceAttributes))
+ return deviceAttributes;
+ else
+ return null;
+ }
+ }
+}
diff --git a/ControllerCommon/Managers/Hid/Capabilities.cs b/ControllerCommon/Managers/Hid/Capabilities.cs
new file mode 100644
index 000000000..8b5dc189c
--- /dev/null
+++ b/ControllerCommon/Managers/Hid/Capabilities.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace ControllerCommon.Managers.Hid
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Capabilities
+ {
+ public short Usage;
+ public short UsagePage;
+ public short InputReportByteLength;
+ public short OutputReportByteLength;
+ public short FeatureReportByteLength;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]
+ public short[] Reserved;
+ public short NumberLinkCollectionNodes;
+ public short NumberInputButtonCaps;
+ public short NumberInputValueCaps;
+ public short NumberInputDataIndices;
+ public short NumberOutputButtonCaps;
+ public short NumberOutputValueCaps;
+ public short NumberOutputDataIndices;
+ public short NumberFeatureButtonCaps;
+ public short NumberFeatureValueCaps;
+ public short NumberFeatureDataIndices;
+ }
+ public static class GetCapabilities
+ {
+ [DllImport("hid.dll")]
+ static internal extern bool HidD_GetPreparsedData(IntPtr hidDeviceObject, ref IntPtr preparsedData);
+
+ [DllImport("hid.dll")]
+ static internal extern int HidP_GetCaps(IntPtr preparsedData, ref Capabilities capabilities);
+
+ [DllImport("hid.dll")]
+ static internal extern bool HidD_FreePreparsedData(IntPtr preparsedData);
+
+ public static Capabilities? Get(IntPtr handle)
+ {
+ var capabilities = new Capabilities();
+ var preparsedDataPointer = IntPtr.Zero;
+
+ if (HidD_GetPreparsedData(handle, ref preparsedDataPointer))
+ {
+ HidP_GetCaps(preparsedDataPointer, ref capabilities);
+ HidD_FreePreparsedData(preparsedDataPointer);
+ return capabilities;
+ }
+ else
+ return null;
+ }
+ }
+}
diff --git a/ControllerCommon/Managers/Manager.cs b/ControllerCommon/Managers/Manager.cs
index ed8cd5fcb..b588f6fe2 100644
--- a/ControllerCommon/Managers/Manager.cs
+++ b/ControllerCommon/Managers/Manager.cs
@@ -6,13 +6,18 @@ public abstract class Manager
public bool IsInitialized { get; set; }
protected string Path { get; set; }
+ public event InitializedEventHandler Initialized;
+ public delegate void InitializedEventHandler();
+
public virtual void Start()
{
IsInitialized = true;
+ Initialized?.Invoke();
}
public virtual void Stop()
{
+ IsInitialized = false;
}
}
}
diff --git a/ControllerCommon/Managers/ServiceManager.cs b/ControllerCommon/Managers/ServiceManager.cs
index 68c182899..4c8d1a876 100644
--- a/ControllerCommon/Managers/ServiceManager.cs
+++ b/ControllerCommon/Managers/ServiceManager.cs
@@ -34,7 +34,7 @@ public class ServiceManager : Manager
public ServiceControllerStatus status = ServiceControllerStatus.None;
private int prevStatus, prevType = -1;
private ServiceControllerStatus nextStatus;
- private ServiceStartMode type = ServiceStartMode.Disabled;
+ public ServiceStartMode type = ServiceStartMode.Disabled;
private Process process;
@@ -90,6 +90,8 @@ public override void Stop()
if (!IsInitialized)
return;
+ IsInitialized = false;
+
MonitorTimer.Elapsed -= MonitorHelper;
MonitorTimer = null;
@@ -220,6 +222,9 @@ public async Task StartServiceAsync()
if (type == ServiceStartMode.Disabled)
return;
+ if (status == ServiceControllerStatus.Running)
+ return;
+
while (!Initialized)
await Task.Delay(1000);
diff --git a/ControllerCommon/Managers/SystemManager.cs b/ControllerCommon/Managers/SystemManager.cs
index 0039bb03d..b961ea47d 100644
--- a/ControllerCommon/Managers/SystemManager.cs
+++ b/ControllerCommon/Managers/SystemManager.cs
@@ -1,7 +1,10 @@
-using ControllerCommon.Sensors;
+using ControllerCommon.Managers.Hid;
+using ControllerCommon.Sensors;
using ControllerCommon.Utils;
using Microsoft.Win32;
using Nefarius.Utilities.DeviceManagement.PnP;
+using PInvoke;
+using SharpDX.DirectInput;
using System;
using System.Collections.Generic;
using System.IO;
@@ -9,6 +12,9 @@
using System.Media;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
+using static ControllerCommon.Managers.SystemManager;
+using Attributes = ControllerCommon.Managers.Hid.Attributes;
+using Capabilities = ControllerCommon.Managers.Hid.Capabilities;
namespace ControllerCommon.Managers
{
@@ -20,26 +26,34 @@ public static class SystemManager
#endregion
#region events
- public static event XInputArrivedEventHandler XInputArrived;
- public delegate void XInputArrivedEventHandler(PnPDeviceEx device);
+ public static event XInputDeviceArrivedEventHandler XInputDeviceArrived;
+ public delegate void XInputDeviceArrivedEventHandler(PnPDetails device);
+ public static event XInputDeviceRemovedEventHandler XInputDeviceRemoved;
+ public delegate void XInputDeviceRemovedEventHandler(PnPDetails device);
- public static event XInputRemovedEventHandler XInputRemoved;
- public delegate void XInputRemovedEventHandler(PnPDeviceEx device);
+ public static event GenericDeviceArrivedEventHandler GenericDeviceArrived;
+ public delegate void GenericDeviceArrivedEventHandler(PnPDevice device);
+ public static event GenericDeviceRemovedEventHandler GenericDeviceRemoved;
+ public delegate void GenericDeviceRemovedEventHandler(PnPDevice device);
- public static event SerialArrivedEventHandler SerialArrived;
- public delegate void SerialArrivedEventHandler(PnPDevice device);
-
- public static event SerialRemovedEventHandler SerialRemoved;
- public delegate void SerialRemovedEventHandler(PnPDevice device);
+ public static event DInputDeviceArrivedEventHandler DInputDeviceArrived;
+ public delegate void DInputDeviceArrivedEventHandler(PnPDetails device);
+ public static event DInputDeviceRemovedEventHandler DInputDeviceRemoved;
+ public delegate void DInputDeviceRemovedEventHandler(PnPDetails device);
public static event SystemStatusChangedEventHandler SystemStatusChanged;
public delegate void SystemStatusChangedEventHandler(SystemStatus status);
+
+ public static event InitializedEventHandler Initialized;
+ public delegate void InitializedEventHandler();
#endregion
public static Guid HidDevice;
- private static DeviceNotificationListener hidListener = new();
- private static DeviceNotificationListener xinputListener = new();
- private static List devices = new();
+ private static DeviceNotificationListener GenericListener = new();
+ private static DeviceNotificationListener XInputListener = new();
+ private static DeviceNotificationListener HIDListener = new();
+
+ private static Dictionary PnPDevices = new();
private static bool IsPowerSuspended;
private static bool IsSessionLocked;
@@ -58,28 +72,47 @@ public enum SystemStatus
static SystemManager()
{
// initialize hid
- HidD_GetHidGuidMethod(out var interfaceGuid);
- HidDevice = interfaceGuid;
+ HidD_GetHidGuidMethod(out HidDevice);
}
public static void Start()
{
- if (IsInitialized)
- return;
-
// listen to system events
SystemEvents.PowerModeChanged += OnPowerChange;
SystemEvents.SessionSwitch += OnSessionSwitch;
- hidListener.StartListen(DeviceInterfaceIds.UsbDevice);
- hidListener.DeviceArrived += Listener_DeviceArrived;
- hidListener.DeviceRemoved += Listener_DeviceRemoved;
+ GenericListener.StartListen(DeviceInterfaceIds.UsbDevice);
+ GenericListener.DeviceArrived += GenericListener_DeviceArrived;
+ GenericListener.DeviceRemoved += GenericListener_DeviceRemoved;
- xinputListener.StartListen(DeviceInterfaceIds.XUsbDevice);
- xinputListener.DeviceArrived += XinputListener_DeviceArrived;
- xinputListener.DeviceRemoved += XinputListener_DeviceRemoved;
+ XInputListener.StartListen(DeviceInterfaceIds.XUsbDevice);
+ XInputListener.DeviceArrived += XInputListener_DeviceArrived;
+ XInputListener.DeviceRemoved += XInputListener_DeviceRemoved;
+
+ HIDListener.StartListen(DeviceInterfaceIds.HidDevice);
+ HIDListener.DeviceArrived += HIDListener_DeviceArrived;
+ HIDListener.DeviceRemoved += HIDListener_DeviceRemoved;
+
+ RefreshHID();
+ RefreshXInput();
+ RefreshDInput();
IsInitialized = true;
+ Initialized?.Invoke();
+ }
+
+ private static void RefreshXInput()
+ {
+ int deviceIndex = 0;
+ while (Devcon.Find(DeviceInterfaceIds.XUsbDevice, out var path, out var instanceId, deviceIndex++))
+ XInputListener_DeviceArrived(new DeviceEventArgs() { InterfaceGuid = new Guid(), SymLink = path });
+ }
+
+ private static void RefreshDInput()
+ {
+ int deviceIndex = 0;
+ while (Devcon.Find(DeviceInterfaceIds.HidDevice, out var path, out var instanceId, deviceIndex++))
+ HIDListener_DeviceArrived(new DeviceEventArgs() { InterfaceGuid = new Guid(), SymLink = path });
}
public static void Stop()
@@ -87,141 +120,158 @@ public static void Stop()
if (!IsInitialized)
return;
+ IsInitialized = false;
+
// stop listening to system events
SystemEvents.PowerModeChanged -= OnPowerChange;
SystemEvents.SessionSwitch -= OnSessionSwitch;
- hidListener.StopListen(DeviceInterfaceIds.UsbDevice);
- hidListener.DeviceArrived -= Listener_DeviceArrived;
- hidListener.DeviceRemoved -= Listener_DeviceRemoved;
+ GenericListener.StopListen(DeviceInterfaceIds.UsbDevice);
+ GenericListener.DeviceArrived -= GenericListener_DeviceArrived;
+ GenericListener.DeviceRemoved -= GenericListener_DeviceRemoved;
- xinputListener.StopListen(DeviceInterfaceIds.XUsbDevice);
- xinputListener.DeviceArrived -= XinputListener_DeviceArrived;
- xinputListener.DeviceRemoved -= XinputListener_DeviceRemoved;
+ XInputListener.StopListen(DeviceInterfaceIds.XUsbDevice);
+ XInputListener.DeviceArrived -= XInputListener_DeviceArrived;
+ XInputListener.DeviceRemoved -= XInputListener_DeviceRemoved;
- IsInitialized = false;
+ HIDListener.StopListen(DeviceInterfaceIds.HidDevice);
+ HIDListener.DeviceArrived -= HIDListener_DeviceArrived;
+ HIDListener.DeviceRemoved -= HIDListener_DeviceRemoved;
}
- public static bool IsVirtualDevice(PnPDevice device, bool isRemoved = false)
+ private static PnPDetails FindDeviceFromUSB(PnPDevice parent)
{
- while (device is not null)
- {
- var parentId = device.GetProperty(DevicePropertyKey.Device_Parent);
-
- if (parentId.Equals(@"HTREE\ROOT\0", StringComparison.OrdinalIgnoreCase))
- break;
-
- device = PnPDevice.GetDeviceByInstanceId(parentId,
- isRemoved
- ? DeviceLocationFlags.Phantom
- : DeviceLocationFlags.Normal
- );
- }
-
- //
- // TODO: test how others behave (reWASD, NVIDIA, ...)
- //
- return device is not null &&
- (device.InstanceId.StartsWith(@"ROOT\SYSTEM", StringComparison.OrdinalIgnoreCase)
- || device.InstanceId.StartsWith(@"ROOT\USB", StringComparison.OrdinalIgnoreCase));
+ return PnPDevices.Values.Where(device => device.baseContainerDeviceInstancePath.Equals(parent.InstanceId, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
}
- private static PnPDeviceEx GetDeviceEx(PnPDevice owner)
+ private static PnPDetails FindDeviceFromHID(PnPDevice children)
{
- PnPDeviceEx deviceEx = new PnPDeviceEx()
- {
- deviceUSB = owner
- };
+ PnPDevices.TryGetValue(children.InstanceId, out var device);
+ return device;
+ }
+ private static void RefreshHID()
+ {
int deviceIndex = 0;
- while (Devcon.Find(HidDevice, out var path, out var instanceId, deviceIndex++))
+ while (Devcon.Find(DeviceInterfaceIds.HidDevice, out var path, out var instanceId, deviceIndex++))
{
- var pnpDevice = PnPDevice.GetDeviceByInterfaceId(path);
- var device = pnpDevice;
+ var children = PnPDevice.GetDeviceByInterfaceId(path);
+ var parent = children;
+
+ // get attributes
+ Attributes? attributes = GetHidAttributes(path);
+ Capabilities? capabilities = GetHidCapabilities(path);
- while (device is not null)
+ if (attributes is null || capabilities is null)
+ continue;
+
+ var ProductID = ((Attributes)attributes).ProductID.ToString("X4");
+ var VendorID = ((Attributes)attributes).VendorID.ToString("X4");
+
+ while (parent is not null)
{
- var parentId = device.GetProperty(DevicePropertyKey.Device_Parent);
-
- if (parentId == owner.DeviceId)
- {
- deviceEx = new PnPDeviceEx()
- {
- deviceUSB = device,
- deviceHID = pnpDevice,
- path = path,
- isVirtual = IsVirtualDevice(pnpDevice),
- deviceIndex = deviceIndex,
- arrivalDate = pnpDevice.GetProperty(DevicePropertyKey.Device_LastArrivalDate)
- };
- devices.Add(deviceEx);
- }
-
- if (parentId.Equals(@"HTREE\ROOT\0", StringComparison.OrdinalIgnoreCase))
+ var parentId = parent.GetProperty(DevicePropertyKey.Device_Parent);
+
+ if (parentId.Equals(@"HTREE\ROOT\0", StringComparison.InvariantCultureIgnoreCase))
break;
- if (parentId.Contains(@"USB\ROOT", StringComparison.OrdinalIgnoreCase))
+ if (parentId.Contains(@"USB\ROOT", StringComparison.InvariantCultureIgnoreCase))
break;
- if (parentId.Contains(@"HID\", StringComparison.OrdinalIgnoreCase))
+ if (parentId.Contains(@"ROOT\SYSTEM", StringComparison.InvariantCultureIgnoreCase))
break;
- device = PnPDevice.GetDeviceByInstanceId(parentId, DeviceLocationFlags.Normal);
- }
- }
+ if (parentId.Contains(@"HID\", StringComparison.InvariantCultureIgnoreCase))
+ break;
- return deviceEx;
- }
+ if (!parentId.Contains(ProductID, StringComparison.InvariantCultureIgnoreCase))
+ break;
- public static List GetDeviceExs()
- {
- devices.Clear();
+ if (!parentId.Contains(VendorID, StringComparison.InvariantCultureIgnoreCase))
+ break;
- int deviceIndex = 0;
- while (Devcon.Find(HidDevice, out var path, out var instanceId, deviceIndex++))
- {
- var pnpDevice = PnPDevice.GetDeviceByInterfaceId(path);
- var device = pnpDevice;
+ parent = PnPDevice.GetDeviceByInstanceId(parentId, DeviceLocationFlags.Normal);
+ }
- while (device is not null)
+ // get details
+ PnPDetails details = new PnPDetails()
{
- var parentId = device.GetProperty(DevicePropertyKey.Device_Parent);
+ SymLink = path,
- if (parentId.Equals(@"HTREE\ROOT\0", StringComparison.OrdinalIgnoreCase))
- break;
+ deviceInstancePath = children.DeviceId,
+ baseContainerDeviceInstancePath = parent.DeviceId,
- if (parentId.Contains(@"USB\ROOT", StringComparison.OrdinalIgnoreCase))
- break;
+ DeviceDesc = parent.GetProperty(DevicePropertyKey.Device_DeviceDesc),
+ Manufacturer = parent.GetProperty(DevicePropertyKey.Device_Manufacturer),
- if (parentId.Contains(@"ROOT\SYSTEM", StringComparison.OrdinalIgnoreCase))
- break;
+ isVirtual = parent.IsVirtual(),
+ isGaming = IsGaming((Attributes)attributes, (Capabilities)capabilities),
- if (parentId.Contains(@"HID\", StringComparison.OrdinalIgnoreCase))
- break;
+ arrivalDate = children.GetProperty(DevicePropertyKey.Device_LastArrivalDate),
- device = PnPDevice.GetDeviceByInstanceId(parentId, DeviceLocationFlags.Normal);
- }
+ attributes = (Attributes)attributes,
+ capabilities = (Capabilities)capabilities,
+ };
- devices.Add(new PnPDeviceEx()
- {
- deviceUSB = device,
- deviceHID = pnpDevice,
- path = path,
- isVirtual = IsVirtualDevice(pnpDevice),
- deviceIndex = deviceIndex,
- arrivalDate = pnpDevice.GetProperty(DevicePropertyKey.Device_LastArrivalDate)
- });
+ // add or update device
+ PnPDevices[children.InstanceId] = details;
}
+ }
+
+ public static List GetDetails(ushort VendorId = 0, ushort ProductId = 0)
+ {
+ List temp = PnPDevices.Values.OrderBy(a => a.arrivalDate).Where(a => a.attributes.VendorID == VendorId && a.attributes.ProductID == ProductId && !a.isHooked).ToList();
+ return temp;
+ }
+
+ public static void UpdateDetails(string InstanceId)
+ {
+ PnPDevices[InstanceId].isHooked = true;
+ }
- return devices;
+ private static Attributes? GetHidAttributes(string path)
+ {
+ using var handle = Kernel32.CreateFile(path,
+ Kernel32.ACCESS_MASK.GenericRight.GENERIC_READ |
+ Kernel32.ACCESS_MASK.GenericRight.GENERIC_WRITE,
+ Kernel32.FileShare.FILE_SHARE_READ | Kernel32.FileShare.FILE_SHARE_WRITE,
+ IntPtr.Zero, Kernel32.CreationDisposition.OPEN_EXISTING,
+ Kernel32.CreateFileFlags.FILE_ATTRIBUTE_NORMAL
+ | Kernel32.CreateFileFlags.FILE_FLAG_NO_BUFFERING
+ | Kernel32.CreateFileFlags.FILE_FLAG_WRITE_THROUGH,
+ Kernel32.SafeObjectHandle.Null
+ );
+
+ return GetAttributes.Get(handle.DangerousGetHandle());
}
- private static PnPDeviceEx GetPnPDeviceEx(string InstanceId)
+ private static Capabilities? GetHidCapabilities(string path)
{
- return devices.Where(a => a.deviceUSB.InstanceId == InstanceId).FirstOrDefault();
+ using var handle = Kernel32.CreateFile(path,
+ Kernel32.ACCESS_MASK.GenericRight.GENERIC_READ |
+ Kernel32.ACCESS_MASK.GenericRight.GENERIC_WRITE,
+ Kernel32.FileShare.FILE_SHARE_READ | Kernel32.FileShare.FILE_SHARE_WRITE,
+ IntPtr.Zero, Kernel32.CreationDisposition.OPEN_EXISTING,
+ Kernel32.CreateFileFlags.FILE_ATTRIBUTE_NORMAL
+ | Kernel32.CreateFileFlags.FILE_FLAG_NO_BUFFERING
+ | Kernel32.CreateFileFlags.FILE_FLAG_WRITE_THROUGH,
+ Kernel32.SafeObjectHandle.Null
+ );
+
+ return GetCapabilities.Get(handle.DangerousGetHandle());
}
- private static void XinputListener_DeviceRemoved(DeviceEventArgs obj)
+ private static bool IsGaming(Attributes attributes, Capabilities capabilities)
+ {
+ return (((attributes.VendorID == 0x28DE) && (attributes.ProductID == 0x1142)) || (0x05 == capabilities.UsagePage) || (0x01 == capabilities.UsagePage) && ((0x04 == capabilities.Usage) || (0x05 == capabilities.Usage)));
+ }
+
+ private static PnPDetails GetPnPDeviceEx(string InstanceId)
+ {
+ return PnPDevices[InstanceId];
+ }
+
+ private async static void XInputListener_DeviceRemoved(DeviceEventArgs obj)
{
// XInput device removed
try
@@ -230,27 +280,73 @@ private static void XinputListener_DeviceRemoved(DeviceEventArgs obj)
InstanceId = CommonUtils.Between(InstanceId, @"\\?\", @"\{");
var deviceEx = GetPnPDeviceEx(InstanceId);
- devices.Remove(deviceEx);
+ PnPDevices.Remove(InstanceId);
- XInputRemoved?.Invoke(deviceEx);
+ XInputDeviceRemoved?.Invoke(deviceEx);
}
catch (Exception) { }
+
+ // give system at least one second to initialize device
+ await Task.Delay(1000);
+ RefreshHID();
}
- private async static void XinputListener_DeviceArrived(DeviceEventArgs obj)
+ private async static void XInputListener_DeviceArrived(DeviceEventArgs obj)
{
- // XInput device arrived
try
{
var device = PnPDevice.GetDeviceByInterfaceId(obj.SymLink);
- await Task.Delay(1000);
- var deviceEx = GetDeviceEx(device);
- XInputArrived?.Invoke(deviceEx);
+
+ if (IsInitialized)
+ {
+ // give system at least one second to initialize device
+ await Task.Delay(1000);
+ RefreshHID();
+ }
+
+ PnPDetails deviceEx = FindDeviceFromUSB(device);
+ if (deviceEx != null && deviceEx.isGaming)
+ XInputDeviceArrived?.Invoke(deviceEx);
}
catch (Exception) { }
}
- private static void Listener_DeviceRemoved(DeviceEventArgs obj)
+ private async static void HIDListener_DeviceRemoved(DeviceEventArgs obj)
+ {
+ try
+ {
+ string InstanceId = obj.SymLink.Replace("#", @"\");
+ InstanceId = CommonUtils.Between(InstanceId, @"\\?\", @"\{");
+
+ var deviceEx = GetPnPDeviceEx(InstanceId);
+ PnPDevices.Remove(InstanceId);
+
+ DInputDeviceRemoved?.Invoke(deviceEx);
+ }
+ catch (Exception) { }
+
+ // give system at least one second to initialize device
+ await Task.Delay(1000);
+ RefreshHID();
+ }
+
+ private async static void HIDListener_DeviceArrived(DeviceEventArgs obj)
+ {
+ var device = PnPDevice.GetDeviceByInterfaceId(obj.SymLink);
+
+ if (IsInitialized)
+ {
+ // give system at least one second to initialize device
+ await Task.Delay(1000);
+ RefreshHID();
+ }
+
+ PnPDetails deviceEx = FindDeviceFromHID(device);
+ if (deviceEx != null && deviceEx.isGaming)
+ DInputDeviceArrived?.Invoke(deviceEx);
+ }
+
+ private static void GenericListener_DeviceRemoved(DeviceEventArgs obj)
{
try
{
@@ -259,12 +355,12 @@ private static void Listener_DeviceRemoved(DeviceEventArgs obj)
string ProductID = CommonUtils.Between(symLink, "PID_", "&");
if (SerialUSBIMU.vendors.ContainsKey(new KeyValuePair(VendorID, ProductID)))
- SerialRemoved?.Invoke(null);
+ GenericDeviceRemoved?.Invoke(null);
}
catch (Exception) { }
}
- private static void Listener_DeviceArrived(DeviceEventArgs obj)
+ private static void GenericListener_DeviceArrived(DeviceEventArgs obj)
{
try
{
@@ -273,7 +369,7 @@ private static void Listener_DeviceArrived(DeviceEventArgs obj)
string ProductID = CommonUtils.Between(symLink, "PID_", "&");
if (SerialUSBIMU.vendors.ContainsKey(new KeyValuePair(VendorID, ProductID)))
- SerialArrived?.Invoke(null);
+ GenericDeviceArrived?.Invoke(null);
}
catch (Exception) { }
}
diff --git a/ControllerCommon/PipeClass/PipeClient.cs b/ControllerCommon/PipeClass/PipeClient.cs
deleted file mode 100644
index be5519207..000000000
--- a/ControllerCommon/PipeClass/PipeClient.cs
+++ /dev/null
@@ -1,118 +0,0 @@
-using ControllerCommon.Managers;
-using NamedPipeWrapper;
-using System;
-using System.Collections.Concurrent;
-using System.Timers;
-using Timer = System.Timers.Timer;
-
-namespace ControllerCommon
-{
- public class PipeClient
- {
- public NamedPipeClient client;
-
- public event ConnectedEventHandler Connected;
- public delegate void ConnectedEventHandler(Object sender);
-
- public event DisconnectedEventHandler Disconnected;
- public delegate void DisconnectedEventHandler(Object sender);
-
- public event ServerMessageEventHandler ServerMessage;
- public delegate void ServerMessageEventHandler(Object sender, PipeMessage e);
-
- private ConcurrentQueue m_queue;
- private Timer m_timer;
-
- public bool connected;
-
- public PipeClient(string pipeName)
- {
- m_queue = new ConcurrentQueue();
-
- // monitors processes and settings
- m_timer = new Timer(1000) { Enabled = false, AutoReset = true };
- m_timer.Elapsed += SendMessageQueue;
-
- client = new NamedPipeClient(pipeName);
- client.AutoReconnect = true;
-
- client.Disconnected += OnClientDisconnected;
- client.ServerMessage += OnServerMessage;
- client.Error += OnError;
- }
-
- public override string ToString()
- {
- return this.GetType().Name;
- }
-
- private void OnClientDisconnected(NamedPipeConnection connection)
- {
- LogManager.LogInformation("Client {0} disconnected", connection.Id);
- Disconnected?.Invoke(this);
-
- connected = false;
- }
-
- public void Open()
- {
- client?.Start();
- LogManager.LogInformation("{0} has started", this.ToString());
- }
-
- public void Close()
- {
- client?.Stop();
- LogManager.LogInformation("{0} has stopped", this.ToString());
- client = null;
- }
-
- private void OnServerMessage(NamedPipeConnection connection, PipeMessage message)
- {
- LogManager.LogDebug("Client {0} opcode: {1} says: {2}", connection.Id, message.code, string.Join(" ", message.ToString()));
- ServerMessage?.Invoke(this, message);
-
- switch (message.code)
- {
- case PipeCode.SERVER_PING:
- connected = true;
- Connected?.Invoke(this);
- LogManager.LogInformation("Client {0} is now connected!", connection.Id);
- break;
- }
- }
-
- private void OnError(Exception exception)
- {
- LogManager.LogError("{0} failed. {1}", this.ToString(), exception.Message);
- }
-
- public void SendMessage(PipeMessage message)
- {
- if (!connected)
- {
- Type nodeType = message.GetType();
- if (nodeType == typeof(PipeClientCursor))
- return;
-
- m_queue.Enqueue(message);
- m_timer.Start();
- return;
- }
-
- client?.PushMessage(message);
- }
-
- private void SendMessageQueue(object sender, ElapsedEventArgs e)
- {
- if (!connected)
- return;
-
- foreach (PipeMessage m in m_queue)
- client?.PushMessage(m);
-
- m_queue.Clear();
- m_timer.Stop();
- }
- }
-}
diff --git a/ControllerCommon/Pipes/PipeClient.cs b/ControllerCommon/Pipes/PipeClient.cs
new file mode 100644
index 000000000..9db0299e3
--- /dev/null
+++ b/ControllerCommon/Pipes/PipeClient.cs
@@ -0,0 +1,114 @@
+using ControllerCommon.Managers;
+using NamedPipeWrapper;
+using System;
+using System.Collections.Concurrent;
+using System.Timers;
+using Timer = System.Timers.Timer;
+
+namespace ControllerCommon
+{
+ public static class PipeClient
+ {
+ public static NamedPipeClient client;
+
+ public static event ConnectedEventHandler Connected;
+ public delegate void ConnectedEventHandler();
+
+ public static event DisconnectedEventHandler Disconnected;
+ public delegate void DisconnectedEventHandler();
+
+ public static event ServerMessageEventHandler ServerMessage;
+ public delegate void ServerMessageEventHandler(PipeMessage e);
+
+ private static ConcurrentQueue m_queue = new();
+ private static Timer m_timer;
+
+ public static bool IsConnected;
+
+ public static void Initialize(string pipeName)
+ {
+ // monitors processes and settings
+ m_timer = new Timer(1000) { Enabled = false, AutoReset = true };
+ m_timer.Elapsed += SendMessageQueue;
+
+ client = new NamedPipeClient(pipeName);
+ client.AutoReconnect = true;
+ }
+
+ private static void OnClientDisconnected(NamedPipeConnection connection)
+ {
+ LogManager.LogInformation("Client {0} disconnected", connection.Id);
+ Disconnected?.Invoke();
+
+ IsConnected = false;
+ }
+
+ public static void Open()
+ {
+ client.Disconnected += OnClientDisconnected;
+ client.ServerMessage += OnServerMessage;
+ client.Error += OnError;
+
+ client?.Start();
+ LogManager.LogInformation("{0} has started", "PipeClient");
+ }
+
+ public static void Close()
+ {
+ client.Disconnected -= OnClientDisconnected;
+ client.ServerMessage -= OnServerMessage;
+ client.Error -= OnError;
+
+ client?.Stop();
+ LogManager.LogInformation("{0} has stopped", "PipeClient");
+ client = null;
+ }
+
+ private static void OnServerMessage(NamedPipeConnection connection, PipeMessage message)
+ {
+ ServerMessage?.Invoke(message);
+
+ switch (message.code)
+ {
+ case PipeCode.SERVER_PING:
+ IsConnected = true;
+ Connected?.Invoke();
+ LogManager.LogInformation("Client {0} is now connected!", connection.Id);
+ break;
+ }
+ }
+
+ private static void OnError(Exception exception)
+ {
+ LogManager.LogError("{0} failed. {1}", "PipeClient", exception.Message);
+ }
+
+ public static void SendMessage(PipeMessage message)
+ {
+ if (!IsConnected)
+ {
+ Type nodeType = message.GetType();
+ if (nodeType == typeof(PipeClientCursor))
+ return;
+
+ m_queue.Enqueue(message);
+ m_timer.Start();
+ return;
+ }
+
+ client?.PushMessage(message);
+ }
+
+ private static void SendMessageQueue(object sender, ElapsedEventArgs e)
+ {
+ if (!IsConnected)
+ return;
+
+ foreach (PipeMessage m in m_queue)
+ client?.PushMessage(m);
+
+ m_queue.Clear();
+ m_timer.Stop();
+ }
+ }
+}
diff --git a/ControllerCommon/PipeClass/PipeMessage.cs b/ControllerCommon/Pipes/PipeMessage.cs
similarity index 82%
rename from ControllerCommon/PipeClass/PipeMessage.cs
rename to ControllerCommon/Pipes/PipeMessage.cs
index d631a715e..a5f9aeb98 100644
--- a/ControllerCommon/PipeClass/PipeMessage.cs
+++ b/ControllerCommon/Pipes/PipeMessage.cs
@@ -1,4 +1,5 @@
-using System;
+using ControllerCommon.Controllers;
+using System;
using System.Collections.Generic;
using System.Numerics;
@@ -111,36 +112,30 @@ public PipeClientCursor()
}
[Serializable]
- public enum HidderAction
+ public partial class PipeClientInput : PipeMessage
{
- Register = 0,
- Unregister = 1
- }
+ public ControllerInput Inputs;
- [Serializable]
- public partial class PipeClientHidder : PipeMessage
- {
- public HidderAction action;
- public string path;
+ public PipeClientInput()
+ {
+ code = PipeCode.CLIENT_INPUT;
+ }
- public PipeClientHidder()
+ public PipeClientInput(ControllerInput inputs) : this()
{
- code = PipeCode.CLIENT_HIDDER;
+ Inputs = inputs;
}
}
[Serializable]
- public partial class PipeClientInput : PipeMessage
+ public partial class PipeClientVibration : PipeMessage
{
- public uint Buttons;
- public ushort sButtons;
-
- public bool IsKeyDown;
- public bool IsKeyUp;
+ public ushort LargeMotor;
+ public ushort SmallMotor;
- public PipeClientInput()
+ public PipeClientVibration()
{
- code = PipeCode.CLIENT_INPUT;
+ code = PipeCode.SERVER_VIBRATION;
}
}
@@ -239,22 +234,5 @@ public PipeOverlay(int Visibility)
this.Visibility = Visibility;
}
}
-
- [Serializable]
- public partial class PipeControllerIndex : PipeMessage
- {
- public int UserIndex;
- public string deviceInstancePath;
- public string baseContainerDeviceInstancePath;
-
- public PipeControllerIndex(int UserIndex, string deviceInstancePath, string baseContainerDeviceInstancePath)
- {
- code = PipeCode.CLIENT_CONTROLLERINDEX;
-
- this.UserIndex = UserIndex;
- this.deviceInstancePath = deviceInstancePath;
- this.baseContainerDeviceInstancePath = baseContainerDeviceInstancePath;
- }
- }
#endregion
}
diff --git a/ControllerCommon/PipeClass/PipeServer.cs b/ControllerCommon/Pipes/PipeServer.cs
similarity index 64%
rename from ControllerCommon/PipeClass/PipeServer.cs
rename to ControllerCommon/Pipes/PipeServer.cs
index 358d49acf..59a4916d2 100644
--- a/ControllerCommon/PipeClass/PipeServer.cs
+++ b/ControllerCommon/Pipes/PipeServer.cs
@@ -31,8 +31,7 @@ public enum PipeCode
CLIENT_SETTINGS = 8, // Sent to server to update settings
// args: ...
- CLIENT_HIDDER = 9, // Sent to server to register applications
- // args: ...
+ OBSOLETE_0 = 9, // OBSOLETE, REUSEME
OBSOLETE_1 = 11, // OBSOLETE, REUSEME
@@ -51,37 +50,35 @@ public enum PipeCode
CLIENT_OVERLAY = 16, // Sent to server to share current overlay status
// args: ...
- OBSOLETE_2 = 17, // OBSOLETE, REUSEME
-
- CLIENT_CONTROLLERINDEX = 18, // Sent to server to share details on controller
+ SERVER_VIBRATION = 17, // Sent to client to notify a vibration feedback arrived
// args: ...
+ OBSOLETE_2 = 18, // OBSOLETE, REUSEME
+
CLIENT_CLEARINDEX = 19, // Sent to server to clear all hidden controllers
// args: ...
}
- public class PipeServer
+ public static class PipeServer
{
- private NamedPipeServer server;
+ private static NamedPipeServer server;
- public event ConnectedEventHandler Connected;
- public delegate void ConnectedEventHandler(Object sender);
+ public static event ConnectedEventHandler Connected;
+ public delegate void ConnectedEventHandler();
- public event DisconnectedEventHandler Disconnected;
- public delegate void DisconnectedEventHandler(Object sender);
+ public static event DisconnectedEventHandler Disconnected;
+ public delegate void DisconnectedEventHandler();
- public event ClientMessageEventHandler ClientMessage;
- public delegate void ClientMessageEventHandler(Object sender, PipeMessage e);
+ public static event ClientMessageEventHandler ClientMessage;
+ public delegate void ClientMessageEventHandler(PipeMessage e);
- private readonly ConcurrentQueue m_queue;
- private readonly Timer m_timer;
+ private static ConcurrentQueue m_queue = new();
+ private static Timer m_timer;
- public bool connected;
+ public static bool IsConnected;
- public PipeServer(string pipeName)
+ public static void Initialize(string pipeName)
{
- m_queue = new ConcurrentQueue();
-
// monitors processes and settings
m_timer = new Timer(1000) { Enabled = false, AutoReset = true };
m_timer.Elapsed += SendMessageQueue;
@@ -92,63 +89,63 @@ public PipeServer(string pipeName)
ps.AddAccessRule(par);
server = new NamedPipeServer(pipeName, ps);
+ }
+
+ public static void Open()
+ {
server.ClientConnected += OnClientConnected;
server.ClientDisconnected += OnClientDisconnected;
server.ClientMessage += OnClientMessage;
server.Error += OnError;
- }
-
- public override string ToString()
- {
- return this.GetType().Name;
- }
-
- public void Open()
- {
server?.Start();
- LogManager.LogInformation("{0} has started", this.ToString());
+
+ LogManager.LogInformation("{0} has started", "PipeServer");
}
- public void Close()
+ public static void Close()
{
+ server.ClientConnected -= OnClientConnected;
+ server.ClientDisconnected -= OnClientDisconnected;
+ server.ClientMessage -= OnClientMessage;
+ server.Error -= OnError;
server?.Stop();
- LogManager.LogInformation("{0} has stopped", this.ToString());
+
+ LogManager.LogInformation("{0} has stopped", "PipeServer");
server = null;
}
- private void OnClientConnected(NamedPipeConnection connection)
+ private static void OnClientConnected(NamedPipeConnection connection)
{
LogManager.LogInformation("Client {0} is now connected!", connection.Id);
- Connected?.Invoke(this);
+ Connected?.Invoke();
- connected = true;
+ IsConnected = true;
// send ping
SendMessage(new PipeServerPing());
}
- private void OnClientDisconnected(NamedPipeConnection connection)
+ private static void OnClientDisconnected(NamedPipeConnection connection)
{
LogManager.LogInformation("Client {0} disconnected", connection.Id);
- Disconnected?.Invoke(this);
+ Disconnected?.Invoke();
- connected = false;
+ IsConnected = false;
}
- private void OnClientMessage(NamedPipeConnection connection, PipeMessage message)
+ private static void OnClientMessage(NamedPipeConnection connection, PipeMessage message)
{
- LogManager.LogDebug("Client {0} opcode: {1} says: {2}", connection.Id, message.code, string.Join(" ", message.ToString()));
- ClientMessage?.Invoke(this, message);
+ ClientMessage?.Invoke(message);
}
- private void OnError(Exception exception)
+ private static void OnError(Exception exception)
{
- LogManager.LogError("{0} failed. {1}", this.ToString(), exception.Message);
+ LogManager.LogError("{0} failed. {1}", "PipeServer", exception.Message);
}
- public void SendMessage(PipeMessage message)
+ public static void SendMessage(PipeMessage message)
{
- if (!connected)
+ if (!IsConnected)
{
Type nodeType = message.GetType();
if (nodeType == typeof(PipeSensor))
@@ -162,9 +159,9 @@ public void SendMessage(PipeMessage message)
server?.PushMessage(message);
}
- private void SendMessageQueue(object sender, ElapsedEventArgs e)
+ private static void SendMessageQueue(object sender, ElapsedEventArgs e)
{
- if (!connected)
+ if (!IsConnected)
return;
foreach (PipeMessage m in m_queue)
diff --git a/ControllerCommon/PnPDetails.cs b/ControllerCommon/PnPDetails.cs
new file mode 100644
index 000000000..24dac5fc5
--- /dev/null
+++ b/ControllerCommon/PnPDetails.cs
@@ -0,0 +1,25 @@
+using ControllerCommon.Managers.Hid;
+using System;
+using System.Runtime.InteropServices;
+
+namespace ControllerCommon
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public class PnPDetails
+ {
+ public string Manufacturer;
+ public string DeviceDesc;
+ public string SymLink;
+
+ public bool isVirtual;
+ public bool isGaming;
+ public bool isHooked;
+ public DateTimeOffset arrivalDate;
+
+ public string deviceInstancePath;
+ public string baseContainerDeviceInstancePath;
+
+ public Attributes attributes;
+ public Capabilities capabilities;
+ }
+}
diff --git a/ControllerCommon/Processor/Processor.cs b/ControllerCommon/Processor/Processor.cs
index d8cf80640..ef3d80afb 100644
--- a/ControllerCommon/Processor/Processor.cs
+++ b/ControllerCommon/Processor/Processor.cs
@@ -1,13 +1,9 @@
using ControllerCommon.Managers;
using ControllerCommon.Processor.AMD;
using ControllerCommon.Processor.Intel;
-using PInvoke;
-using SharpDX.XInput;
using System;
using System.Collections.Generic;
-using System.Drawing.Drawing2D;
using System.Management;
-using System.ServiceProcess;
using System.Threading;
using System.Timers;
using Timer = System.Timers.Timer;
@@ -62,6 +58,9 @@ public class Processor
public event StatusChangedHandler StatusChanged;
public delegate void StatusChangedHandler(bool CanChangeTDP, bool CanChangeGPU);
+
+ public event InitializedEventHandler Initialized;
+ public delegate void InitializedEventHandler();
#endregion
public static Processor GetCurrent()
@@ -105,6 +104,7 @@ public Processor()
public virtual void Initialize()
{
StatusChanged?.Invoke(CanChangeTDP, CanChangeGPU);
+ Initialized?.Invoke();
if (CanChangeTDP)
updateTimer.Start();
@@ -487,7 +487,10 @@ public override void SetGPUClock(double clock, int result)
{
// reset default var
if (clock == 12750)
+ {
+ Monitor.Exit(base.IsBusy);
return;
+ }
var error = RyzenAdj.set_gfx_clk(ry, (uint)clock);
diff --git a/ControllerCommon/Profile.cs b/ControllerCommon/Profile.cs
index 1adac6abc..581866ac9 100644
--- a/ControllerCommon/Profile.cs
+++ b/ControllerCommon/Profile.cs
@@ -1,3 +1,4 @@
+using ControllerCommon.Controllers;
using ControllerCommon.Utils;
using System;
using System.Collections.Generic;
@@ -76,7 +77,7 @@ public class Profile
// Aiming down sights
public float aiming_down_sights_multiplier { get; set; } = 1.0f;
- public GamepadButtonFlagsExt aiming_down_sights_activation { get; set; }
+ public ControllerButtonFlags aiming_down_sights_activation { get; set; }
// flickstick
public bool flickstick_enabled { get; set; }
@@ -87,7 +88,7 @@ public class Profile
public bool TDP_override { get; set; }
public double[] TDP_value { get; set; } = new double[3];
- public GamepadButtonFlagsExt umc_trigger { get; set; }
+ public ControllerButtonFlags umc_trigger { get; set; }
// hidden settings
[JsonIgnore] public ProfileErrorCode error;
diff --git a/ControllerCommon/SensorFusion.cs b/ControllerCommon/SensorFusion.cs
index 5f95ad9c4..f524bcd3c 100644
--- a/ControllerCommon/SensorFusion.cs
+++ b/ControllerCommon/SensorFusion.cs
@@ -1,5 +1,4 @@
-using ControllerCommon.Managers;
-using ControllerCommon.Utils;
+using ControllerCommon.Utils;
using System;
using System.Numerics;
@@ -29,18 +28,6 @@ public SensorFusion()
public void UpdateReport(double TotalMilliseconds, double DeltaSeconds, Vector3 AngularVelocity, Vector3 Acceleration)
{
-#if DEBUG
- LogManager.LogDebug("Plot XInputSensorFusion_DeltaSeconds {0} {1}", TotalMilliseconds, DeltaSeconds);
-
- LogManager.LogDebug("Plot XInputSensorFusion_AngularVelocityX {0} {1}", TotalMilliseconds, AngularVelocity.X);
- LogManager.LogDebug("Plot XInputSensorFusion_AngularVelocityY {0} {1}", TotalMilliseconds, AngularVelocity.Y);
- LogManager.LogDebug("Plot XInputSensorFusion_AngularVelocityZ {0} {1}", TotalMilliseconds, AngularVelocity.Z);
-
- LogManager.LogDebug("Plot XInputSensorFusion_AccelerationX {0} {1}", TotalMilliseconds, Acceleration.X);
- LogManager.LogDebug("Plot XInputSensorFusion_AccelerationY {0} {1}", TotalMilliseconds, Acceleration.Y);
- LogManager.LogDebug("Plot XInputSensorFusion_AccelerationZ {0} {1}", TotalMilliseconds, Acceleration.Z);
-#endif
-
// Check for empty inputs, prevent NaN computes
Vector3 EmptyVector = new(0f, 0f, 0f);
@@ -80,12 +67,6 @@ public void CalculateGravitySimple(double TotalMilliseconds, double DeltaMillise
Vector3 gravityDelta = Vector3.Subtract(newGravity, GravityVectorSimple);
GravityVectorSimple += Vector3.Multiply(0.02f, Vector3.Normalize(gravityDelta));
-
-#if DEBUG
- LogManager.LogDebug("Plot XInputSensorFusion_GravityVectorSimpleEndX {0} {1}", TotalMilliseconds, GravityVectorSimple.X);
- LogManager.LogDebug("Plot XInputSensorFusion_GravityVectorSimpleEndY {0} {1}", TotalMilliseconds, GravityVectorSimple.Y);
- LogManager.LogDebug("Plot XInputSensorFusion_GravityVectorSimpleEndZ {0} {1}", TotalMilliseconds, GravityVectorSimple.Z);
-#endif
}
public void CalculateGravityFancy(double TotalMilliseconds, double DeltaTimeSec, Vector3 AngularVelocity, Vector3 Acceleration)
@@ -128,29 +109,12 @@ public void CalculateGravityFancy(double TotalMilliseconds, double DeltaTimeSec,
// convert gyro input to reverse rotation
Quaternion reverseRotation = Quaternion.CreateFromAxisAngle(-AngularVelocityRad, AngularVelocityRad.Length() * (float)DeltaTimeSec);
-#if DEBUG
- LogManager.LogDebug("Plot vigemtarget_reverseRotationy.X {0} {1}", TotalMilliseconds, reverseRotation.X);
- LogManager.LogDebug("Plot vigemtarget_reverseRotationy.Y {0} {1}", TotalMilliseconds, reverseRotation.Y);
- LogManager.LogDebug("Plot vigemtarget_reverseRotationy.Z {0} {1}", TotalMilliseconds, reverseRotation.Z);
- LogManager.LogDebug("Plot vigemtarget_reverseRotationy.W {0} {1}", TotalMilliseconds, reverseRotation.W);
-#endif
-
// rotate gravity vector
GravityVectorFancy = Vector3.Transform(GravityVectorFancy, reverseRotation);
// Correction factor variables
SmoothAccel = Vector3.Transform(SmoothAccel, reverseRotation);
-#if DEBUG
- LogManager.LogDebug("Plot vigemtarget_GravityVectorFancy_after_rotate_x {0} {1}", TotalMilliseconds, GravityVectorFancy.X);
- LogManager.LogDebug("Plot vigemtarget_GravityVectorFancy_after_rotate_y {0} {1}", TotalMilliseconds, GravityVectorFancy.Y);
- LogManager.LogDebug("Plot vigemtarget_GravityVectorFancy_after_rotate_z {0} {1}", TotalMilliseconds, GravityVectorFancy.Z);
-
- LogManager.LogDebug("Plot vigemtarget_GravityVectorFancy_SmoothAccel_x {0} {1}", TotalMilliseconds, SmoothAccel.X);
- LogManager.LogDebug("Plot vigemtarget_GravityVectorFancy_SmoothAccel_y {0} {1}", TotalMilliseconds, SmoothAccel.Y);
- LogManager.LogDebug("Plot vigemtarget_GravityVectorFancy_SmoothAccel_z {0} {1}", TotalMilliseconds, SmoothAccel.Z);
-#endif
-
// Note to self, SmoothAccel seems OK.
float smoothInterpolator = (float)Math.Pow(2, (-(float)DeltaTimeSec / SmoothingHalfTime));
// Note to self, SmoothInterpolator seems OK, still no sure about the Pow from C++ to C#, also, is it suppose to be a negative value?
@@ -159,16 +123,6 @@ public void CalculateGravityFancy(double TotalMilliseconds, double DeltaTimeSec,
Shakiness = Math.Max(Shakiness, Vector3.Subtract(Acceleration, SmoothAccel).Length()); // Does this apply vector subtract and length correctly?
SmoothAccel = Vector3.Lerp(Acceleration, SmoothAccel, smoothInterpolator); // smoothInterpolator is a negative value, correct?
-#if DEBUG
- LogManager.LogDebug("Plot vigemtarget_GravityVectorFancy_smoothInterpolator {0} {1}", TotalMilliseconds, smoothInterpolator);
- LogManager.LogDebug("Plot vigemtarget_GravityVectorFancy_ShakinessTimesInterpolator {0} {1}", TotalMilliseconds, Shakiness);
- LogManager.LogDebug("Plot vigemtarget_GravityVectorFancy_Shakiness {0} {1}", TotalMilliseconds, Shakiness);
-
- LogManager.LogDebug("Plot vigemtarget_GravityVectorFancy_SmoothAccel2_x {0} {1}", TotalMilliseconds, SmoothAccel.X);
- LogManager.LogDebug("Plot vigemtarget_GravityVectorFancy_SmoothAccel2_y {0} {1}", TotalMilliseconds, SmoothAccel.Y);
- LogManager.LogDebug("Plot vigemtarget_GravityVectorFancy_SmoothAccel2_z {0} {1}", TotalMilliseconds, SmoothAccel.Z);
-#endif
-
Vector3 gravityDelta = Vector3.Subtract(-Acceleration, GravityVectorFancy);
Vector3 gravityDirection = Vector3.Normalize(gravityDelta);
float correctionRate;
@@ -177,11 +131,6 @@ public void CalculateGravityFancy(double TotalMilliseconds, double DeltaTimeSec,
if (ShakinessMaxThreshold > ShakinessMinThreshold)
{
float stillOrShaky = Math.Clamp((Shakiness - ShakinessMinThreshold) / (ShakinessMaxThreshold - ShakinessMaxThreshold), 0, 1);
-
-#if DEBUG
- LogManager.LogDebug("Plot vigemtarget_GravityVectorFancy_stillOrShaky {0} {1}", TotalMilliseconds, stillOrShaky);
-#endif
-
correctionRate = CorrectionStillRate + (CorrectionShakyRate - CorrectionStillRate) * stillOrShaky;
// 1 + (0.1 - 1) * 1 = 0.1
// Note, found still or shaky to be a constant 1, correction rate to be a constant 0.1
@@ -201,13 +150,6 @@ public void CalculateGravityFancy(double TotalMilliseconds, double DeltaTimeSec,
float angleRate = AngularVelocity.Length() * (float)Math.PI / 180;
float correctionLimit = angleRate * GravityVectorFancy.Length() * CorrectionGyroFactor;
-#if DEBUG
- LogManager.LogDebug("Plot vigemtarget_GravityVectorFancy_correctionRate {0} {1}", TotalMilliseconds, correctionRate);
-
- LogManager.LogDebug("Plot vigemtarget_GravityVectorFancy_angleRate {0} {1}", TotalMilliseconds, angleRate);
- LogManager.LogDebug("Plot vigemtarget_GravityVectorFancy_correctionLimit {0} {1}", TotalMilliseconds, correctionLimit);
-#endif
-
if (correctionRate > correctionLimit)
{
float closeEnoughFactor;
@@ -264,11 +206,6 @@ private void PlayerSpace(double TotalMilliseconds, double DeltaSeconds, Vector3
// Pitch (local space)
CameraPitchDelta = AngularVelocity.X * AdditionalFactor * DeltaSeconds;
-
-#if DEBUG
- LogManager.LogDebug("Plot XInputSensorFusion_CameraYawDelta {0} {1}", TotalMilliseconds, CameraYawDelta);
- LogManager.LogDebug("Plot XInputSensorFusion_CameraPitchDelta {0} {1}", TotalMilliseconds, CameraPitchDelta);
-#endif
}
private void DeviceAngles(double TotalMilliseconds, Vector3 GravityVector)
@@ -278,10 +215,6 @@ private void DeviceAngles(double TotalMilliseconds, Vector3 GravityVector)
// Based on: https://www.digikey.com/en/articles/using-an-accelerometer-for-inclination-sensing
DeviceAngle.X = (float)((Math.Atan(GravityVector.Y / (Math.Sqrt(Math.Pow(GravityVector.X, 2) + Math.Pow(GravityVector.Z, 2))))) * 180 / Math.PI);
DeviceAngle.Y = (float)((Math.Atan(GravityVector.X / (Math.Sqrt(Math.Pow(GravityVector.Y, 2) + Math.Pow(GravityVector.Z, 2))))) * 180 / Math.PI);
-
-#if DEBUG
- LogManager.LogDebug("Plot XInputSensorFusion_DeviceAngle.Y {0} {1}", TotalMilliseconds, DeviceAngle.Y);
-#endif
}
}
}
\ No newline at end of file
diff --git a/ControllerCommon/Utils/InputUtils.cs b/ControllerCommon/Utils/InputUtils.cs
index 2004e7150..d401fb68b 100644
--- a/ControllerCommon/Utils/InputUtils.cs
+++ b/ControllerCommon/Utils/InputUtils.cs
@@ -1,4 +1,5 @@
-using System;
+using ControllerCommon.Controllers;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
@@ -35,26 +36,6 @@ public enum Output
Mouse = 2 */
}
- public enum GamepadButtonFlagsExt : uint
- {
- DPadUp = 1,
- DPadDown = 2,
- DPadLeft = 4,
- DPadRight = 8,
- Start = 16,
- Back = 32,
- LeftThumb = 64,
- RightThumb = 128,
- LeftShoulder = 256,
- RightShoulder = 512,
- LeftTrigger = 1024,
- RightTrigger = 2048,
- A = 4096,
- B = 8192,
- X = 16384,
- Y = 32768
- }
-
public enum OverlayModelMode
{
OEM = 0,
@@ -64,49 +45,12 @@ public enum OverlayModelMode
EightBitDoLite2 = 4,
MachenikeHG510 = 5,
Toy = 6,
- N64 = 7
+ N64 = 7,
+ DualSense = 8,
}
public static class InputUtils
{
- public static string GamepadButtonToGlyph(GamepadButtonFlagsExt button)
- {
- switch (button)
- {
- case GamepadButtonFlagsExt.A:
- return "\uF093";
- case GamepadButtonFlagsExt.B:
- return "\uF094";
- case GamepadButtonFlagsExt.Y:
- return "\uF095";
- case GamepadButtonFlagsExt.X:
- return "\uF096";
- case GamepadButtonFlagsExt.DPadRight:
- case GamepadButtonFlagsExt.DPadDown:
- case GamepadButtonFlagsExt.DPadUp:
- case GamepadButtonFlagsExt.DPadLeft:
- return "\uF10E";
- case GamepadButtonFlagsExt.LeftTrigger:
- return "\uF10A";
- case GamepadButtonFlagsExt.RightTrigger:
- return "\uF10B";
- case GamepadButtonFlagsExt.LeftShoulder:
- return "\uF10C";
- case GamepadButtonFlagsExt.RightShoulder:
- return "\uF10D";
- case GamepadButtonFlagsExt.LeftThumb:
- return "\uF108";
- case GamepadButtonFlagsExt.RightThumb:
- return "\uF109";
- case GamepadButtonFlagsExt.Start:
- return "\uEDE3";
- case GamepadButtonFlagsExt.Back:
- return "\uEECA";
- default:
- return "\uE783";
- }
- }
-
public static float Clamp(float value, float min, float max)
{
return Math.Min(max, Math.Max(min, value));
diff --git a/ControllerCommon/Utils/ProcessUtils.cs b/ControllerCommon/Utils/ProcessUtils.cs
index 52ce15fad..335c24bee 100644
--- a/ControllerCommon/Utils/ProcessUtils.cs
+++ b/ControllerCommon/Utils/ProcessUtils.cs
@@ -16,6 +16,7 @@
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Windows.System.Diagnostics;
+using Point = System.Windows.Point;
namespace ControllerCommon.Utils
{
@@ -56,6 +57,10 @@ public enum BinaryType : uint
[DllImport("User32.dll")]
public static extern bool ShowWindow(IntPtr handle, int nCmdShow);
+ [DllImport("user32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
+
[DllImport("User32.dll")]
public static extern bool IsIconic(IntPtr handle);
@@ -79,12 +84,29 @@ public interface ITipInvocation
[DllImport("ntdll.dll", EntryPoint = "NtResumeProcess", SetLastError = true, ExactSpelling = false)]
public static extern UIntPtr NtResumeProcess(IntPtr processHandle);
-
- public const int SW_RESTORE = 9;
- public const int SW_MAXIMIZE = 3;
- public const int SW_MINIMIZE = 2;
#endregion
+ [Serializable]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct WINDOWPLACEMENT
+ {
+ public int length;
+ public int flags;
+ public ShowWindowCommands showCmd;
+ public Point ptMinPosition;
+ public Point ptMaxPosition;
+ public Rectangle rcNormalPosition;
+ }
+
+ public enum ShowWindowCommands : int
+ {
+ Hide = 0,
+ Normal = 1,
+ Minimized = 2,
+ Maximized = 3,
+ Restored = 9
+ }
+
public class FindHostedProcess
{
// Speical handling needs for UWP to get the child window process
@@ -210,6 +232,14 @@ public static List GetChildIds(Process process)
.Select(mo => Convert.ToInt32(mo["ProcessID"]))
.ToList();
}
+
+ public static WINDOWPLACEMENT GetPlacement(IntPtr hwnd)
+ {
+ WINDOWPLACEMENT placement = new WINDOWPLACEMENT();
+ placement.length = Marshal.SizeOf(placement);
+ GetWindowPlacement(hwnd, ref placement);
+ return placement;
+ }
}
public static class IconUtilities
diff --git a/ControllerCommon/Utils/RegistryUtils.cs b/ControllerCommon/Utils/RegistryUtils.cs
new file mode 100644
index 000000000..6c2a70320
--- /dev/null
+++ b/ControllerCommon/Utils/RegistryUtils.cs
@@ -0,0 +1,21 @@
+using Microsoft.Win32;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Media.Animation;
+
+namespace ControllerCommon.Utils
+{
+ public static class RegistryUtils
+ {
+ private const string HKLM = @"HKEY_LOCAL_MACHINE";
+
+ public static string GetHKLM(string key, string value)
+ {
+ string keyName = HKLM + "\\" + key;
+ return Convert.ToString(Registry.GetValue(keyName, value, string.Empty));
+ }
+ }
+}
diff --git a/ControllerCommon/hidapi.dll b/ControllerCommon/hidapi.dll
new file mode 100644
index 000000000..02145e5d0
Binary files /dev/null and b/ControllerCommon/hidapi.dll differ
diff --git a/ControllerCommon/hidapi.net.dll b/ControllerCommon/hidapi.net.dll
new file mode 100644
index 000000000..aa95eaef6
Binary files /dev/null and b/ControllerCommon/hidapi.net.dll differ
diff --git a/ControllerService/ControllerService.cs b/ControllerService/ControllerService.cs
index 9bb8fa1cf..b33131caf 100644
--- a/ControllerService/ControllerService.cs
+++ b/ControllerService/ControllerService.cs
@@ -6,7 +6,6 @@
using Microsoft.Extensions.Hosting;
using Nefarius.Utilities.DeviceManagement.PnP;
using Nefarius.ViGEm.Client;
-using SharpDX.XInput;
using System;
using System.Collections.Generic;
using System.Configuration;
@@ -25,30 +24,23 @@ namespace ControllerService
public class ControllerService : IHostedService
{
// controllers vars
- private ViGEmClient VirtualClient;
- private ViGEmTarget VirtualTarget;
- public XInputController XInputController;
+ public static ViGEmClient vClient;
+ public static ViGEmTarget vTarget;
- private PipeServer pipeServer;
private DSUServer DSUServer;
- public HidHide Hidder;
// devices vars
public static Device handheldDevice;
- private UserIndex HIDidx;
- private string deviceInstancePath;
- private string baseContainerDeviceInstancePath;
public static string CurrentExe, CurrentPath, CurrentPathDep;
public static string CurrentTag;
public static int CurrentOverlayStatus = 2;
// settings vars
- Configuration configuration;
+ public Configuration configuration;
private string DSUip;
- private bool HIDcloaked, HIDuncloakonclose, DSUEnabled;
+ private bool DSUEnabled;
private int DSUport;
- private double HIDstrength;
private HIDmode HIDmode = HIDmode.NoController;
private HIDstatus HIDstatus = HIDstatus.Disconnected;
@@ -75,27 +67,21 @@ public ControllerService(IHostApplicationLifetime lifetime)
// todo: move me to a specific class
configuration = ConfigurationManager.OpenExeConfiguration("ControllerService.exe");
- HIDcloaked = bool.Parse(configuration.AppSettings.Settings["HIDcloaked"].Value);
- HIDuncloakonclose = bool.Parse(configuration.AppSettings.Settings["HIDuncloakonclose"].Value);
HIDmode = Enum.Parse(configuration.AppSettings.Settings["HIDmode"].Value);
HIDstatus = Enum.Parse(configuration.AppSettings.Settings["HIDstatus"].Value);
+
DSUEnabled = bool.Parse(configuration.AppSettings.Settings["DSUEnabled"].Value);
DSUip = configuration.AppSettings.Settings["DSUip"].Value;
DSUport = int.Parse(configuration.AppSettings.Settings["DSUport"].Value);
- HIDstrength = double.Parse(configuration.AppSettings.Settings["HIDstrength"].Value);
SensorSelection = Enum.Parse(configuration.AppSettings.Settings["SensorSelection"].Value);
SensorPlacement = int.Parse(configuration.AppSettings.Settings["SensorPlacement"].Value);
SensorPlacementUpsideDown = bool.Parse(configuration.AppSettings.Settings["SensorPlacementUpsideDown"].Value);
- HIDidx = Enum.Parse(configuration.AppSettings.Settings["HIDidx"].Value);
- deviceInstancePath = configuration.AppSettings.Settings["deviceInstancePath"].Value;
- baseContainerDeviceInstancePath = configuration.AppSettings.Settings["baseContainerDeviceInstancePath"].Value;
-
// verifying ViGEm is installed
try
{
- VirtualClient = new ViGEmClient();
+ vClient = new ViGEmClient();
}
catch (Exception)
{
@@ -104,31 +90,25 @@ public ControllerService(IHostApplicationLifetime lifetime)
}
// initialize HidHide
- Hidder = new HidHide();
- Hidder.RegisterApplication(CurrentExe);
+ HidHide.RegisterApplication(CurrentExe);
// initialize PipeServer
- pipeServer = new PipeServer("ControllerService");
- pipeServer.Connected += OnClientConnected;
- pipeServer.Disconnected += OnClientDisconnected;
- pipeServer.ClientMessage += OnClientMessage;
+ PipeServer.Initialize("ControllerService");
+ PipeServer.Connected += OnClientConnected;
+ PipeServer.Disconnected += OnClientDisconnected;
+ PipeServer.ClientMessage += OnClientMessage;
// initialize manager(s)
- SystemManager.SerialArrived += SystemManager_SerialArrived;
- SystemManager.SerialRemoved += SystemManager_SerialRemoved;
+ SystemManager.GenericDeviceArrived += GenericDeviceArrived;
+ SystemManager.GenericDeviceRemoved += GenericDeviceRemoved;
SystemManager.Start();
- SystemManager_SerialArrived(null);
+ GenericDeviceArrived(null);
// initialize device
handheldDevice = Device.GetDefault();
// XInputController settings
- XInputController = new XInputController(SensorSelection, pipeServer);
- XInputController.SetVibrationStrength(HIDstrength);
- XInputController.Updated += OnTargetSubmited;
-
- // prepare physical controller
- SetControllerIdx(HIDidx, deviceInstancePath, baseContainerDeviceInstancePath);
+ IMU.Initialize(SensorSelection);
// initialize DSUClient
DSUServer = new DSUServer(DSUip, DSUport);
@@ -137,7 +117,7 @@ public ControllerService(IHostApplicationLifetime lifetime)
}
private SerialUSBIMU sensor;
- private void SystemManager_SerialArrived(PnPDevice device)
+ private void GenericDeviceArrived(PnPDevice device)
{
switch (SensorSelection)
{
@@ -151,13 +131,13 @@ private void SystemManager_SerialArrived(PnPDevice device)
sensor.Open();
sensor.SetSensorPlacement((SerialPlacement)SensorPlacement, SensorPlacementUpsideDown);
- XInputController?.UpdateSensors();
+ IMU.UpdateSensors();
}
break;
}
}
- private void SystemManager_SerialRemoved(PnPDevice device)
+ private void GenericDeviceRemoved(PnPDevice device)
{
switch (SensorSelection)
{
@@ -167,88 +147,40 @@ private void SystemManager_SerialRemoved(PnPDevice device)
break;
sensor.Close();
- XInputController?.UpdateSensors();
+ IMU.UpdateSensors();
}
break;
}
}
- private void SetControllerIdx(UserIndex idx, string deviceInstancePath, string baseContainerDeviceInstancePath)
- {
- ControllerEx controller = new ControllerEx(idx);
- controller.deviceInstancePath = deviceInstancePath;
- controller.baseContainerDeviceInstancePath = baseContainerDeviceInstancePath;
-
- XInputController.SetController(controller);
-
- if (!controller.IsConnected())
- {
- LogManager.LogWarning("No physical controller detected on UserIndex: {0}", idx);
- return;
- }
-
- if (this.deviceInstancePath == deviceInstancePath &&
- this.baseContainerDeviceInstancePath == baseContainerDeviceInstancePath)
- return;
-
- LogManager.LogInformation("Listening to physical controller on UserIndex: {0}", idx);
-
- // clear previous values
- List deviceInstancePaths = Hidder.GetRegisteredDevices();
-
- // exclude controller
- deviceInstancePaths.Remove(deviceInstancePath);
- deviceInstancePaths.Remove(baseContainerDeviceInstancePath);
-
- foreach (string instancePath in deviceInstancePaths)
- Hidder.UnregisterController(instancePath);
-
- // register controller
- Hidder.RegisterController(deviceInstancePath);
- Hidder.RegisterController(baseContainerDeviceInstancePath);
-
- // update variables
- this.HIDidx = idx;
- this.deviceInstancePath = deviceInstancePath;
- this.baseContainerDeviceInstancePath = baseContainerDeviceInstancePath;
-
- // update settings
- configuration.AppSettings.Settings["HIDidx"].Value = ((int)idx).ToString();
- configuration.AppSettings.Settings["deviceInstancePath"].Value = deviceInstancePath;
- configuration.AppSettings.Settings["baseContainerDeviceInstancePath"].Value = baseContainerDeviceInstancePath;
- configuration.Save(ConfigurationSaveMode.Modified);
- }
-
private void SetControllerMode(HIDmode mode)
{
- if (HIDmode == mode && VirtualTarget != null)
+ if (HIDmode == mode && vTarget != null)
return;
// disconnect current virtual controller
// todo: do not disconnect if similar to incoming mode
- VirtualTarget?.Disconnect();
+ vTarget?.Disconnect();
switch (mode)
{
default:
case HIDmode.NoController:
- VirtualTarget.Dispose();
- VirtualTarget = null;
- XInputController.DetachTarget();
+ vTarget.Dispose();
+ vTarget = null;
break;
case HIDmode.DualShock4Controller:
- VirtualTarget = new DualShock4Target(XInputController, VirtualClient);
+ vTarget = new DualShock4Target();
break;
case HIDmode.Xbox360Controller:
- VirtualTarget = new Xbox360Target(XInputController, VirtualClient);
+ vTarget = new Xbox360Target();
break;
}
- if (VirtualTarget != null)
+ if (vTarget != null)
{
- VirtualTarget.Connected += OnTargetConnected;
- VirtualTarget.Disconnected += OnTargetDisconnected;
- XInputController.AttachTarget(VirtualTarget);
+ vTarget.Connected += OnTargetConnected;
+ vTarget.Disconnected += OnTargetDisconnected;
}
// update status
@@ -260,17 +192,17 @@ private void SetControllerMode(HIDmode mode)
private void SetControllerStatus(HIDstatus status)
{
- if (VirtualTarget == null)
+ if (vTarget == null)
return;
switch (status)
{
default:
case HIDstatus.Connected:
- VirtualTarget.Connect();
+ vTarget.Connect();
break;
case HIDstatus.Disconnected:
- VirtualTarget.Disconnect();
+ vTarget.Disconnect();
break;
}
@@ -281,7 +213,7 @@ private void SetControllerStatus(HIDstatus status)
private void OnTargetDisconnected(ViGEmTarget target)
{
// send notification
- pipeServer?.SendMessage(new PipeServerToast
+ PipeServer.SendMessage(new PipeServerToast
{
title = $"{target}",
content = Properties.Resources.ToastOnTargetDisconnected,
@@ -292,7 +224,7 @@ private void OnTargetDisconnected(ViGEmTarget target)
private void OnTargetConnected(ViGEmTarget target)
{
// send notification
- pipeServer?.SendMessage(new PipeServerToast
+ PipeServer.SendMessage(new PipeServerToast
{
title = $"{target}",
content = Properties.Resources.ToastOnTargetConnected,
@@ -300,11 +232,6 @@ private void OnTargetConnected(ViGEmTarget target)
});
}
- private void OnTargetSubmited(XInputController controller)
- {
- DSUServer?.SubmitReport(controller);
- }
-
// deprecated
private void OnDSUStopped(DSUServer server)
{
@@ -325,17 +252,12 @@ private void OnDSUStarted(DSUServer server)
pipeServer.SendMessage(settings); */
}
- private void OnClientMessage(object sender, PipeMessage message)
+ private void OnClientMessage(PipeMessage message)
{
switch (message.code)
{
- case PipeCode.CLIENT_CONTROLLERINDEX:
- PipeControllerIndex pipeControllerIndex = (PipeControllerIndex)message;
- SetControllerIdx((UserIndex)pipeControllerIndex.UserIndex, pipeControllerIndex.deviceInstancePath, pipeControllerIndex.baseContainerDeviceInstancePath);
- break;
-
case PipeCode.FORCE_SHUTDOWN:
- Hidder?.SetCloaking(false, XInputController.ProductName);
+ HidHide.SetCloaking(false);
break;
case PipeCode.CLIENT_PROFILE:
@@ -349,13 +271,13 @@ private void OnClientMessage(object sender, PipeMessage message)
switch (cursor.action)
{
case CursorAction.CursorUp:
- XInputController.Touch.OnMouseUp(cursor.x, cursor.y, cursor.button, cursor.flags);
+ DS4Touch.OnMouseUp(cursor.x, cursor.y, cursor.button, cursor.flags);
break;
case CursorAction.CursorDown:
- XInputController.Touch.OnMouseDown(cursor.x, cursor.y, cursor.button, cursor.flags);
+ DS4Touch.OnMouseDown(cursor.x, cursor.y, cursor.button, cursor.flags);
break;
case CursorAction.CursorMove:
- XInputController.Touch.OnMouseMove(cursor.x, cursor.y, cursor.button, cursor.flags);
+ DS4Touch.OnMouseMove(cursor.x, cursor.y, cursor.button, cursor.flags);
break;
}
break;
@@ -365,20 +287,6 @@ private void OnClientMessage(object sender, PipeMessage message)
UpdateSettings(settings.settings);
break;
- case PipeCode.CLIENT_HIDDER:
- PipeClientHidder hidder = (PipeClientHidder)message;
-
- switch (hidder.action)
- {
- case HidderAction.Register:
- Hidder.RegisterApplication(hidder.path);
- break;
- case HidderAction.Unregister:
- Hidder.UnregisterApplication(hidder.path);
- break;
- }
- break;
-
case PipeCode.CLIENT_NAVIGATED:
PipeNavigation navigation = (PipeNavigation)message;
CurrentTag = navigation.Tag;
@@ -404,21 +312,23 @@ private void OnClientMessage(object sender, PipeMessage message)
case PipeCode.CLIENT_INPUT:
PipeClientInput input = (PipeClientInput)message;
- VirtualTarget?.InjectReport((GamepadButtonFlagsExt)input.Buttons, input.sButtons, input.IsKeyDown, input.IsKeyUp);
+
+ vTarget?.UpdateInputs(input.Inputs);
+ DSUServer.UpdateInputs(input.Inputs);
break;
}
}
- private void OnClientDisconnected(object sender)
+ private void OnClientDisconnected()
{
- XInputController.Touch.OnMouseUp(0, 0, CursorButton.TouchLeft, 26);
- XInputController.Touch.OnMouseUp(0, 0, CursorButton.TouchRight, 26);
+ DS4Touch.OnMouseUp(0, 0, CursorButton.TouchLeft, 26);
+ DS4Touch.OnMouseUp(0, 0, CursorButton.TouchRight, 26);
}
- private void OnClientConnected(object sender)
+ private void OnClientConnected()
{
// send server settings
- pipeServer.SendMessage(new PipeServerSettings() { settings = GetSettings() });
+ PipeServer.SendMessage(new PipeServerSettings() { settings = GetSettings() });
}
internal void ProfileUpdated(Profile profile, bool backgroundtask)
@@ -463,19 +373,6 @@ private void ApplySetting(string name, string property)
{
switch (name)
{
- case "HIDcloaked":
- {
- bool value = bool.Parse(property);
- Hidder.SetCloaking(value, XInputController.ProductName);
- HIDcloaked = value;
- }
- break;
- case "HIDuncloakonclose":
- {
- bool value = bool.Parse(property);
- HIDuncloakonclose = value;
- }
- break;
case "HIDmode":
{
HIDmode value = Enum.Parse(property);
@@ -488,12 +385,6 @@ private void ApplySetting(string name, string property)
SetControllerStatus(value);
}
break;
- case "HIDstrength":
- {
- double value = double.Parse(property);
- XInputController.SetVibrationStrength(value);
- }
- break;
case "DSUEnabled":
{
bool value = bool.Parse(property);
@@ -542,19 +433,17 @@ private void ApplySetting(string name, string property)
public Task StartAsync(CancellationToken cancellationToken)
{
// start listening to controller
- XInputController.StartListening();
-
- // turn on cloaking
- Hidder.SetCloaking(HIDcloaked, XInputController.ProductName);
+ IMU.StartListening();
// start DSUClient
- if (DSUEnabled) DSUServer.Start();
+ if (DSUEnabled)
+ DSUServer.Start();
// update virtual controller
SetControllerMode(HIDmode);
// start Pipe Server
- pipeServer.Open();
+ PipeServer.Open();
// listen to system events
SystemManager.SystemStatusChanged += OnSystemStatusChanged;
@@ -568,10 +457,7 @@ public Task StartAsync(CancellationToken cancellationToken)
public Task StopAsync(CancellationToken cancellationToken)
{
// stop listening from controller
- XInputController.StopListening();
-
- // turn off cloaking
- Hidder?.SetCloaking(!HIDuncloakonclose, XInputController.ProductName);
+ IMU.StopListening();
// update virtual controller
SetControllerMode(HIDmode.NoController);
@@ -583,7 +469,7 @@ public Task StopAsync(CancellationToken cancellationToken)
DSUServer?.Stop();
// stop Pipe Server
- pipeServer?.Close();
+ PipeServer.Close();
// stop System Manager
SystemManager.Stop();
@@ -603,24 +489,21 @@ private async void OnSystemStatusChanged(SystemStatus status)
await Task.Delay(4000);
// (re)initialize sensors
- XInputController?.UpdateSensors();
- XInputController?.StartListening();
+ IMU.UpdateSensors();
// (re)initialize ViGEm
- VirtualClient = new ViGEmClient();
+ vClient = new ViGEmClient();
SetControllerMode(HIDmode);
}
break;
case SystemStatus.Unready:
{
- XInputController?.StopListening();
-
- VirtualTarget.Dispose();
- VirtualTarget = null;
+ vTarget.Dispose();
+ vTarget = null;
- VirtualClient.Dispose();
- VirtualClient = null;
+ vClient.Dispose();
+ vClient = null;
}
break;
}
diff --git a/ControllerService/ControllerService.csproj b/ControllerService/ControllerService.csproj
index 2faa5bf5b..9f909b07d 100644
--- a/ControllerService/ControllerService.csproj
+++ b/ControllerService/ControllerService.csproj
@@ -33,8 +33,8 @@
-
-
+
+
all
@@ -46,10 +46,10 @@
-
+
-
+
diff --git a/ControllerService/DS4Touch.cs b/ControllerService/DS4Touch.cs
index 3331b7a6a..81218295d 100644
--- a/ControllerService/DS4Touch.cs
+++ b/ControllerService/DS4Touch.cs
@@ -2,7 +2,7 @@
namespace ControllerService
{
- public class DS4Touch
+ public static class DS4Touch
{
private const int TOUCHPAD_WIDTH = 1920;
private const int TOUCHPAD_HEIGHT = 943;
@@ -11,32 +11,31 @@ public class DS4Touch
private const int TOUCH1_ID = 2;
private const int TOUCH_DISABLE = 128;
- public struct TrackPadTouch
+ public class TrackPadTouch
{
public bool IsActive;
public byte Id;
public short X;
public short Y;
public int RawTrackingNum;
- }
- public TrackPadTouch TrackPadTouch1;
- public TrackPadTouch TrackPadTouch2;
- public byte TouchPacketCounter = 0;
+ public TrackPadTouch(byte _Id)
+ {
+ this.Id = _Id;
+ this.RawTrackingNum |= _Id + TOUCH_DISABLE;
+ }
+ }
- private short TouchX, TouchY;
- public bool OutputClickButton;
+ public static TrackPadTouch TrackPadTouch1 = new(TOUCH0_ID);
+ public static TrackPadTouch TrackPadTouch2 = new(TOUCH1_ID);
+ public static byte TouchPacketCounter = 0;
- private float BoundsWidth, BoundsHeight;
+ private static short TouchX, TouchY;
+ public static bool OutputClickButton;
- public DS4Touch()
- {
- // default values
- TrackPadTouch1.RawTrackingNum |= TOUCH0_ID + TOUCH_DISABLE;
- TrackPadTouch2.RawTrackingNum |= TOUCH1_ID + TOUCH_DISABLE;
- }
+ private static float BoundsWidth, BoundsHeight;
- public void OnMouseUp(double X, double Y, CursorButton Button, int flags = 20)
+ public static void OnMouseUp(double X, double Y, CursorButton Button, int flags = 20)
{
TouchX = (short)(X * TOUCHPAD_WIDTH);
TouchY = (short)(Y * TOUCHPAD_HEIGHT);
@@ -58,7 +57,7 @@ public void OnMouseUp(double X, double Y, CursorButton Button, int flags = 20)
OutputClickButton = false;
}
- public void OnMouseDown(double X, double Y, CursorButton Button, int flags = 20)
+ public static void OnMouseDown(double X, double Y, CursorButton Button, int flags = 20)
{
TouchX = (short)(X * TOUCHPAD_WIDTH);
TouchY = (short)(Y * TOUCHPAD_HEIGHT);
@@ -83,7 +82,7 @@ public void OnMouseDown(double X, double Y, CursorButton Button, int flags = 20)
TouchPacketCounter++;
}
- public void OnMouseMove(double X, double Y, CursorButton Button, int flags = 20)
+ public static void OnMouseMove(double X, double Y, CursorButton Button, int flags = 20)
{
TouchX = (short)(X * TOUCHPAD_WIDTH);
TouchY = (short)(Y * TOUCHPAD_HEIGHT);
diff --git a/ControllerService/DSUServer.cs b/ControllerService/DSUServer.cs
index 2a2495cbb..47e0a9bde 100644
--- a/ControllerService/DSUServer.cs
+++ b/ControllerService/DSUServer.cs
@@ -1,7 +1,9 @@
+using ControllerCommon.Controllers;
using ControllerCommon.Managers;
using ControllerCommon.Utils;
using ControllerService.Sensors;
using Force.Crc32;
+using PrecisionTiming;
using System;
using System.Collections.Generic;
using System.ComponentModel;
@@ -10,10 +12,7 @@
using System.Net.Sockets;
using System.Numerics;
using System.Threading;
-using System.Timers;
using System.Windows.Forms;
-using GamepadButtonFlags = SharpDX.XInput.GamepadButtonFlags;
-using Timer = System.Timers.Timer;
namespace ControllerService
{
@@ -92,7 +91,13 @@ public class DSUServer
public delegate void GetPadDetail(int padIdx, ref DualShockPadMeta meta);
private GetPadDetail portInfoGet;
- private Timer BatteryTimer;
+
+ public PrecisionTimer UpdateTimer;
+ private PrecisionTimer BatteryTimer;
+
+ private ControllerInput Inputs = new();
+
+ public const int UpdateInterval = 5;
void GetPadDetailForIdx(int padIdx, ref DualShockPadMeta meta)
{
@@ -141,8 +146,14 @@ public DSUServer(string ipString, int port)
argsList[num] = args;
}
- BatteryTimer = new Timer(1000) { Enabled = false, AutoReset = true };
- BatteryTimer.Elapsed += UpdateBattery;
+ BatteryTimer = new PrecisionTimer();
+ BatteryTimer.SetInterval(1000);
+ BatteryTimer.SetAutoResetMode(true);
+
+ // initialize timers
+ UpdateTimer = new PrecisionTimer();
+ UpdateTimer.SetInterval(UpdateInterval);
+ UpdateTimer.SetAutoResetMode(true);
}
public override string ToString()
@@ -150,7 +161,7 @@ public override string ToString()
return this.GetType().Name;
}
- private void UpdateBattery(object sender, ElapsedEventArgs e)
+ private void UpdateBattery(object sender, EventArgs e)
{
if (!running)
return;
@@ -519,11 +530,14 @@ public bool Start()
new Random().NextBytes(randomBuf);
serverId = BitConverter.ToUInt32(randomBuf, 0);
+ UpdateTimer.Tick += SubmitReport;
+ BatteryTimer.Tick += UpdateBattery;
+
running = true;
- StartReceive();
- BatteryTimer.Enabled = true;
+ UpdateTimer.Start();
BatteryTimer.Start();
+ StartReceive();
LogManager.LogInformation("{0} has started. Listening to ip: {1} port: {2}", this.ToString(), ip, port);
Started?.Invoke(this);
@@ -540,74 +554,85 @@ public void Stop()
}
running = false;
+ UpdateTimer.Tick -= SubmitReport;
+ BatteryTimer.Tick -= UpdateBattery;
+
+ UpdateTimer.Stop();
+ BatteryTimer.Stop();
+
LogManager.LogInformation($"{0} has stopped", this.ToString());
Stopped?.Invoke(this);
}
- private bool ReportToBuffer(XInputController hidReport, byte[] outputData, long microseconds, ref int outIdx)
+ public void UpdateInputs(ControllerInput inputs)
+ {
+ Inputs = inputs;
+ }
+
+ private bool ReportToBuffer(byte[] outputData, ref int outIdx)
{
unchecked
{
outputData[outIdx] = 0;
- if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadLeft)) outputData[outIdx] |= 0x80;
- if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadDown)) outputData[outIdx] |= 0x40;
- if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadRight)) outputData[outIdx] |= 0x20;
- if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadUp)) outputData[outIdx] |= 0x10;
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadLeft)) outputData[outIdx] |= 0x80;
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadDown)) outputData[outIdx] |= 0x40;
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadRight)) outputData[outIdx] |= 0x20;
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadUp)) outputData[outIdx] |= 0x10;
- if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.Start)) outputData[outIdx] |= 0x08;
- if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.RightThumb)) outputData[outIdx] |= 0x04;
- if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.LeftThumb)) outputData[outIdx] |= 0x02;
- if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.Back)) outputData[outIdx] |= 0x01;
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.Start)) outputData[outIdx] |= 0x08;
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.RightThumb)) outputData[outIdx] |= 0x04;
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.LeftThumb)) outputData[outIdx] |= 0x02;
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.Back)) outputData[outIdx] |= 0x01;
outputData[++outIdx] = 0;
- if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.X)) outputData[outIdx] |= 0x80;
- if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.A)) outputData[outIdx] |= 0x40;
- if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.B)) outputData[outIdx] |= 0x20;
- if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.Y)) outputData[outIdx] |= 0x10;
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.B1)) outputData[outIdx] |= 0x40;
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.B2)) outputData[outIdx] |= 0x20;
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.B3)) outputData[outIdx] |= 0x80;
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.B4)) outputData[outIdx] |= 0x10;
- if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.RightShoulder)) outputData[outIdx] |= 0x08;
- if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.LeftShoulder)) outputData[outIdx] |= 0x04;
- if (hidReport.Gamepad.RightTrigger == byte.MaxValue) outputData[outIdx] |= 0x02;
- if (hidReport.Gamepad.LeftTrigger == byte.MaxValue) outputData[outIdx] |= 0x01;
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.RightShoulder)) outputData[outIdx] |= 0x08;
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.LeftShoulder)) outputData[outIdx] |= 0x04;
+ if (Inputs.RightTrigger == byte.MaxValue) outputData[outIdx] |= 0x02;
+ if (Inputs.LeftTrigger == byte.MaxValue) outputData[outIdx] |= 0x01;
- outputData[++outIdx] = (byte)0; // (hidReport.PS) ? (byte)1 :
- outputData[++outIdx] = (byte)0; // (hidReport.TouchButton) ? (byte)1 :
+ outputData[++outIdx] = Convert.ToByte(Inputs.Buttons.HasFlag(ControllerButtonFlags.Special)); // (hidReport.PS) ? (byte)1 :
+ outputData[++outIdx] = Convert.ToByte(DS4Touch.OutputClickButton); // (hidReport.TouchButton) ? (byte)1 :
//Left stick
- outputData[++outIdx] = InputUtils.NormalizeXboxInput(hidReport.Gamepad.LeftThumbX);
- outputData[++outIdx] = InputUtils.NormalizeXboxInput(hidReport.Gamepad.LeftThumbY);
+ outputData[++outIdx] = InputUtils.NormalizeXboxInput(Inputs.LeftThumbX);
+ outputData[++outIdx] = InputUtils.NormalizeXboxInput(Inputs.LeftThumbY);
outputData[outIdx] = (byte)(byte.MaxValue - outputData[outIdx]); //invert Y by convention
//Right stick
- outputData[++outIdx] = InputUtils.NormalizeXboxInput(hidReport.Gamepad.RightThumbX);
- outputData[++outIdx] = InputUtils.NormalizeXboxInput(hidReport.Gamepad.RightThumbY);
+ outputData[++outIdx] = InputUtils.NormalizeXboxInput(Inputs.RightThumbX);
+ outputData[++outIdx] = InputUtils.NormalizeXboxInput(Inputs.RightThumbY);
outputData[outIdx] = (byte)(byte.MaxValue - outputData[outIdx]); //invert Y by convention
//we don't have analog buttons on DS4 :(
- outputData[++outIdx] = hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadLeft) ? (byte)0xFF : (byte)0x00;
- outputData[++outIdx] = hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadDown) ? (byte)0xFF : (byte)0x00;
- outputData[++outIdx] = hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadRight) ? (byte)0xFF : (byte)0x00;
- outputData[++outIdx] = hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadUp) ? (byte)0xFF : (byte)0x00;
+ outputData[++outIdx] = Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadLeft) ? (byte)0xFF : (byte)0x00;
+ outputData[++outIdx] = Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadDown) ? (byte)0xFF : (byte)0x00;
+ outputData[++outIdx] = Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadRight) ? (byte)0xFF : (byte)0x00;
+ outputData[++outIdx] = Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadUp) ? (byte)0xFF : (byte)0x00;
- outputData[++outIdx] = hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.X) ? (byte)0xFF : (byte)0x00;
- outputData[++outIdx] = hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.A) ? (byte)0xFF : (byte)0x00;
- outputData[++outIdx] = hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.B) ? (byte)0xFF : (byte)0x00;
- outputData[++outIdx] = hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.Y) ? (byte)0xFF : (byte)0x00;
+ outputData[++outIdx] = Inputs.Buttons.HasFlag(ControllerButtonFlags.B1) ? (byte)0xFF : (byte)0x00;
+ outputData[++outIdx] = Inputs.Buttons.HasFlag(ControllerButtonFlags.B2) ? (byte)0xFF : (byte)0x00;
+ outputData[++outIdx] = Inputs.Buttons.HasFlag(ControllerButtonFlags.B3) ? (byte)0xFF : (byte)0x00;
+ outputData[++outIdx] = Inputs.Buttons.HasFlag(ControllerButtonFlags.B4) ? (byte)0xFF : (byte)0x00;
- outputData[++outIdx] = hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.RightShoulder) ? (byte)0xFF : (byte)0x00;
- outputData[++outIdx] = hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.LeftShoulder) ? (byte)0xFF : (byte)0x00;
+ outputData[++outIdx] = Inputs.Buttons.HasFlag(ControllerButtonFlags.RightShoulder) ? (byte)0xFF : (byte)0x00;
+ outputData[++outIdx] = Inputs.Buttons.HasFlag(ControllerButtonFlags.LeftShoulder) ? (byte)0xFF : (byte)0x00;
- outputData[++outIdx] = hidReport.Gamepad.RightTrigger;
- outputData[++outIdx] = hidReport.Gamepad.LeftTrigger;
+ outputData[++outIdx] = (byte)Inputs.RightTrigger;
+ outputData[++outIdx] = (byte)Inputs.LeftTrigger;
outIdx++;
//DS4 only: touchpad points
for (int i = 0; i < 2; i++)
{
- var tpad = (i == 0) ? hidReport.Touch.TrackPadTouch1 : hidReport.Touch.TrackPadTouch2;
+ var tpad = (i == 0) ? DS4Touch.TrackPadTouch1 : DS4Touch.TrackPadTouch2;
outputData[outIdx++] = tpad.IsActive ? (byte)1 : (byte)0;
outputData[outIdx++] = (byte)tpad.RawTrackingNum;
@@ -618,21 +643,21 @@ private bool ReportToBuffer(XInputController hidReport, byte[] outputData, long
}
//motion timestamp
- Array.Copy(BitConverter.GetBytes((ulong)hidReport.CurrentMicroseconds), 0, outputData, outIdx, 8);
+ Array.Copy(BitConverter.GetBytes((ulong)IMU.CurrentMicroseconds), 0, outputData, outIdx, 8);
outIdx += 8;
//accelerometer
- if (hidReport.Accelerations[XInputSensorFlags.Default] != empty)
+ if (IMU.Acceleration[XInputSensorFlags.Default] != empty)
{
// accelXG
- Array.Copy(BitConverter.GetBytes(hidReport.Accelerations[XInputSensorFlags.Default].X), 0, outputData, outIdx, 4);
+ Array.Copy(BitConverter.GetBytes(IMU.Acceleration[XInputSensorFlags.Default].X), 0, outputData, outIdx, 4);
outIdx += 4;
// accelYG
- Array.Copy(BitConverter.GetBytes(hidReport.Accelerations[XInputSensorFlags.Default].Y), 0, outputData, outIdx, 4);
+ Array.Copy(BitConverter.GetBytes(IMU.Acceleration[XInputSensorFlags.Default].Y), 0, outputData, outIdx, 4);
outIdx += 4;
// accelZG
- Array.Copy(BitConverter.GetBytes(-hidReport.Accelerations[XInputSensorFlags.Default].Z), 0, outputData, outIdx, 4);
+ Array.Copy(BitConverter.GetBytes(-IMU.Acceleration[XInputSensorFlags.Default].Z), 0, outputData, outIdx, 4);
outIdx += 4;
}
else
@@ -642,16 +667,16 @@ private bool ReportToBuffer(XInputController hidReport, byte[] outputData, long
}
//gyroscope
- if (hidReport.AngularVelocities[XInputSensorFlags.CenteredRatio] != empty)
+ if (IMU.AngularVelocity[XInputSensorFlags.CenteredRatio] != empty)
{
// angVelPitch
- Array.Copy(BitConverter.GetBytes(hidReport.AngularVelocities[XInputSensorFlags.CenteredRatio].X), 0, outputData, outIdx, 4);
+ Array.Copy(BitConverter.GetBytes(IMU.AngularVelocity[XInputSensorFlags.CenteredRatio].X), 0, outputData, outIdx, 4);
outIdx += 4;
// angVelYaw
- Array.Copy(BitConverter.GetBytes(hidReport.AngularVelocities[XInputSensorFlags.CenteredRatio].Y), 0, outputData, outIdx, 4);
+ Array.Copy(BitConverter.GetBytes(IMU.AngularVelocity[XInputSensorFlags.CenteredRatio].Y), 0, outputData, outIdx, 4);
outIdx += 4;
// angVelRoll
- Array.Copy(BitConverter.GetBytes(-hidReport.AngularVelocities[XInputSensorFlags.CenteredRatio].Z), 0, outputData, outIdx, 4);
+ Array.Copy(BitConverter.GetBytes(-IMU.AngularVelocity[XInputSensorFlags.CenteredRatio].Z), 0, outputData, outIdx, 4);
outIdx += 4;
}
else
@@ -664,13 +689,13 @@ private bool ReportToBuffer(XInputController hidReport, byte[] outputData, long
return true;
}
- public void SubmitReport(XInputController hidReport)
+ public void SubmitReport(object sender, EventArgs e)
{
if (!running)
return;
// update status
- padMeta.IsActive = hidReport.controllerEx.IsConnected();
+ padMeta.IsActive = true; // fixme ?
var clientsList = new List();
var now = DateTime.UtcNow;
@@ -757,7 +782,7 @@ public void SubmitReport(XInputController hidReport)
Array.Copy(BitConverter.GetBytes((uint)udpPacketCount++), 0, outputData, outIdx, 4);
outIdx += 4;
- if (!ReportToBuffer(hidReport, outputData, hidReport.CurrentMicroseconds, ref outIdx))
+ if (!ReportToBuffer(outputData, ref outIdx))
return;
else
FinishPacket(outputData);
diff --git a/ControllerService/IMU.cs b/ControllerService/IMU.cs
new file mode 100644
index 000000000..5e9c35a46
--- /dev/null
+++ b/ControllerService/IMU.cs
@@ -0,0 +1,178 @@
+using ControllerCommon;
+using ControllerCommon.Utils;
+using ControllerService.Sensors;
+using PrecisionTiming;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Numerics;
+using System.Threading;
+using System.Threading.Tasks;
+using static ControllerCommon.Utils.DeviceUtils;
+
+namespace ControllerService
+{
+ public static class IMU
+ {
+ public static Dictionary Acceleration = new();
+ public static Dictionary AngularVelocity = new();
+ public static Vector3 IMU_Angle = new();
+
+ public static PrecisionTimer UpdateTimer;
+ public const int UpdateInterval = 10;
+
+ private static SensorFamily SensorFamily = SensorFamily.None;
+ public static IMUGyrometer Gyrometer;
+ public static IMUAccelerometer Accelerometer;
+ public static IMUInclinometer Inclinometer;
+
+ public static SensorFusion sensorFusion;
+ public static MadgwickAHRS madgwickAHRS;
+
+ public static Stopwatch stopwatch;
+ public static long CurrentMicroseconds;
+
+ public static double TotalMilliseconds;
+ public static double UpdateTimePreviousMilliseconds;
+ public static double DeltaSeconds = 100.0d;
+
+ public static event UpdatedEventHandler Updated;
+ public delegate void UpdatedEventHandler();
+
+ private static object updateLock = new();
+
+ public static void Initialize(SensorFamily sensorFamily)
+ {
+ // initialize sensorfusion and madgwick
+ sensorFusion = new SensorFusion();
+ madgwickAHRS = new MadgwickAHRS(0.01f, 0.1f);
+
+ // initialize sensors
+ SensorFamily = sensorFamily;
+ Gyrometer = new IMUGyrometer(SensorFamily, UpdateInterval);
+ Accelerometer = new IMUAccelerometer(SensorFamily, UpdateInterval);
+ Inclinometer = new IMUInclinometer(SensorFamily, UpdateInterval);
+
+ // initialize stopwatch
+ stopwatch = new Stopwatch();
+
+ // initialize timers
+ UpdateTimer = new PrecisionTimer();
+ UpdateTimer.SetInterval(UpdateInterval);
+ UpdateTimer.SetAutoResetMode(true);
+ }
+
+ public static void StartListening()
+ {
+ stopwatch.Start();
+
+ UpdateTimer.Tick += ComputeMovements;
+ UpdateTimer.Start();
+ }
+
+ public static void StopListening()
+ {
+ Gyrometer.StopListening(SensorFamily);
+ Accelerometer.StopListening(SensorFamily);
+ Inclinometer.StopListening(SensorFamily);
+
+ UpdateTimer.Tick -= ComputeMovements;
+ UpdateTimer.Stop();
+
+ stopwatch.Stop();
+ }
+
+ public static void UpdateSensors()
+ {
+ Gyrometer.UpdateSensor(SensorFamily);
+ Accelerometer.UpdateSensor(SensorFamily);
+ Inclinometer.UpdateSensor(SensorFamily);
+ }
+
+ private static void ComputeMovements(object sender, EventArgs e)
+ {
+ if (Monitor.TryEnter(updateLock))
+ {
+ // update timestamp
+ CurrentMicroseconds = stopwatch.ElapsedMilliseconds * 1000L;
+ TotalMilliseconds = stopwatch.Elapsed.TotalMilliseconds;
+ DeltaSeconds = (TotalMilliseconds - UpdateTimePreviousMilliseconds) / 1000L;
+ UpdateTimePreviousMilliseconds = TotalMilliseconds;
+
+ // update reading(s)
+ foreach (XInputSensorFlags flags in (XInputSensorFlags[])Enum.GetValues(typeof(XInputSensorFlags)))
+ {
+ switch (flags)
+ {
+ case XInputSensorFlags.Default:
+ AngularVelocity[flags] = Gyrometer.GetCurrentReading();
+ Acceleration[flags] = Accelerometer.GetCurrentReading();
+ break;
+
+ case XInputSensorFlags.RawValue:
+ AngularVelocity[flags] = Gyrometer.GetCurrentReadingRaw();
+ Acceleration[flags] = Accelerometer.GetCurrentReadingRaw();
+ break;
+
+ case XInputSensorFlags.Centered:
+ AngularVelocity[flags] = Gyrometer.GetCurrentReading(true);
+ Acceleration[flags] = Accelerometer.GetCurrentReading(true);
+ break;
+
+ case XInputSensorFlags.WithRatio:
+ AngularVelocity[flags] = Gyrometer.GetCurrentReading(false, true);
+ Acceleration[flags] = Accelerometer.GetCurrentReading(false, false);
+ break;
+
+ case XInputSensorFlags.CenteredRatio:
+ AngularVelocity[flags] = Gyrometer.GetCurrentReading(true, true);
+ Acceleration[flags] = Accelerometer.GetCurrentReading(true, false);
+ break;
+
+ case XInputSensorFlags.CenteredRaw:
+ AngularVelocity[flags] = Gyrometer.GetCurrentReadingRaw(true);
+ Acceleration[flags] = Accelerometer.GetCurrentReadingRaw(true);
+ break;
+ }
+ }
+
+ IMU_Angle = Inclinometer.GetCurrentReading();
+
+ // update sensorFusion (todo: call only when needed ?)
+ sensorFusion.UpdateReport(TotalMilliseconds, DeltaSeconds, AngularVelocity[XInputSensorFlags.Centered], Acceleration[XInputSensorFlags.Default]);
+
+ // async update client(s)
+ Task.Run(() =>
+ {
+ switch (ControllerService.CurrentTag)
+ {
+ case "ProfileSettingsMode0":
+ PipeServer.SendMessage(new PipeSensor(AngularVelocity[XInputSensorFlags.Centered], SensorType.Girometer));
+ break;
+
+ case "ProfileSettingsMode1":
+ PipeServer.SendMessage(new PipeSensor(IMU_Angle, SensorType.Inclinometer));
+ break;
+ }
+
+ switch (ControllerService.CurrentOverlayStatus)
+ {
+ case 0: // Visible
+ var AngularVelocityRad = new Vector3();
+ AngularVelocityRad.X = -InputUtils.deg2rad(AngularVelocity[XInputSensorFlags.CenteredRaw].X);
+ AngularVelocityRad.Y = -InputUtils.deg2rad(AngularVelocity[XInputSensorFlags.CenteredRaw].Y);
+ AngularVelocityRad.Z = -InputUtils.deg2rad(AngularVelocity[XInputSensorFlags.CenteredRaw].Z);
+ madgwickAHRS.UpdateReport(AngularVelocityRad.X, AngularVelocityRad.Y, AngularVelocityRad.Z, -Acceleration[XInputSensorFlags.RawValue].X, Acceleration[XInputSensorFlags.RawValue].Y, Acceleration[XInputSensorFlags.RawValue].Z, DeltaSeconds);
+
+ PipeServer.SendMessage(new PipeSensor(madgwickAHRS.GetEuler(), madgwickAHRS.GetQuaternion(), SensorType.Quaternion));
+ break;
+ }
+ });
+
+ Updated?.Invoke();
+
+ Monitor.Exit(updateLock);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ControllerService/Sensors/XInputAccelerometer.cs b/ControllerService/Sensors/IMUAccelerometer.cs
similarity index 94%
rename from ControllerService/Sensors/XInputAccelerometer.cs
rename to ControllerService/Sensors/IMUAccelerometer.cs
index ff49eacae..103123a15 100644
--- a/ControllerService/Sensors/XInputAccelerometer.cs
+++ b/ControllerService/Sensors/IMUAccelerometer.cs
@@ -7,7 +7,7 @@
namespace ControllerService.Sensors
{
- public class XInputAccelerometer : XInputSensor
+ public class IMUAccelerometer : IMUSensor
{
public static SensorSpec sensorSpec = new SensorSpec()
{
@@ -17,7 +17,7 @@ public class XInputAccelerometer : XInputSensor
maxOut = short.MaxValue,
};
- public XInputAccelerometer(SensorFamily sensorFamily, int updateInterval) : base()
+ public IMUAccelerometer(SensorFamily sensorFamily, int updateInterval) : base()
{
this.updateInterval = updateInterval;
UpdateSensor(sensorFamily);
@@ -94,9 +94,9 @@ public void StopListening(SensorFamily sensorFamily)
private void ReadingChanged(Vector3 AccelerationG, Vector3 AngularVelocityDeg)
{
- this.reading.X = this.reading_fixed.X = (float)filter.axis1Filter.Filter(AccelerationG.X, XInputController.DeltaSeconds);
- this.reading.Y = this.reading_fixed.Y = (float)filter.axis2Filter.Filter(AccelerationG.Y, XInputController.DeltaSeconds);
- this.reading.Z = this.reading_fixed.Z = (float)filter.axis3Filter.Filter(AccelerationG.Z, XInputController.DeltaSeconds);
+ this.reading.X = this.reading_fixed.X = (float)filter.axis1Filter.Filter(AccelerationG.X, IMU.DeltaSeconds);
+ this.reading.Y = this.reading_fixed.Y = (float)filter.axis2Filter.Filter(AccelerationG.Y, IMU.DeltaSeconds);
+ this.reading.Z = this.reading_fixed.Z = (float)filter.axis3Filter.Filter(AccelerationG.Z, IMU.DeltaSeconds);
base.ReadingChanged();
}
diff --git a/ControllerService/Sensors/XInputGirometer.cs b/ControllerService/Sensors/IMUGyrometer.cs
similarity index 97%
rename from ControllerService/Sensors/XInputGirometer.cs
rename to ControllerService/Sensors/IMUGyrometer.cs
index 6d8ad6853..6e8628f12 100644
--- a/ControllerService/Sensors/XInputGirometer.cs
+++ b/ControllerService/Sensors/IMUGyrometer.cs
@@ -7,7 +7,7 @@
namespace ControllerService.Sensors
{
- public class XInputGirometer : XInputSensor
+ public class IMUGyrometer : IMUSensor
{
public static SensorSpec sensorSpec = new SensorSpec()
{
@@ -17,7 +17,7 @@ public class XInputGirometer : XInputSensor
maxOut = 2048.0f,
};
- public XInputGirometer(SensorFamily sensorFamily, int updateInterval) : base()
+ public IMUGyrometer(SensorFamily sensorFamily, int updateInterval) : base()
{
this.updateInterval = updateInterval;
centerTimer.Interval = updateInterval * 6;
diff --git a/ControllerService/Sensors/XInputInclinometer.cs b/ControllerService/Sensors/IMUInclinometer.cs
similarity index 92%
rename from ControllerService/Sensors/XInputInclinometer.cs
rename to ControllerService/Sensors/IMUInclinometer.cs
index afcf4822f..a70d5696f 100644
--- a/ControllerService/Sensors/XInputInclinometer.cs
+++ b/ControllerService/Sensors/IMUInclinometer.cs
@@ -1,162 +1,162 @@
-using ControllerCommon.Managers;
-using ControllerCommon.Sensors;
-using System;
-using System.Numerics;
-using Windows.Devices.Sensors;
-using static ControllerCommon.Utils.DeviceUtils;
-
-namespace ControllerService.Sensors
-{
- public class XInputInclinometer : XInputSensor
- {
- public XInputInclinometer(SensorFamily sensorFamily, int updateInterval) : base()
- {
- this.updateInterval = updateInterval;
- UpdateSensor(sensorFamily);
- }
-
- public void UpdateSensor(SensorFamily sensorFamily)
- {
- switch (sensorFamily)
- {
- case SensorFamily.WindowsDevicesSensors:
- sensor = Accelerometer.GetDefault();
- break;
- case SensorFamily.SerialUSBIMU:
- sensor = SerialUSBIMU.GetDefault();
- break;
- }
-
- if (sensor == null)
- {
- LogManager.LogWarning("{0} not initialised as a {1}.", this.ToString(), sensorFamily.ToString());
- return;
- }
-
- switch (sensorFamily)
- {
- case SensorFamily.WindowsDevicesSensors:
- ((Accelerometer)sensor).ReportInterval = (uint)updateInterval;
- ((Accelerometer)sensor).ReadingChanged += ReadingChanged;
- filter.SetFilterAttrs(ControllerService.handheldDevice.oneEuroSettings.minCutoff, ControllerService.handheldDevice.oneEuroSettings.beta);
-
- LogManager.LogInformation("{0} initialised as a {1}. Report interval set to {2}ms", this.ToString(), sensorFamily.ToString(), updateInterval);
- break;
- case SensorFamily.SerialUSBIMU:
- ((SerialUSBIMU)sensor).ReadingChanged += ReadingChanged;
- filter.SetFilterAttrs(((SerialUSBIMU)sensor).GetFilterCutoff(), ((SerialUSBIMU)sensor).GetFilterBeta());
-
- LogManager.LogInformation("{0} initialised as a {1}. Baud rate set to {2}", this.ToString(), sensorFamily.ToString(), ((SerialUSBIMU)sensor).GetInterval());
- break;
- }
-
- StartListening(sensorFamily);
- }
-
- public void StartListening(SensorFamily sensorFamily)
- {
- switch (sensorFamily)
- {
- case SensorFamily.WindowsDevicesSensors:
- ((Accelerometer)sensor).ReadingChanged += ReadingChanged;
- break;
- case SensorFamily.SerialUSBIMU:
- ((SerialUSBIMU)sensor).ReadingChanged += ReadingChanged;
- break;
- }
- }
-
- public void StopListening(SensorFamily sensorFamily)
- {
- if (sensor is null)
- return;
-
- switch (sensorFamily)
- {
- case SensorFamily.WindowsDevicesSensors:
- ((Accelerometer)sensor).ReadingChanged -= ReadingChanged;
- break;
- case SensorFamily.SerialUSBIMU:
- ((SerialUSBIMU)sensor).ReadingChanged -= ReadingChanged;
- break;
- }
-
- sensor = null;
- }
-
- private void ReadingChanged(Vector3 AccelerationG, Vector3 AngularVelocityDeg)
- {
- this.reading.X = this.reading_fixed.X = (float)filter.axis1Filter.Filter(AccelerationG.X, XInputController.DeltaSeconds);
- this.reading.Y = this.reading_fixed.Y = (float)filter.axis2Filter.Filter(AccelerationG.Y, XInputController.DeltaSeconds);
- this.reading.Z = this.reading_fixed.Z = (float)filter.axis3Filter.Filter(AccelerationG.Z, XInputController.DeltaSeconds);
-
- base.ReadingChanged();
- }
-
- private void ReadingChanged(Accelerometer sender, AccelerometerReadingChangedEventArgs args)
- {
- foreach (char axis in reading_axis.Keys)
- {
- switch (ControllerService.handheldDevice.AccelerationAxisSwap[axis])
- {
- default:
- case 'X':
- reading_axis[axis] = args.Reading.AccelerationX;
- break;
- case 'Y':
- reading_axis[axis] = args.Reading.AccelerationY;
- break;
- case 'Z':
- reading_axis[axis] = args.Reading.AccelerationZ;
- break;
- }
- }
-
- this.reading.X = this.reading_fixed.X = (float)reading_axis['X'] * ControllerService.handheldDevice.AccelerationAxis.X;
- this.reading.Y = this.reading_fixed.Y = (float)reading_axis['Y'] * ControllerService.handheldDevice.AccelerationAxis.Y;
- this.reading.Z = this.reading_fixed.Z = (float)reading_axis['Z'] * ControllerService.handheldDevice.AccelerationAxis.Z;
-
- base.ReadingChanged();
- }
-
- public new Vector3 GetCurrentReading(bool center = false)
- {
- Vector3 reading = new Vector3()
- {
- X = center ? this.reading_fixed.X : this.reading.X,
- Y = center ? this.reading_fixed.Y : this.reading.Y,
- Z = center ? this.reading_fixed.Z : this.reading.Z
- };
-
- var readingZ = ControllerService.currentProfile.steering == 0 ? reading.Z : reading.Y;
- var readingY = ControllerService.currentProfile.steering == 0 ? reading.Y : -reading.Z;
- var readingX = ControllerService.currentProfile.steering == 0 ? reading.X : reading.X;
-
- if (ControllerService.currentProfile.inverthorizontal)
- {
- readingY *= -1.0f;
- readingZ *= -1.0f;
- }
-
- if (ControllerService.currentProfile.invertvertical)
- {
- readingY *= -1.0f;
- readingX *= -1.0f;
- }
-
- reading.X = readingX;
- reading.Y = readingY;
- reading.Z = readingZ;
-
- // Calculate angles around Y and X axis (Theta and Psi) using all 3 directions of accelerometer
- // Based on: https://www.digikey.com/en/articles/using-an-accelerometer-for-inclination-sensing
- double angle_x_psi = -1 * (Math.Atan(reading.Y / (Math.Sqrt(Math.Pow(reading.X, 2) + Math.Pow(reading.Z, 2))))) * 180 / Math.PI;
- double angle_y_theta = -1 * (Math.Atan(reading.X / (Math.Sqrt(Math.Pow(reading.Y, 2) + Math.Pow(reading.Z, 2))))) * 180 / Math.PI;
-
- reading.X = (float)(angle_x_psi);
- reading.Y = (float)(angle_y_theta);
-
- return reading;
- }
- }
+using ControllerCommon.Managers;
+using ControllerCommon.Sensors;
+using System;
+using System.Numerics;
+using Windows.Devices.Sensors;
+using static ControllerCommon.Utils.DeviceUtils;
+
+namespace ControllerService.Sensors
+{
+ public class IMUInclinometer : IMUSensor
+ {
+ public IMUInclinometer(SensorFamily sensorFamily, int updateInterval) : base()
+ {
+ this.updateInterval = updateInterval;
+ UpdateSensor(sensorFamily);
+ }
+
+ public void UpdateSensor(SensorFamily sensorFamily)
+ {
+ switch (sensorFamily)
+ {
+ case SensorFamily.WindowsDevicesSensors:
+ sensor = Accelerometer.GetDefault();
+ break;
+ case SensorFamily.SerialUSBIMU:
+ sensor = SerialUSBIMU.GetDefault();
+ break;
+ }
+
+ if (sensor == null)
+ {
+ LogManager.LogWarning("{0} not initialised as a {1}.", this.ToString(), sensorFamily.ToString());
+ return;
+ }
+
+ switch (sensorFamily)
+ {
+ case SensorFamily.WindowsDevicesSensors:
+ ((Accelerometer)sensor).ReportInterval = (uint)updateInterval;
+ ((Accelerometer)sensor).ReadingChanged += ReadingChanged;
+ filter.SetFilterAttrs(ControllerService.handheldDevice.oneEuroSettings.minCutoff, ControllerService.handheldDevice.oneEuroSettings.beta);
+
+ LogManager.LogInformation("{0} initialised as a {1}. Report interval set to {2}ms", this.ToString(), sensorFamily.ToString(), updateInterval);
+ break;
+ case SensorFamily.SerialUSBIMU:
+ ((SerialUSBIMU)sensor).ReadingChanged += ReadingChanged;
+ filter.SetFilterAttrs(((SerialUSBIMU)sensor).GetFilterCutoff(), ((SerialUSBIMU)sensor).GetFilterBeta());
+
+ LogManager.LogInformation("{0} initialised as a {1}. Baud rate set to {2}", this.ToString(), sensorFamily.ToString(), ((SerialUSBIMU)sensor).GetInterval());
+ break;
+ }
+
+ StartListening(sensorFamily);
+ }
+
+ public void StartListening(SensorFamily sensorFamily)
+ {
+ switch (sensorFamily)
+ {
+ case SensorFamily.WindowsDevicesSensors:
+ ((Accelerometer)sensor).ReadingChanged += ReadingChanged;
+ break;
+ case SensorFamily.SerialUSBIMU:
+ ((SerialUSBIMU)sensor).ReadingChanged += ReadingChanged;
+ break;
+ }
+ }
+
+ public void StopListening(SensorFamily sensorFamily)
+ {
+ if (sensor is null)
+ return;
+
+ switch (sensorFamily)
+ {
+ case SensorFamily.WindowsDevicesSensors:
+ ((Accelerometer)sensor).ReadingChanged -= ReadingChanged;
+ break;
+ case SensorFamily.SerialUSBIMU:
+ ((SerialUSBIMU)sensor).ReadingChanged -= ReadingChanged;
+ break;
+ }
+
+ sensor = null;
+ }
+
+ private void ReadingChanged(Vector3 AccelerationG, Vector3 AngularVelocityDeg)
+ {
+ this.reading.X = this.reading_fixed.X = (float)filter.axis1Filter.Filter(AccelerationG.X, IMU.DeltaSeconds);
+ this.reading.Y = this.reading_fixed.Y = (float)filter.axis2Filter.Filter(AccelerationG.Y, IMU.DeltaSeconds);
+ this.reading.Z = this.reading_fixed.Z = (float)filter.axis3Filter.Filter(AccelerationG.Z, IMU.DeltaSeconds);
+
+ base.ReadingChanged();
+ }
+
+ private void ReadingChanged(Accelerometer sender, AccelerometerReadingChangedEventArgs args)
+ {
+ foreach (char axis in reading_axis.Keys)
+ {
+ switch (ControllerService.handheldDevice.AccelerationAxisSwap[axis])
+ {
+ default:
+ case 'X':
+ reading_axis[axis] = args.Reading.AccelerationX;
+ break;
+ case 'Y':
+ reading_axis[axis] = args.Reading.AccelerationY;
+ break;
+ case 'Z':
+ reading_axis[axis] = args.Reading.AccelerationZ;
+ break;
+ }
+ }
+
+ this.reading.X = this.reading_fixed.X = (float)reading_axis['X'] * ControllerService.handheldDevice.AccelerationAxis.X;
+ this.reading.Y = this.reading_fixed.Y = (float)reading_axis['Y'] * ControllerService.handheldDevice.AccelerationAxis.Y;
+ this.reading.Z = this.reading_fixed.Z = (float)reading_axis['Z'] * ControllerService.handheldDevice.AccelerationAxis.Z;
+
+ base.ReadingChanged();
+ }
+
+ public new Vector3 GetCurrentReading(bool center = false)
+ {
+ Vector3 reading = new Vector3()
+ {
+ X = center ? this.reading_fixed.X : this.reading.X,
+ Y = center ? this.reading_fixed.Y : this.reading.Y,
+ Z = center ? this.reading_fixed.Z : this.reading.Z
+ };
+
+ var readingZ = ControllerService.currentProfile.steering == 0 ? reading.Z : reading.Y;
+ var readingY = ControllerService.currentProfile.steering == 0 ? reading.Y : -reading.Z;
+ var readingX = ControllerService.currentProfile.steering == 0 ? reading.X : reading.X;
+
+ if (ControllerService.currentProfile.inverthorizontal)
+ {
+ readingY *= -1.0f;
+ readingZ *= -1.0f;
+ }
+
+ if (ControllerService.currentProfile.invertvertical)
+ {
+ readingY *= -1.0f;
+ readingX *= -1.0f;
+ }
+
+ reading.X = readingX;
+ reading.Y = readingY;
+ reading.Z = readingZ;
+
+ // Calculate angles around Y and X axis (Theta and Psi) using all 3 directions of accelerometer
+ // Based on: https://www.digikey.com/en/articles/using-an-accelerometer-for-inclination-sensing
+ double angle_x_psi = -1 * (Math.Atan(reading.Y / (Math.Sqrt(Math.Pow(reading.X, 2) + Math.Pow(reading.Z, 2))))) * 180 / Math.PI;
+ double angle_y_theta = -1 * (Math.Atan(reading.X / (Math.Sqrt(Math.Pow(reading.Y, 2) + Math.Pow(reading.Z, 2))))) * 180 / Math.PI;
+
+ reading.X = (float)(angle_x_psi);
+ reading.Y = (float)(angle_y_theta);
+
+ return reading;
+ }
+ }
}
\ No newline at end of file
diff --git a/ControllerService/Sensors/XInputSensor.cs b/ControllerService/Sensors/IMUSensor.cs
similarity index 90%
rename from ControllerService/Sensors/XInputSensor.cs
rename to ControllerService/Sensors/IMUSensor.cs
index efe8e26d7..9ceee6809 100644
--- a/ControllerService/Sensors/XInputSensor.cs
+++ b/ControllerService/Sensors/IMUSensor.cs
@@ -1,5 +1,4 @@
-using ControllerCommon.Managers;
-using ControllerCommon.Sensors;
+using ControllerCommon.Sensors;
using ControllerCommon.Utils;
using System;
using System.Collections.Generic;
@@ -30,7 +29,7 @@ public enum XInputSensorStatus
Busy = 2
}
- public abstract class XInputSensor
+ public abstract class IMUSensor
{
protected Vector3 reading = new();
protected Vector3 reading_fixed = new();
@@ -50,7 +49,7 @@ public abstract class XInputSensor
{ 'Z', 0.0d },
};
- protected XInputSensor()
+ protected IMUSensor()
{
this.centerTimer = new Timer() { Enabled = false, AutoReset = false, Interval = 100 };
this.centerTimer.Elapsed += Timer_Elapsed;
@@ -61,10 +60,6 @@ protected virtual void ReadingChanged()
// reset reading after inactivity
centerTimer.Stop();
centerTimer.Start();
-
-#if DEBUG
- LogManager.LogDebug("{0}.ReadingChanged({1:00.####}, {2:00.####}, {3:00.####})", this.GetType().Name, this.reading.X, this.reading.Y, this.reading.Z);
-#endif
}
public static XInputSensorStatus GetStatus(SensorFamily sensorFamily)
diff --git a/ControllerService/Targets/DualShock4Target.cs b/ControllerService/Targets/DualShock4Target.cs
index 5caaaccb3..55cec4338 100644
--- a/ControllerService/Targets/DualShock4Target.cs
+++ b/ControllerService/Targets/DualShock4Target.cs
@@ -1,49 +1,16 @@
-using ControllerCommon.Managers;
+using ControllerCommon;
+using ControllerCommon.Controllers;
+using ControllerCommon.Managers;
using ControllerCommon.Utils;
using ControllerService.Sensors;
-using Nefarius.ViGEm.Client;
using Nefarius.ViGEm.Client.Exceptions;
using Nefarius.ViGEm.Client.Targets;
using Nefarius.ViGEm.Client.Targets.DualShock4;
-using SharpDX.XInput;
-using System.Collections.Generic;
namespace ControllerService.Targets
{
internal class DualShock4Target : ViGEmTarget
- {
- private static readonly List ButtonMap = new List
- {
- DualShock4Button.ThumbRight,
- DualShock4Button.ThumbLeft,
- DualShock4Button.Options,
- DualShock4Button.Share,
- DualShock4Button.TriggerRight,
- DualShock4Button.TriggerLeft,
- DualShock4Button.ShoulderRight,
- DualShock4Button.ShoulderLeft,
- DualShock4Button.Triangle,
- DualShock4Button.Circle,
- DualShock4Button.Cross,
- DualShock4Button.Square,
- DualShock4SpecialButton.Ps,
- DualShock4SpecialButton.Touchpad
- };
-
- private static readonly List AxisMap = new List
- {
- DualShock4Axis.LeftThumbX,
- DualShock4Axis.LeftThumbY,
- DualShock4Axis.RightThumbX,
- DualShock4Axis.RightThumbY
- };
-
- private static readonly List SliderMap = new List
- {
- DualShock4Slider.LeftTrigger,
- DualShock4Slider.RightTrigger
- };
-
+ {
// DS4 Accelerometer g-force measurement range G SI unit to short
// Various sources state either +/- 2 or 4 ranges are in use
private static readonly SensorSpec DS4AccelerometerSensorSpec = new SensorSpec()
@@ -68,57 +35,54 @@ internal class DualShock4Target : ViGEmTarget
private new IDualShock4Controller virtualController;
- public DualShock4Target(XInputController xinput, ViGEmClient client) : base(xinput, client)
+ public DualShock4Target() : base()
{
// initialize controller
HID = HIDmode.DualShock4Controller;
- virtualController = client.CreateDualShock4Controller();
+ virtualController = ControllerService.vClient.CreateDualShock4Controller();
virtualController.AutoSubmitReport = false;
- virtualController.FeedbackReceived += FeedbackReceived;
+ virtualController.FeedbackReceived += FeedbackReceived;
+
+ UpdateTimer.Tick += (sender, e) => UpdateReport();
LogManager.LogInformation("{0} initialized, {1}", ToString(), virtualController);
- }
-
- public override void Connect()
- {
- if (IsConnected)
- return;
-
- virtualController.Connect();
- base.Connect();
- }
-
- public override void Disconnect()
- {
- if (!IsConnected)
- return;
-
- virtualController.Disconnect();
- base.Disconnect();
+ }
+
+ public override void Connect()
+ {
+ if (IsConnected)
+ return;
+
+ virtualController.Connect();
+ UpdateTimer.Start();
+
+ base.Connect();
+ }
+
+ public override void Disconnect()
+ {
+ if (!IsConnected)
+ return;
+
+ virtualController.Disconnect();
+ UpdateTimer.Stop();
+
+ base.Disconnect();
}
public void FeedbackReceived(object sender, DualShock4FeedbackReceivedEventArgs e)
- {
- if (!physicalController.IsConnected)
- return;
-
- Vibration inputMotor = new()
- {
- LeftMotorSpeed = (ushort)((e.LargeMotor * ushort.MaxValue / byte.MaxValue) * vibrationStrength),
- RightMotorSpeed = (ushort)((e.SmallMotor * ushort.MaxValue / byte.MaxValue) * vibrationStrength),
- };
- physicalController.SetVibration(inputMotor);
+ {
+ // pass raw vibration to client
+ PipeServer.SendMessage(new PipeClientVibration() { LargeMotor = e.LargeMotor, SmallMotor = e.SmallMotor });
}
- public override unsafe void UpdateReport(Gamepad Gamepad)
+ public override unsafe void UpdateReport()
{
if (!IsConnected)
return;
- base.UpdateReport(Gamepad);
-
- var Touch = xinputController.Touch;
+ base.UpdateReport();
// reset vars
byte[] rawOutReportEx = new byte[63];
@@ -133,59 +97,59 @@ public override unsafe void UpdateReport(Gamepad Gamepad)
unchecked
{
- if (Buttons.HasFlag(GamepadButtonFlagsExt.A))
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.B1))
tempButtons |= DualShock4Button.Cross.Value;
- if (Buttons.HasFlag(GamepadButtonFlagsExt.B))
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.B2))
tempButtons |= DualShock4Button.Circle.Value;
- if (Buttons.HasFlag(GamepadButtonFlagsExt.X))
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.B3))
tempButtons |= DualShock4Button.Square.Value;
- if (Buttons.HasFlag(GamepadButtonFlagsExt.Y))
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.B4))
tempButtons |= DualShock4Button.Triangle.Value;
- if (Buttons.HasFlag(GamepadButtonFlagsExt.Start))
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.Start))
tempButtons |= DualShock4Button.Options.Value;
- if (Buttons.HasFlag(GamepadButtonFlagsExt.Back))
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.Back))
tempButtons |= DualShock4Button.Share.Value;
- if (Buttons.HasFlag(GamepadButtonFlagsExt.RightThumb))
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.RightThumb))
tempButtons |= DualShock4Button.ThumbRight.Value;
- if (Buttons.HasFlag(GamepadButtonFlagsExt.LeftThumb))
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.LeftThumb))
tempButtons |= DualShock4Button.ThumbLeft.Value;
- if (Buttons.HasFlag(GamepadButtonFlagsExt.RightShoulder))
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.RightShoulder))
tempButtons |= DualShock4Button.ShoulderRight.Value;
- if (Buttons.HasFlag(GamepadButtonFlagsExt.LeftShoulder))
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.LeftShoulder))
tempButtons |= DualShock4Button.ShoulderLeft.Value;
- if (Gamepad.LeftTrigger > 0)
+ if (Inputs.LeftTrigger > 0)
tempButtons |= DualShock4Button.TriggerLeft.Value;
- if (Gamepad.RightTrigger > 0)
+ if (Inputs.RightTrigger > 0)
tempButtons |= DualShock4Button.TriggerRight.Value;
- if (Buttons.HasFlag(GamepadButtonFlagsExt.DPadUp) &&
- Buttons.HasFlag(GamepadButtonFlagsExt.DPadRight))
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadUp) &&
+ Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadRight))
tempDPad = DualShock4DPadDirection.Northeast;
- else if (Buttons.HasFlag(GamepadButtonFlagsExt.DPadUp) &&
- Buttons.HasFlag(GamepadButtonFlagsExt.DPadLeft))
+ else if (Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadUp) &&
+ Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadLeft))
tempDPad = DualShock4DPadDirection.Northwest;
- else if (Buttons.HasFlag(GamepadButtonFlagsExt.DPadUp))
+ else if (Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadUp))
tempDPad = DualShock4DPadDirection.North;
- else if (Buttons.HasFlag(GamepadButtonFlagsExt.DPadRight) &&
- Buttons.HasFlag(GamepadButtonFlagsExt.DPadDown))
+ else if (Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadRight) &&
+ Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadDown))
tempDPad = DualShock4DPadDirection.Southeast;
- else if (Buttons.HasFlag(GamepadButtonFlagsExt.DPadRight))
+ else if (Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadRight))
tempDPad = DualShock4DPadDirection.East;
- else if (Buttons.HasFlag(GamepadButtonFlagsExt.DPadDown) &&
- Buttons.HasFlag(GamepadButtonFlagsExt.DPadLeft))
+ else if (Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadDown) &&
+ Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadLeft))
tempDPad = DualShock4DPadDirection.Southwest;
- else if (Buttons.HasFlag(GamepadButtonFlagsExt.DPadDown))
+ else if (Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadDown))
tempDPad = DualShock4DPadDirection.South;
- else if (Buttons.HasFlag(GamepadButtonFlagsExt.DPadLeft))
+ else if (Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadLeft))
tempDPad = DualShock4DPadDirection.West;
- if (sState.wButtons.HasFlag(XInputStateButtons.Xbox))
+ if (Inputs.Buttons.HasFlag(ControllerButtonFlags.Special))
tempSpecial |= DualShock4SpecialButton.Ps.Value;
- if (Touch.OutputClickButton)
+ if (DS4Touch.OutputClickButton)
tempSpecial |= DualShock4SpecialButton.Touchpad.Value;
outDS4Report.bSpecial = (byte)(tempSpecial | (0 << 2));
@@ -196,8 +160,8 @@ public override unsafe void UpdateReport(Gamepad Gamepad)
outDS4Report.wButtons = tempButtons;
outDS4Report.wButtons |= tempDPad.Value;
- outDS4Report.bTriggerL = Gamepad.LeftTrigger;
- outDS4Report.bTriggerR = Gamepad.RightTrigger;
+ outDS4Report.bTriggerL = (byte)Inputs.LeftTrigger;
+ outDS4Report.bTriggerR = (byte)Inputs.RightTrigger;
outDS4Report.bThumbLX = InputUtils.NormalizeXboxInput(LeftThumb.X);
outDS4Report.bThumbLY = (byte)(byte.MaxValue - InputUtils.NormalizeXboxInput(LeftThumb.Y));
@@ -208,32 +172,38 @@ public override unsafe void UpdateReport(Gamepad Gamepad)
unchecked
{
outDS4Report.bTouchPacketsN = 0x01;
- outDS4Report.sCurrentTouch.bPacketCounter = Touch.TouchPacketCounter;
- outDS4Report.sCurrentTouch.bIsUpTrackingNum1 = (byte)Touch.TrackPadTouch1.RawTrackingNum;
- outDS4Report.sCurrentTouch.bTouchData1[0] = (byte)(Touch.TrackPadTouch1.X & 0xFF);
+ outDS4Report.sCurrentTouch.bPacketCounter = DS4Touch.TouchPacketCounter;
+ outDS4Report.sCurrentTouch.bIsUpTrackingNum1 = (byte)DS4Touch.TrackPadTouch1.RawTrackingNum;
+ outDS4Report.sCurrentTouch.bTouchData1[0] = (byte)(DS4Touch.TrackPadTouch1.X & 0xFF);
outDS4Report.sCurrentTouch.bTouchData1[1] =
- (byte)(((Touch.TrackPadTouch1.X >> 8) & 0x0F) | ((Touch.TrackPadTouch1.Y << 4) & 0xF0));
- outDS4Report.sCurrentTouch.bTouchData1[2] = (byte)(Touch.TrackPadTouch1.Y >> 4);
+ (byte)(((DS4Touch.TrackPadTouch1.X >> 8) & 0x0F) | ((DS4Touch.TrackPadTouch1.Y << 4) & 0xF0));
+ outDS4Report.sCurrentTouch.bTouchData1[2] = (byte)(DS4Touch.TrackPadTouch1.Y >> 4);
- outDS4Report.sCurrentTouch.bIsUpTrackingNum2 = (byte)Touch.TrackPadTouch2.RawTrackingNum;
- outDS4Report.sCurrentTouch.bTouchData2[0] = (byte)(Touch.TrackPadTouch2.X & 0xFF);
+ outDS4Report.sCurrentTouch.bIsUpTrackingNum2 = (byte)DS4Touch.TrackPadTouch2.RawTrackingNum;
+ outDS4Report.sCurrentTouch.bTouchData2[0] = (byte)(DS4Touch.TrackPadTouch2.X & 0xFF);
outDS4Report.sCurrentTouch.bTouchData2[1] =
- (byte)(((Touch.TrackPadTouch2.X >> 8) & 0x0F) | ((Touch.TrackPadTouch2.Y << 4) & 0xF0));
- outDS4Report.sCurrentTouch.bTouchData2[2] = (byte)(Touch.TrackPadTouch2.Y >> 4);
+ (byte)(((DS4Touch.TrackPadTouch2.X >> 8) & 0x0F) | ((DS4Touch.TrackPadTouch2.Y << 4) & 0xF0));
+ outDS4Report.sCurrentTouch.bTouchData2[2] = (byte)(DS4Touch.TrackPadTouch2.Y >> 4);
}
// Use IMU sensor data, map to proper range, invert where needed
- outDS4Report.wGyroX = (short)InputUtils.rangeMap(xinputController.AngularVelocities[XInputSensorFlags.Default].X, DS4GyroscopeSensorSpec); // gyroPitchFull
- outDS4Report.wGyroY = (short)InputUtils.rangeMap(-xinputController.AngularVelocities[XInputSensorFlags.Default].Y, DS4GyroscopeSensorSpec); // gyroYawFull
- outDS4Report.wGyroZ = (short)InputUtils.rangeMap(xinputController.AngularVelocities[XInputSensorFlags.Default].Z, DS4GyroscopeSensorSpec); // gyroRollFull
-
- outDS4Report.wAccelX = (short)InputUtils.rangeMap(-xinputController.Accelerations[XInputSensorFlags.Default].X, DS4AccelerometerSensorSpec); // accelXFull
- outDS4Report.wAccelY = (short)InputUtils.rangeMap(-xinputController.Accelerations[XInputSensorFlags.Default].Y, DS4AccelerometerSensorSpec); // accelYFull
- outDS4Report.wAccelZ = (short)InputUtils.rangeMap(xinputController.Accelerations[XInputSensorFlags.Default].Z, DS4AccelerometerSensorSpec); // accelZFull
+ if (IMU.AngularVelocity.ContainsKey(XInputSensorFlags.Default))
+ {
+ outDS4Report.wGyroX = (short)InputUtils.rangeMap(IMU.AngularVelocity[XInputSensorFlags.Default].X, DS4GyroscopeSensorSpec); // gyroPitchFull
+ outDS4Report.wGyroY = (short)InputUtils.rangeMap(-IMU.AngularVelocity[XInputSensorFlags.Default].Y, DS4GyroscopeSensorSpec); // gyroYawFull
+ outDS4Report.wGyroZ = (short)InputUtils.rangeMap(IMU.AngularVelocity[XInputSensorFlags.Default].Z, DS4GyroscopeSensorSpec); // gyroRollFull
+ }
+ if (IMU.Acceleration.ContainsKey(XInputSensorFlags.Default))
+ {
+ outDS4Report.wAccelX = (short)InputUtils.rangeMap(-IMU.Acceleration[XInputSensorFlags.Default].X, DS4AccelerometerSensorSpec); // accelXFull
+ outDS4Report.wAccelY = (short)InputUtils.rangeMap(-IMU.Acceleration[XInputSensorFlags.Default].Y, DS4AccelerometerSensorSpec); // accelYFull
+ outDS4Report.wAccelZ = (short)InputUtils.rangeMap(IMU.Acceleration[XInputSensorFlags.Default].Z, DS4AccelerometerSensorSpec); // accelZFull
+ }
+
outDS4Report.bBatteryLvlSpecial = 11;
- outDS4Report.wTimestamp = (ushort)(xinputController.CurrentMicroseconds);
+ outDS4Report.wTimestamp = (ushort)(IMU.CurrentMicroseconds);
DS4OutDeviceExtras.CopyBytes(ref outDS4Report, rawOutReportEx);
diff --git a/ControllerService/Targets/ViGEmTarget.cs b/ControllerService/Targets/ViGEmTarget.cs
index 31e8f2134..3bbb1a83e 100644
--- a/ControllerService/Targets/ViGEmTarget.cs
+++ b/ControllerService/Targets/ViGEmTarget.cs
@@ -1,61 +1,25 @@
using ControllerCommon;
+using ControllerCommon.Controllers;
using ControllerCommon.Managers;
using ControllerCommon.Utils;
using ControllerService.Sensors;
using Nefarius.ViGEm.Client;
-using SharpDX.XInput;
+using PrecisionTiming;
using System;
using System.Numerics;
-using System.Runtime.InteropServices;
-using GamepadButtonFlagsExt = ControllerCommon.Utils.GamepadButtonFlagsExt;
namespace ControllerService.Targets
{
public abstract class ViGEmTarget : IDisposable
{
- #region imports
- protected enum XInputStateButtons : ushort
- {
- None = 0,
- Xbox = 1024
- }
-
- [StructLayout(LayoutKind.Sequential)]
- protected struct XInputStateSecret
- {
- public uint eventCount;
- public XInputStateButtons wButtons;
- public byte bLeftTrigger;
- public byte bRightTrigger;
- public short sThumbLX;
- public short sThumbLY;
- public short sThumbRX;
- public short sThumbRY;
- }
-
- [DllImport("xinput1_3.dll", EntryPoint = "#100")]
- protected static extern int XInputGetStateSecret13(int playerIndex, out XInputStateSecret struc);
- [DllImport("xinput1_4.dll", EntryPoint = "#100")]
- protected static extern int XInputGetStateSecret14(int playerIndex, out XInputStateSecret struc);
- #endregion
-
- public Controller physicalController;
- public XInputController xinputController;
public FlickStick flickStick;
+ protected ControllerInput Inputs = new();
+ protected PrecisionTimer UpdateTimer;
public HIDmode HID = HIDmode.NoController;
- protected ViGEmClient client { get; }
protected IVirtualGamepad virtualController;
- protected XInputStateSecret sState;
- protected XInputStateSecret sStateInjector;
-
- protected GamepadButtonFlagsExt Buttons; // used to read/write buttons
- protected GamepadButtonFlagsExt ButtonsInjector; // used to store injected buttons
-
- protected double vibrationStrength;
-
protected Vector2 LeftThumb;
protected Vector2 RightThumb;
@@ -67,30 +31,20 @@ protected struct XInputStateSecret
public bool IsConnected = false;
- protected ViGEmTarget(XInputController xinput, ViGEmClient client)
+ protected ViGEmTarget()
{
// initialize flick stick
flickStick = new FlickStick();
- // initialize secret state
- sState = new();
-
- // initialize controller
- this.client = client;
- this.xinputController = xinput;
- this.physicalController = xinput.controllerEx.Controller;
+ UpdateTimer = new PrecisionTimer();
+ UpdateTimer.SetInterval(5);
+ UpdateTimer.SetAutoResetMode(true);
}
protected void FeedbackReceived(object sender, EventArgs e)
{
}
- public void SetVibrationStrength(double strength)
- {
- vibrationStrength = strength / 100.0f;
- LogManager.LogInformation("{0} vibration strength set to {1}%", ToString(), strength);
- }
-
public override string ToString()
{
return EnumUtils.GetDescriptionFromEnumValue(HID);
@@ -110,40 +64,21 @@ public virtual void Disconnect()
LogManager.LogInformation("{0} disconnected", ToString());
}
- public void InjectReport(GamepadButtonFlagsExt buttons, ushort sButtons, bool IsKeyDown, bool IsKeyUp)
+ public void UpdateInputs(ControllerInput inputs)
{
- if(IsKeyDown)
- {
- ButtonsInjector |= buttons;
- sStateInjector.wButtons |= (XInputStateButtons)sButtons;
- }
- else if (IsKeyUp)
- {
- ButtonsInjector &= ~buttons;
- sStateInjector.wButtons &= ~(XInputStateButtons)sButtons;
- }
+ Inputs = inputs;
}
- public virtual unsafe void UpdateReport(Gamepad Gamepad)
+ public virtual unsafe void UpdateReport()
{
- // get current gamepad state
- XInputGetStateSecret13((int)physicalController.UserIndex, out sState);
- sState.wButtons |= sStateInjector.wButtons;
-
- // get buttons values
- Buttons = (GamepadButtonFlagsExt)Gamepad.Buttons;
- Buttons |= (Gamepad.LeftTrigger > 0 ? GamepadButtonFlagsExt.LeftTrigger : 0);
- Buttons |= (Gamepad.RightTrigger > 0 ? GamepadButtonFlagsExt.RightTrigger : 0);
- Buttons |= ButtonsInjector;
-
// get sticks values
- LeftThumb = new Vector2(Gamepad.LeftThumbX, Gamepad.LeftThumbY);
- RightThumb = new Vector2(Gamepad.RightThumbX, Gamepad.RightThumbY);
+ LeftThumb = new Vector2(Inputs.LeftThumbX, Inputs.LeftThumbY);
+ RightThumb = new Vector2(Inputs.RightThumbX, Inputs.RightThumbY);
if (ControllerService.currentProfile.umc_enabled)
{
- if (((ControllerService.currentProfile.umc_motion_defaultoffon == UMC_Motion_Default.Off) && (ControllerService.currentProfile.umc_trigger & Buttons) != 0) ||
- ((ControllerService.currentProfile.umc_motion_defaultoffon == UMC_Motion_Default.On) && (ControllerService.currentProfile.umc_trigger & Buttons) == 0))
+ if ((ControllerService.currentProfile.umc_motion_defaultoffon == UMC_Motion_Default.Off && (ControllerService.currentProfile.umc_trigger & Inputs.Buttons) != 0) ||
+ (ControllerService.currentProfile.umc_motion_defaultoffon == UMC_Motion_Default.On && (ControllerService.currentProfile.umc_trigger & Inputs.Buttons) == 0))
{
switch (ControllerService.currentProfile.umc_input)
{
@@ -156,23 +91,23 @@ public virtual unsafe void UpdateReport(Gamepad Gamepad)
switch (ControllerService.currentProfile.umc_input)
{
case Input.PlayerSpace:
- Angular = new Vector2((float)xinputController.sensorFusion.CameraYawDelta, (float)xinputController.sensorFusion.CameraPitchDelta);
+ Angular = new Vector2((float)IMU.sensorFusion.CameraYawDelta, (float)IMU.sensorFusion.CameraPitchDelta);
break;
case Input.AutoRollYawSwap:
- Angular = InputUtils.AutoRollYawSwap(xinputController.sensorFusion.GravityVectorSimple, xinputController.AngularVelocities[XInputSensorFlags.Centered]);
+ Angular = InputUtils.AutoRollYawSwap(IMU.sensorFusion.GravityVectorSimple, IMU.AngularVelocity[XInputSensorFlags.Centered]);
break;
default:
case Input.JoystickCamera:
- Angular = new Vector2(-xinputController.AngularVelocities[XInputSensorFlags.Centered].Z, xinputController.AngularVelocities[XInputSensorFlags.Centered].X);
+ Angular = new Vector2(-IMU.AngularVelocity[XInputSensorFlags.Centered].Z, IMU.AngularVelocity[XInputSensorFlags.Centered].X);
break;
}
// apply sensivity curve
- Angular.X *= InputUtils.ApplyCustomSensitivity(Angular.X, XInputGirometer.sensorSpec.maxIn, ControllerService.currentProfile.aiming_array);
- Angular.Y *= InputUtils.ApplyCustomSensitivity(Angular.Y, XInputGirometer.sensorSpec.maxIn, ControllerService.currentProfile.aiming_array);
+ Angular.X *= InputUtils.ApplyCustomSensitivity(Angular.X, IMUGyrometer.sensorSpec.maxIn, ControllerService.currentProfile.aiming_array);
+ Angular.Y *= InputUtils.ApplyCustomSensitivity(Angular.Y, IMUGyrometer.sensorSpec.maxIn, ControllerService.currentProfile.aiming_array);
// apply aiming down scopes multiplier if activated
- if ((ControllerService.currentProfile.aiming_down_sights_activation & Buttons) != 0)
+ if ((ControllerService.currentProfile.aiming_down_sights_activation & Inputs.Buttons) != 0)
{
Angular *= ControllerService.currentProfile.aiming_down_sights_multiplier;
}
@@ -196,7 +131,7 @@ public virtual unsafe void UpdateReport(Gamepad Gamepad)
float FlickStickX = flickStick.Handle(RightThumb,
ControllerService.currentProfile.flick_duration,
ControllerService.currentProfile.stick_sensivity,
- XInputController.TotalMilliseconds);
+ IMU.TotalMilliseconds);
// X input combines motion controls plus flick stick result
// Y input only from motion controls
@@ -221,7 +156,7 @@ public virtual unsafe void UpdateReport(Gamepad Gamepad)
case Input.JoystickSteering:
{
float GamepadThumbX = InputUtils.Steering(
- xinputController.sensorFusion.DeviceAngle.Y,
+ IMU.sensorFusion.DeviceAngle.Y,
ControllerService.currentProfile.steering_max_angle,
ControllerService.currentProfile.steering_power,
ControllerService.currentProfile.steering_deadzone);
diff --git a/ControllerService/Targets/Xbox360Target.cs b/ControllerService/Targets/Xbox360Target.cs
index 281785692..6d1b01158 100644
--- a/ControllerService/Targets/Xbox360Target.cs
+++ b/ControllerService/Targets/Xbox360Target.cs
@@ -1,60 +1,28 @@
-using ControllerCommon.Managers;
+using ControllerCommon;
+using ControllerCommon.Controllers;
+using ControllerCommon.Managers;
using ControllerCommon.Utils;
-using Nefarius.ViGEm.Client;
using Nefarius.ViGEm.Client.Exceptions;
using Nefarius.ViGEm.Client.Targets;
using Nefarius.ViGEm.Client.Targets.Xbox360;
-using SharpDX.XInput;
-using System.Collections.Generic;
namespace ControllerService.Targets
{
internal partial class Xbox360Target : ViGEmTarget
{
- private static readonly List ButtonMap = new List
- {
- Xbox360Button.Up,
- Xbox360Button.Down,
- Xbox360Button.Left,
- Xbox360Button.Right,
- Xbox360Button.Start,
- Xbox360Button.Back,
- Xbox360Button.LeftThumb,
- Xbox360Button.RightThumb,
- Xbox360Button.LeftShoulder,
- Xbox360Button.RightShoulder,
- Xbox360Button.Guide,
- Xbox360Button.A,
- Xbox360Button.B,
- Xbox360Button.X,
- Xbox360Button.Y
- };
-
- private static readonly List AxisMap = new List
- {
- Xbox360Axis.LeftThumbX,
- Xbox360Axis.LeftThumbY,
- Xbox360Axis.RightThumbX,
- Xbox360Axis.RightThumbY
- };
-
- private static readonly List SliderMap = new List
- {
- Xbox360Slider.LeftTrigger,
- Xbox360Slider.RightTrigger
- };
-
private new IXbox360Controller virtualController;
- public Xbox360Target(XInputController xinput, ViGEmClient client) : base(xinput, client)
+ public Xbox360Target() : base()
{
// initialize controller
HID = HIDmode.Xbox360Controller;
- virtualController = client.CreateXbox360Controller();
+ virtualController = ControllerService.vClient.CreateXbox360Controller();
virtualController.AutoSubmitReport = false;
virtualController.FeedbackReceived += FeedbackReceived;
+ UpdateTimer.Tick += (sender, e) => UpdateReport();
+
LogManager.LogInformation("{0} initialized, {1}", ToString(), virtualController);
}
@@ -64,6 +32,8 @@ public override void Connect()
return;
virtualController.Connect();
+ UpdateTimer.Start();
+
base.Connect();
}
@@ -73,23 +43,18 @@ public override void Disconnect()
return;
virtualController.Disconnect();
+ UpdateTimer.Stop();
+
base.Disconnect();
}
public void FeedbackReceived(object sender, Xbox360FeedbackReceivedEventArgs e)
{
- if (!physicalController.IsConnected)
- return;
-
- Vibration inputMotor = new()
- {
- LeftMotorSpeed = (ushort)((e.LargeMotor * ushort.MaxValue / byte.MaxValue) * vibrationStrength),
- RightMotorSpeed = (ushort)((e.SmallMotor * ushort.MaxValue / byte.MaxValue) * vibrationStrength),
- };
- physicalController.SetVibration(inputMotor);
+ // pass raw vibration to client
+ PipeServer.SendMessage(new PipeClientVibration() { LargeMotor = e.LargeMotor, SmallMotor = e.SmallMotor });
}
- public override unsafe void UpdateReport(Gamepad Gamepad)
+ public override unsafe void UpdateReport()
{
if (!IsConnected)
return;
@@ -97,23 +62,36 @@ public override unsafe void UpdateReport(Gamepad Gamepad)
if (ControllerService.currentProfile.whitelisted)
return;
- base.UpdateReport(Gamepad);
+ base.UpdateReport();
- virtualController.SetAxisValue(Xbox360Axis.LeftThumbX, (short)LeftThumb.X);
- virtualController.SetAxisValue(Xbox360Axis.LeftThumbY, (short)LeftThumb.Y);
- virtualController.SetAxisValue(Xbox360Axis.RightThumbX, (short)RightThumb.X);
- virtualController.SetAxisValue(Xbox360Axis.RightThumbY, (short)RightThumb.Y);
+ virtualController.SetAxisValue(Xbox360Axis.LeftThumbX, (short)Inputs.LeftThumbX);
+ virtualController.SetAxisValue(Xbox360Axis.LeftThumbY, (short)Inputs.LeftThumbY);
+ virtualController.SetAxisValue(Xbox360Axis.RightThumbX, (short)Inputs.RightThumbX);
+ virtualController.SetAxisValue(Xbox360Axis.RightThumbY, (short)Inputs.RightThumbY);
- foreach (Xbox360Button button in ButtonMap)
- {
- GamepadButtonFlagsExt value = (GamepadButtonFlagsExt)button.Value;
- virtualController.SetButtonState(button, Buttons.HasFlag(value));
- }
+ virtualController.SetSliderValue(Xbox360Slider.LeftTrigger, (byte)Inputs.LeftTrigger);
+ virtualController.SetSliderValue(Xbox360Slider.RightTrigger, (byte)Inputs.RightTrigger);
+
+ virtualController.SetButtonState(Xbox360Button.A, Inputs.Buttons.HasFlag(ControllerButtonFlags.B1));
+ virtualController.SetButtonState(Xbox360Button.B, Inputs.Buttons.HasFlag(ControllerButtonFlags.B2));
+ virtualController.SetButtonState(Xbox360Button.X, Inputs.Buttons.HasFlag(ControllerButtonFlags.B3));
+ virtualController.SetButtonState(Xbox360Button.Y, Inputs.Buttons.HasFlag(ControllerButtonFlags.B4));
+
+ virtualController.SetButtonState(Xbox360Button.Left, Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadLeft));
+ virtualController.SetButtonState(Xbox360Button.Right, Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadRight));
+ virtualController.SetButtonState(Xbox360Button.Down, Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadDown));
+ virtualController.SetButtonState(Xbox360Button.Up, Inputs.Buttons.HasFlag(ControllerButtonFlags.DPadUp));
+
+ virtualController.SetButtonState(Xbox360Button.Back, Inputs.Buttons.HasFlag(ControllerButtonFlags.Back));
+ virtualController.SetButtonState(Xbox360Button.Start, Inputs.Buttons.HasFlag(ControllerButtonFlags.Start));
+
+ virtualController.SetButtonState(Xbox360Button.LeftShoulder, Inputs.Buttons.HasFlag(ControllerButtonFlags.LeftShoulder));
+ virtualController.SetButtonState(Xbox360Button.RightShoulder, Inputs.Buttons.HasFlag(ControllerButtonFlags.RightShoulder));
- virtualController.SetButtonState(Xbox360Button.Guide, sState.wButtons.HasFlag(XInputStateButtons.Xbox));
+ virtualController.SetButtonState(Xbox360Button.LeftThumb, Inputs.Buttons.HasFlag(ControllerButtonFlags.LeftThumb));
+ virtualController.SetButtonState(Xbox360Button.RightThumb, Inputs.Buttons.HasFlag(ControllerButtonFlags.RightThumb));
- virtualController.SetSliderValue(Xbox360Slider.LeftTrigger, Gamepad.LeftTrigger);
- virtualController.SetSliderValue(Xbox360Slider.RightTrigger, Gamepad.RightTrigger);
+ virtualController.SetButtonState(Xbox360Button.Guide, Inputs.Buttons.HasFlag(ControllerButtonFlags.Special));
try
{
diff --git a/ControllerService/XInputController.cs b/ControllerService/XInputController.cs
deleted file mode 100644
index 9e467bd18..000000000
--- a/ControllerService/XInputController.cs
+++ /dev/null
@@ -1,271 +0,0 @@
-using ControllerCommon;
-using ControllerCommon.Managers;
-using ControllerCommon.Utils;
-using ControllerService.Sensors;
-using ControllerService.Targets;
-using PrecisionTiming;
-using SharpDX.XInput;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Numerics;
-using System.Threading;
-using System.Threading.Tasks;
-using static ControllerCommon.Utils.DeviceUtils;
-
-namespace ControllerService
-{
- public class XInputController
- {
- public ControllerEx controllerEx;
- public string ProductName = "XInput Controller for Windows";
-
- public ViGEmTarget virtualTarget;
-
- public Gamepad Gamepad;
- private State GamepadState;
-
- public Dictionary Accelerations = new();
- public Dictionary AngularVelocities = new();
-
- public Vector3 Angle;
-
- public PrecisionTimer UpdateTimer;
- public double vibrationStrength = 100.0d;
- public int updateInterval = 10;
-
- private SensorFamily sensorFamily = SensorFamily.None;
- public XInputGirometer Gyrometer;
- public XInputAccelerometer Accelerometer;
- public XInputInclinometer Inclinometer;
-
- public SensorFusion sensorFusion;
- public MadgwickAHRS madgwickAHRS;
-
- protected Stopwatch stopwatch;
- public long CurrentMicroseconds;
-
- public static double TotalMilliseconds;
- public static double UpdateTimePreviousMilliseconds;
- public static double DeltaSeconds = 100.0d;
-
- public DS4Touch Touch;
-
- public event UpdatedEventHandler Updated;
- public delegate void UpdatedEventHandler(XInputController controller);
-
- protected object updateLock = new();
- private readonly PipeServer pipeServer;
-
- public XInputController(SensorFamily sensorFamily, PipeServer pipeServer)
- {
- this.pipeServer = pipeServer;
-
- // initialize sensorfusion and madgwick
- sensorFusion = new SensorFusion();
- madgwickAHRS = new MadgwickAHRS(0.01f, 0.1f);
-
- // initialize sensors
- Gyrometer = new XInputGirometer(sensorFamily, updateInterval);
- Accelerometer = new XInputAccelerometer(sensorFamily, updateInterval);
- Inclinometer = new XInputInclinometer(sensorFamily, updateInterval);
- this.sensorFamily = sensorFamily;
-
- // initialize vectors
- Accelerations = new();
- AngularVelocities = new();
- Angle = new();
-
- // initialize touch
- Touch = new();
-
- // initialize stopwatch
- stopwatch = new Stopwatch();
-
- // initialize timers
- UpdateTimer = new PrecisionTimer();
- UpdateTimer.SetInterval(updateInterval);
- UpdateTimer.SetAutoResetMode(true);
- }
-
- public void StartListening()
- {
- stopwatch.Start();
-
- UpdateTimer.Tick += UpdateTimer_Ticked;
- UpdateTimer.Start();
- }
-
- public void StopListening()
- {
- Gyrometer.StopListening(sensorFamily);
- Accelerometer.StopListening(sensorFamily);
- Inclinometer.StopListening(sensorFamily);
-
- UpdateTimer.Tick -= UpdateTimer_Ticked;
- UpdateTimer.Stop();
-
- stopwatch.Stop();
- }
-
- public void UpdateSensors()
- {
- Gyrometer.UpdateSensor(sensorFamily);
- Accelerometer.UpdateSensor(sensorFamily);
- Inclinometer.UpdateSensor(sensorFamily);
- }
-
- public void SetController(ControllerEx controllerEx)
- {
- // initilize controller
- this.controllerEx = controllerEx;
- }
-
- private void UpdateTimer_Ticked(object sender, EventArgs e)
- {
- if (Monitor.TryEnter(updateLock))
- {
- // update timestamp
- CurrentMicroseconds = stopwatch.ElapsedMilliseconds * 1000L;
- TotalMilliseconds = stopwatch.Elapsed.TotalMilliseconds;
- DeltaSeconds = (TotalMilliseconds - UpdateTimePreviousMilliseconds) / 1000L;
- UpdateTimePreviousMilliseconds = TotalMilliseconds;
-
- // update reading(s)
- foreach (XInputSensorFlags flags in (XInputSensorFlags[])Enum.GetValues(typeof(XInputSensorFlags)))
- {
- switch (flags)
- {
- case XInputSensorFlags.Default:
- AngularVelocities[flags] = Gyrometer.GetCurrentReading();
- Accelerations[flags] = Accelerometer.GetCurrentReading();
- break;
-
- case XInputSensorFlags.RawValue:
- AngularVelocities[flags] = Gyrometer.GetCurrentReadingRaw();
- Accelerations[flags] = Accelerometer.GetCurrentReadingRaw();
- break;
-
- case XInputSensorFlags.Centered:
- AngularVelocities[flags] = Gyrometer.GetCurrentReading(true);
- Accelerations[flags] = Accelerometer.GetCurrentReading(true);
- break;
-
- case XInputSensorFlags.WithRatio:
- AngularVelocities[flags] = Gyrometer.GetCurrentReading(false, true);
- Accelerations[flags] = Accelerometer.GetCurrentReading(false, false);
- break;
-
- case XInputSensorFlags.CenteredRatio:
- AngularVelocities[flags] = Gyrometer.GetCurrentReading(true, true);
- Accelerations[flags] = Accelerometer.GetCurrentReading(true, false);
- break;
-
- case XInputSensorFlags.CenteredRaw:
- AngularVelocities[flags] = Gyrometer.GetCurrentReadingRaw(true);
- Accelerations[flags] = Accelerometer.GetCurrentReadingRaw(true);
- break;
- }
- }
-
- Angle = Inclinometer.GetCurrentReading();
-
- // update sensorFusion (todo: call only when needed ?)
- sensorFusion.UpdateReport(TotalMilliseconds, DeltaSeconds, AngularVelocities[XInputSensorFlags.Centered], Accelerations[XInputSensorFlags.Default]);
-
-#if DEBUG
- LogManager.LogDebug("Plot AccelerationRawX {0} {1}", TotalMilliseconds, Accelerations[XInputSensorFlags.RawValue].X);
- LogManager.LogDebug("Plot AccelerationRawY {0} {1}", TotalMilliseconds, Accelerations[XInputSensorFlags.RawValue].Y);
- LogManager.LogDebug("Plot AccelerationRawZ {0} {1}", TotalMilliseconds, Accelerations[XInputSensorFlags.RawValue].Z);
-
- LogManager.LogDebug("Plot AngRawX {0} {1}", TotalMilliseconds, AngularVelocities[XInputSensorFlags.RawValue].X);
- LogManager.LogDebug("Plot AngRawY {0} {1}", TotalMilliseconds, AngularVelocities[XInputSensorFlags.RawValue].Y);
- LogManager.LogDebug("Plot AngRawZ {0} {1}", TotalMilliseconds, AngularVelocities[XInputSensorFlags.RawValue].Z);
-#endif
-
- // async update client(s)
- Task.Run(() =>
- {
- switch (ControllerService.CurrentTag)
- {
- case "ProfileSettingsMode0":
- pipeServer?.SendMessage(new PipeSensor(AngularVelocities[XInputSensorFlags.Centered], SensorType.Girometer));
- break;
-
- case "ProfileSettingsMode1":
- pipeServer?.SendMessage(new PipeSensor(Angle, SensorType.Inclinometer));
- break;
- }
-
- switch (ControllerService.CurrentOverlayStatus)
- {
- case 0: // Visible
- var AngularVelocityRad = new Vector3();
- AngularVelocityRad.X = -InputUtils.deg2rad(AngularVelocities[XInputSensorFlags.CenteredRaw].X);
- AngularVelocityRad.Y = -InputUtils.deg2rad(AngularVelocities[XInputSensorFlags.CenteredRaw].Y);
- AngularVelocityRad.Z = -InputUtils.deg2rad(AngularVelocities[XInputSensorFlags.CenteredRaw].Z);
- madgwickAHRS.UpdateReport(AngularVelocityRad.X, AngularVelocityRad.Y, AngularVelocityRad.Z, -Accelerations[XInputSensorFlags.RawValue].X, Accelerations[XInputSensorFlags.RawValue].Y, Accelerations[XInputSensorFlags.RawValue].Z, DeltaSeconds);
-
- pipeServer?.SendMessage(new PipeSensor(madgwickAHRS.GetEuler(), madgwickAHRS.GetQuaternion(), SensorType.Quaternion));
- break;
- }
- });
-
-#if DEBUG
- LogManager.LogDebug("Plot AccelerationRawX {0} {1}", TotalMilliseconds, Accelerations[XInputSensorFlags.RawValue].X);
- LogManager.LogDebug("Plot AccelerationRawY {0} {1}", TotalMilliseconds, Accelerations[XInputSensorFlags.RawValue].Y);
- LogManager.LogDebug("Plot AccelerationRawZ {0} {1}", TotalMilliseconds, Accelerations[XInputSensorFlags.RawValue].Z);
-
- LogManager.LogDebug("Plot GyroRawCX {0} {1}", TotalMilliseconds, Accelerations[XInputSensorFlags.CenteredRaw].X);
- LogManager.LogDebug("Plot GyroRawCY {0} {1}", TotalMilliseconds, Accelerations[XInputSensorFlags.CenteredRaw].Y);
- LogManager.LogDebug("Plot GyroRawCZ {0} {1}", TotalMilliseconds, Accelerations[XInputSensorFlags.CenteredRaw].Z);
-
- LogManager.LogDebug("Plot PoseX {0} {1}", TotalMilliseconds, madgwickAHRS.GetEuler().X);
- LogManager.LogDebug("Plot PoseY {0} {1}", TotalMilliseconds, madgwickAHRS.GetEuler().Y);
- LogManager.LogDebug("Plot PoseZ {0} {1}", TotalMilliseconds, madgwickAHRS.GetEuler().Z);
-#endif
-
- // get current gamepad state
- if (controllerEx != null && controllerEx.IsConnected())
- {
- GamepadState = controllerEx.GetState();
- Gamepad = GamepadState.Gamepad;
-
- // update virtual controller
- virtualTarget?.UpdateReport(Gamepad);
- }
-
- Updated?.Invoke(this);
-
- Monitor.Exit(updateLock);
- }
- }
-
- public void SetVibrationStrength(double strength)
- {
- vibrationStrength = strength;
- this.virtualTarget?.SetVibrationStrength(vibrationStrength);
- }
-
- public void AttachTarget(ViGEmTarget target)
- {
- if (target is null)
- return;
-
- this.virtualTarget = target;
-
- SetVibrationStrength(vibrationStrength);
-
- LogManager.LogInformation("{0} attached to {1} on slot {2}", target, ProductName, controllerEx.Controller.UserIndex);
- }
-
- public void DetachTarget()
- {
- if (virtualTarget is null)
- return;
-
- LogManager.LogInformation("{0} detached from {1} on slot {2}", virtualTarget, ProductName, controllerEx.Controller.UserIndex);
- this.virtualTarget = null;
- }
- }
-}
\ No newline at end of file
diff --git a/HandheldCompanion/App.config b/HandheldCompanion/App.config
index 7cdace4c9..e0374defa 100644
--- a/HandheldCompanion/App.config
+++ b/HandheldCompanion/App.config
@@ -160,6 +160,18 @@
True
+
+ True
+
+
+ True
+
+
+ 100
+
+
+
+
\ No newline at end of file
diff --git a/HandheldCompanion/App.xaml.cs b/HandheldCompanion/App.xaml.cs
index f7ac10aa8..30b47dc24 100644
--- a/HandheldCompanion/App.xaml.cs
+++ b/HandheldCompanion/App.xaml.cs
@@ -49,7 +49,7 @@ protected override void OnStartup(StartupEventArgs args)
IntPtr handle = process.MainWindowHandle;
if (ProcessUtils.IsIconic(handle))
- ProcessUtils.ShowWindow(handle, ProcessUtils.SW_RESTORE);
+ ProcessUtils.ShowWindow(handle, (int)ProcessUtils.ShowWindowCommands.Restored);
ProcessUtils.SetForegroundWindow(handle);
diff --git a/HandheldCompanion/HandheldCompanion.csproj b/HandheldCompanion/HandheldCompanion.csproj
index 48bce7a3f..82e116111 100644
--- a/HandheldCompanion/HandheldCompanion.csproj
+++ b/HandheldCompanion/HandheldCompanion.csproj
@@ -52,6 +52,18 @@
+
+
+ tlbimp
+ 0
+ 1
+ 50a7e9b0-70ef-11d1-b75a-00a0c90564fe
+ 0
+ false
+ true
+
+
+
PreserveNewest
@@ -83,12 +95,12 @@
-
+
-
+
@@ -136,16 +148,16 @@
PreserveNewest
-
+
Always
-
+
Always
-
+
Always
-
+
Always
@@ -250,16 +262,28 @@
Always
-
+
+ Always
+
+
Always
-
+
Always
-
+
Always
-
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
Always
@@ -430,19 +454,19 @@
Always
-
+
Always
-
+
Always
Always
-
+
Always
-
+
Always
@@ -463,10 +487,10 @@
Always
-
+
Always
-
+
Always
@@ -514,6 +538,12 @@
Always
+
+ Always
+
+
+ Always
+
Always
@@ -553,16 +583,16 @@
Always
-
+
Always
-
+
Always
-
+
Always
-
+
Always
@@ -571,6 +601,18 @@
Always
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
Always
@@ -664,6 +706,30 @@
Always
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
Always
@@ -715,7 +781,7 @@
Always
-
+
Always
@@ -757,12 +823,138 @@
Always
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
Always
Always
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
Always
@@ -793,7 +985,7 @@
Always
-
+
Always
@@ -916,19 +1108,19 @@
Always
-
+
Always
-
+
Always
-
+
Always
-
+
Always
-
+
Always
@@ -982,10 +1174,10 @@
Always
-
+
Always
-
+
Always
@@ -1027,6 +1219,30 @@
Always
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
Always
@@ -1063,7 +1279,7 @@
Always
-
+
Always
@@ -1087,7 +1303,7 @@
Always
-
+
Always
@@ -1129,7 +1345,7 @@
Always
-
+
Always
@@ -1147,22 +1363,22 @@
Always
-
+
Always
-
+
Always
-
+
Always
-
+
Always
Always
-
+
Always
@@ -1255,46 +1471,46 @@
Always
-
+
Always
-
+
Always
-
+
Always
-
+
Always
-
+
Always
-
+
Always
-
+
Always
Always
-
+
Always
-
+
Always
Always
-
+
Always
Always
-
+
Always
@@ -1351,55 +1567,58 @@
Always
+
+ Always
+
Always
Always
-
+
Always
-
+
Always
-
+
Always
-
+
Always
Always
-
+
Always
-
+
Always
-
+
Always
-
+
Always
-
+
Always
-
+
Always
-
+
Always
-
+
Always
-
+