diff --git a/DS4Control/MouseCursor.cs b/DS4Control/MouseCursor.cs new file mode 100644 index 0000000..e557469 --- /dev/null +++ b/DS4Control/MouseCursor.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using DS4Library; + +namespace DS4Control +{ + class MouseCursor + { + private readonly int deviceNumber; + public MouseCursor(int deviceNum) + { + deviceNumber = deviceNum; + } + + // Keep track of remainders when performing moves or we lose fractional parts. + private double horizontalRemainder = 0.0, verticalRemainder = 0.0; + + public void touchesBegan(TouchpadEventArgs arg) + { + if (arg.touches.Length == 1) + horizontalRemainder = verticalRemainder = 0.0; + } + + private byte lastTouchID; + public void touchesMoved(TouchpadEventArgs arg) + { + if (arg.touches.Length != 1) + return; + int deltaX, deltaY; + if (arg.touches[0].touchID != lastTouchID) + { + deltaX = deltaY = 0; + horizontalRemainder = verticalRemainder = 0.0; + lastTouchID = arg.touches[0].touchID; + } + else if (Global.getTouchpadJitterCompensation(deviceNumber)) + { + // Often the DS4's internal jitter compensation kicks in and starts hiding changes, ironically creating jitter... + deltaX = arg.touches[0].deltaX; + deltaY = arg.touches[0].deltaY; + // allow only very fine, slow motions, when changing direction + if (deltaX < -1) + { + if (horizontalRemainder >= 0.0) + { + deltaX = -1; + horizontalRemainder = 0.0; + } + } + else if (deltaX > 1) + { + if (horizontalRemainder <= 0.0) + { + deltaX = 1; + horizontalRemainder = 0.0; + } + } + + if (deltaY < -1) + { + if (verticalRemainder >= 0.0) + { + deltaY = -1; + verticalRemainder = 0.0; + } + } + else if (deltaY > 1) + { + if (verticalRemainder <= 0.0) + { + deltaY = 1; + verticalRemainder = 0.0; + } + } + } + else + { + deltaX = arg.touches[0].deltaX; + deltaY = arg.touches[0].deltaY; + } + + double coefficient = Global.getTouchSensitivity(deviceNumber) / 100.0; + // Collect rounding errors instead of losing motion. + double xMotion = coefficient * deltaX; + if (xMotion > 0.0) + { + if (horizontalRemainder > 0.0) + xMotion += horizontalRemainder; + } + else if (xMotion < 0.0) + { + if (horizontalRemainder < 0.0) + xMotion += horizontalRemainder; + } + int xAction = (int)xMotion; + horizontalRemainder = xMotion - xAction; + + double yMotion = coefficient * deltaY; + if (yMotion > 0.0) + { + if (verticalRemainder > 0.0) + yMotion += verticalRemainder; + } + else if (yMotion < 0.0) + { + if (verticalRemainder < 0.0) + yMotion += verticalRemainder; + } + int yAction = (int)yMotion; + verticalRemainder = yMotion - yAction; + + if (yAction != 0 || xAction != 0) + InputMethods.MoveCursorBy(xAction, yAction); + } + } +} diff --git a/DS4Control/MouseWheel.cs b/DS4Control/MouseWheel.cs new file mode 100644 index 0000000..39dce1f --- /dev/null +++ b/DS4Control/MouseWheel.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using DS4Library; + +namespace DS4Control +{ + class MouseWheel + { + private readonly int deviceNumber; + public MouseWheel(int deviceNum) + { + deviceNumber = deviceNum; + } + + // Keep track of remainders when performing scrolls or we lose fractional parts. + private double horizontalRemainder = 0.0, verticalRemainder = 0.0; + + public void touchesBegan(TouchpadEventArgs arg) + { + if (arg.touches.Length == 2) + horizontalRemainder = verticalRemainder = 0.0; + } + + public void touchesMoved(TouchpadEventArgs arg) + { + if (arg.touches.Length != 2) + return; + Touch lastT0 = arg.touches[0].previousTouch; + Touch lastT1 = arg.touches[1].previousTouch; + Touch T0 = arg.touches[0]; + Touch T1 = arg.touches[1]; + + //mouse wheel 120 == 1 wheel click according to Windows API + int lastMidX = (lastT0.hwX + lastT1.hwX) / 2, lastMidY = (lastT0.hwY + lastT1.hwY) / 2, + currentMidX = (T0.hwX + T1.hwX) / 2, currentMidY = (T0.hwY + T1.hwY) / 2; + double coefficient = Global.getScrollSensitivity(deviceNumber); + // Adjust for touch distance: "standard" distance is 960 pixels, i.e. half the width. Scroll farther if fingers are farther apart, and vice versa, in linear proportion. + double touchXDistance = T1.hwX - T0.hwX, touchYDistance = T1.hwY - T0.hwY, touchDistance = Math.Sqrt(touchXDistance * touchXDistance + touchYDistance * touchYDistance); + coefficient *= touchDistance / 960.0; + + // Collect rounding errors instead of losing motion. + double xMotion = coefficient * (currentMidX - lastMidX); + if (xMotion > 0.0) + { + if (horizontalRemainder > 0.0) + xMotion += horizontalRemainder; + } + else if (xMotion < 0.0) + { + if (horizontalRemainder < 0.0) + xMotion += horizontalRemainder; + } + int xAction = (int)xMotion; + horizontalRemainder = xMotion - xAction; + + double yMotion = coefficient * (lastMidY - currentMidY); + if (yMotion > 0.0) + { + if (verticalRemainder > 0.0) + yMotion += verticalRemainder; + } + else if (yMotion < 0.0) + { + if (verticalRemainder < 0.0) + yMotion += verticalRemainder; + } + int yAction = (int)yMotion; + verticalRemainder = yMotion - yAction; + + if (yAction != 0 || xAction != 0) + InputMethods.MouseWheel(yAction, xAction); + } + } +} diff --git a/DS4Tool/HidDevices.cs b/DS4Tool/HidDevices.cs new file mode 100644 index 0000000..e66fc6e --- /dev/null +++ b/DS4Tool/HidDevices.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; + +namespace HidLibrary +{ + public class HidDevices + { + private static Guid _hidClassGuid = Guid.Empty; + + public static bool IsConnected(string devicePath) + { + return EnumerateDevices().Any(x => x.Path == devicePath); + } + + public static HidDevice GetDevice(string devicePath) + { + return Enumerate(devicePath).FirstOrDefault(); + } + + public static IEnumerable Enumerate() + { + return EnumerateDevices().Select(x => new HidDevice(x.Path, x.Description)); + } + + public static IEnumerable Enumerate(string devicePath) + { + return EnumerateDevices().Where(x => x.Path == devicePath).Select(x => new HidDevice(x.Path, x.Description)); + } + + public static IEnumerable Enumerate(int vendorId, params int[] productIds) + { + return EnumerateDevices().Select(x => new HidDevice(x.Path, x.Description)).Where(x => x.Attributes.VendorId == vendorId && + productIds.Contains(x.Attributes.ProductId)); + } + + public static IEnumerable Enumerate(int vendorId) + { + return EnumerateDevices().Select(x => new HidDevice(x.Path, x.Description)).Where(x => x.Attributes.VendorId == vendorId); + } + + private class DeviceInfo { public string Path { get; set; } public string Description { get; set; } } + + private static IEnumerable EnumerateDevices() + { + var devices = new List(); + var hidClass = HidClassGuid; + var deviceInfoSet = NativeMethods.SetupDiGetClassDevs(ref hidClass, null, 0, NativeMethods.DIGCF_PRESENT | NativeMethods.DIGCF_DEVICEINTERFACE); + + if (deviceInfoSet.ToInt64() != NativeMethods.INVALID_HANDLE_VALUE) + { + var deviceInfoData = CreateDeviceInfoData(); + var deviceIndex = 0; + + while (NativeMethods.SetupDiEnumDeviceInfo(deviceInfoSet, deviceIndex, ref deviceInfoData)) + { + deviceIndex += 1; + + var deviceInterfaceData = new NativeMethods.SP_DEVICE_INTERFACE_DATA(); + deviceInterfaceData.cbSize = Marshal.SizeOf(deviceInterfaceData); + var deviceInterfaceIndex = 0; + + while (NativeMethods.SetupDiEnumDeviceInterfaces(deviceInfoSet, ref deviceInfoData, ref hidClass, deviceInterfaceIndex, ref deviceInterfaceData)) + { + deviceInterfaceIndex++; + var devicePath = GetDevicePath(deviceInfoSet, deviceInterfaceData); + var description = GetBusReportedDeviceDescription(deviceInfoSet, ref deviceInfoData) ?? + GetDeviceDescription(deviceInfoSet, ref deviceInfoData); + devices.Add(new DeviceInfo { Path = devicePath, Description = description }); + } + } + NativeMethods.SetupDiDestroyDeviceInfoList(deviceInfoSet); + } + return devices; + } + + private static NativeMethods.SP_DEVINFO_DATA CreateDeviceInfoData() + { + var deviceInfoData = new NativeMethods.SP_DEVINFO_DATA(); + + deviceInfoData.cbSize = Marshal.SizeOf(deviceInfoData); + deviceInfoData.DevInst = 0; + deviceInfoData.ClassGuid = Guid.Empty; + deviceInfoData.Reserved = IntPtr.Zero; + + return deviceInfoData; + } + + private static string GetDevicePath(IntPtr deviceInfoSet, NativeMethods.SP_DEVICE_INTERFACE_DATA deviceInterfaceData) + { + var bufferSize = 0; + var interfaceDetail = new NativeMethods.SP_DEVICE_INTERFACE_DETAIL_DATA { Size = IntPtr.Size == 4 ? 4 + Marshal.SystemDefaultCharSize : 8 }; + + NativeMethods.SetupDiGetDeviceInterfaceDetailBuffer(deviceInfoSet, ref deviceInterfaceData, IntPtr.Zero, 0, ref bufferSize, IntPtr.Zero); + + return NativeMethods.SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref deviceInterfaceData, ref interfaceDetail, bufferSize, ref bufferSize, IntPtr.Zero) ? + interfaceDetail.DevicePath : null; + } + + private static Guid HidClassGuid + { + get + { + if (_hidClassGuid.Equals(Guid.Empty)) NativeMethods.HidD_GetHidGuid(ref _hidClassGuid); + return _hidClassGuid; + } + } + + private static string GetDeviceDescription(IntPtr deviceInfoSet, ref NativeMethods.SP_DEVINFO_DATA devinfoData) + { + var descriptionBuffer = new byte[1024]; + + var requiredSize = 0; + var type = 0; + + NativeMethods.SetupDiGetDeviceRegistryProperty(deviceInfoSet, + ref devinfoData, + NativeMethods.SPDRP_DEVICEDESC, + ref type, + descriptionBuffer, + descriptionBuffer.Length, + ref requiredSize); + + return descriptionBuffer.ToUTF8String(); + } + + private static string GetBusReportedDeviceDescription(IntPtr deviceInfoSet, ref NativeMethods.SP_DEVINFO_DATA devinfoData) + { + var descriptionBuffer = new byte[1024]; + + if (Environment.OSVersion.Version.Major > 5) + { + ulong propertyType = 0; + var requiredSize = 0; + + var _continue = NativeMethods.SetupDiGetDeviceProperty(deviceInfoSet, + ref devinfoData, + ref NativeMethods.DEVPKEY_Device_BusReportedDeviceDesc, + ref propertyType, + descriptionBuffer, + descriptionBuffer.Length, + ref requiredSize, + 0); + + if (_continue) return descriptionBuffer.ToUTF16String(); + } + return null; + } + } +} diff --git a/DS4Tool/Options.Designer.cs b/DS4Tool/Options.Designer.cs index 16de698..6250e97 100644 --- a/DS4Tool/Options.Designer.cs +++ b/DS4Tool/Options.Designer.cs @@ -847,6 +847,9 @@ this.Controls.Add(this.saveButton); this.Controls.Add(this.CustomMappingButton); this.Controls.Add(this.setButton); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.MinimizeBox = false; this.MinimumSize = new System.Drawing.Size(470, 282); this.Name = "Options"; this.Text = "Options";