From df43fd0d74ce5b3cd3241c08082f4f9ef5bad1b7 Mon Sep 17 00:00:00 2001 From: jays2kings Date: Thu, 27 Mar 2014 21:50:40 -0400 Subject: [PATCH] Revised Custom Mapping I kinda just felt like doing it :P wanted to test myself, trying to make a cleaner UI --- .gitattributes | 63 + .gitignore | 156 + DS4Control/ButtonMouse.cs | 200 + DS4Control/Control.cs | 287 + DS4Control/CursorOnlyMode.cs | 43 + DS4Control/DS4Control.csproj | 91 + DS4Control/DS4LightBar.cs | 63 + DS4Control/DragMouse.cs | 149 + DS4Control/ITouchpadBehaviour.cs | 16 + DS4Control/InputMethods.cs | 255 + DS4Control/Log.cs | 30 + DS4Control/Mapping.cs | 488 ++ DS4Control/Mouse.cs | 136 + DS4Control/Properties/AssemblyInfo.cs | 36 + DS4Control/ScpDevice.Designer.cs | 36 + DS4Control/ScpDevice.cs | 707 +++ DS4Control/ScpHub.Designer.cs | 36 + DS4Control/ScpHub.cs | 87 + DS4Control/ScpUtil.cs | 817 +++ DS4Control/TPadModeSwitcher.cs | 80 + DS4Control/TouchpadDisabled.cs | 30 + DS4Control/X360Device.cs | 203 + DS4Control/X360Device.designer.cs | 36 + DS4Library/DS4Device.cs | 482 ++ DS4Library/DS4Devices.cs | 90 + DS4Library/DS4Library.csproj | 65 + DS4Library/DS4State.cs | 95 + DS4Library/DS4StateExposed.cs | 73 + DS4Library/DS4Touchpad.cs | 178 + DS4Library/NativeMethods.cs | 30 + DS4Library/Properties/AssemblyInfo.cs | 36 + DS4Service/DS4Service.Designer.cs | 41 + DS4Service/DS4Service.cs | 39 + DS4Service/DS4Service.csproj | 84 + DS4Service/Program.cs | 24 + DS4Service/ProjectInstaller.cs | 15 + DS4Service/ProjectInstaller.designer.cs | 60 + DS4Service/ProjectInstaller.resx | 129 + DS4Service/Properties/AssemblyInfo.cs | 36 + DS4Tool.sln | 68 + DS4Tool/AboutBox.Designer.cs | 97 + DS4Tool/AboutBox.cs | 34 + DS4Tool/AboutBox.resx | 120 + DS4Tool/AdvancedColorDialog.cs | 170 + DS4Tool/AdvancedComboBox.cs | 93 + DS4Tool/CustomMapping.Designer.cs | 732 +++ DS4Tool/CustomMapping.cs | 332 ++ DS4Tool/CustomMapping.resx | 120 + DS4Tool/DS4Tool.csproj | 240 + DS4Tool/Hotkeys.Designer.cs | 241 + DS4Tool/Hotkeys.cs | 24 + DS4Tool/Hotkeys.resx | 120 + DS4Tool/Options.Designer.cs | 947 ++++ DS4Tool/Options.cs | 535 ++ DS4Tool/Options.resx | 123 + DS4Tool/Program.cs | 28 + DS4Tool/Properties/AssemblyInfo.cs | 36 + DS4Tool/Properties/Resources.Designer.cs | 381 ++ DS4Tool/Properties/Resources.resx | 219 + DS4Tool/Properties/Settings.Designer.cs | 26 + DS4Tool/Properties/Settings.settings | 7 + DS4Tool/ReadInputForm.Designer.cs | 114 + DS4Tool/ReadInputForm.cs | 157 + DS4Tool/ReadInputForm.resx | 123 + DS4Tool/Resources/1.png | Bin 0 -> 47362 bytes DS4Tool/Resources/10.png | Bin 0 -> 47402 bytes DS4Tool/Resources/11.png | Bin 0 -> 47525 bytes DS4Tool/Resources/12.png | Bin 0 -> 47320 bytes DS4Tool/Resources/13.png | Bin 0 -> 47293 bytes DS4Tool/Resources/14.png | Bin 0 -> 47225 bytes DS4Tool/Resources/15.png | Bin 0 -> 47268 bytes DS4Tool/Resources/16.png | Bin 0 -> 47309 bytes DS4Tool/Resources/17.png | Bin 0 -> 47348 bytes DS4Tool/Resources/18.png | Bin 0 -> 45318 bytes DS4Tool/Resources/19.png | Bin 0 -> 47376 bytes DS4Tool/Resources/2.png | Bin 0 -> 47608 bytes DS4Tool/Resources/20.png | Bin 0 -> 47337 bytes DS4Tool/Resources/21.png | Bin 0 -> 48249 bytes DS4Tool/Resources/22.png | Bin 0 -> 47581 bytes DS4Tool/Resources/23.png | Bin 0 -> 47593 bytes DS4Tool/Resources/24.png | Bin 0 -> 47596 bytes DS4Tool/Resources/25.png | Bin 0 -> 47547 bytes DS4Tool/Resources/26.png | Bin 0 -> 47585 bytes DS4Tool/Resources/27.png | Bin 0 -> 47570 bytes DS4Tool/Resources/28.png | Bin 0 -> 47608 bytes DS4Tool/Resources/29.png | Bin 0 -> 47620 bytes DS4Tool/Resources/3.png | Bin 0 -> 47584 bytes DS4Tool/Resources/4.png | Bin 0 -> 47592 bytes DS4Tool/Resources/5.png | Bin 0 -> 47524 bytes DS4Tool/Resources/6.png | Bin 0 -> 47285 bytes DS4Tool/Resources/7.png | Bin 0 -> 47300 bytes DS4Tool/Resources/8.png | Bin 0 -> 47352 bytes DS4Tool/Resources/9.png | Bin 0 -> 47327 bytes DS4Tool/Resources/DS4.ico | Bin 0 -> 370070 bytes DS4Tool/Resources/Scp_All.ico | Bin 0 -> 370070 bytes DS4Tool/ScpForm.Designer.cs | 373 ++ DS4Tool/ScpForm.cs | 287 + DS4Tool/ScpForm.resx | 6299 ++++++++++++++++++++++ DS4Tool/Settings.cs | 28 + DS4Tool/app.config | 3 + HidLibrary/Extensions.cs | 19 + HidLibrary/HidDevice.cs | 423 ++ HidLibrary/HidDeviceAttributes.cs | 21 + HidLibrary/HidDeviceCapabilities.cs | 43 + HidLibrary/HidDeviceEventMonitor.cs | 41 + HidLibrary/HidDevices.cs | 152 + HidLibrary/HidLibrary.csproj | 67 + HidLibrary/LICENSE.htm | 739 +++ HidLibrary/NativeMethods.cs | 349 ++ HidLibrary/Properties/AssemblyInfo.cs | 36 + 110 files changed, 19489 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 DS4Control/ButtonMouse.cs create mode 100644 DS4Control/Control.cs create mode 100644 DS4Control/CursorOnlyMode.cs create mode 100644 DS4Control/DS4Control.csproj create mode 100644 DS4Control/DS4LightBar.cs create mode 100644 DS4Control/DragMouse.cs create mode 100644 DS4Control/ITouchpadBehaviour.cs create mode 100644 DS4Control/InputMethods.cs create mode 100644 DS4Control/Log.cs create mode 100644 DS4Control/Mapping.cs create mode 100644 DS4Control/Mouse.cs create mode 100644 DS4Control/Properties/AssemblyInfo.cs create mode 100644 DS4Control/ScpDevice.Designer.cs create mode 100644 DS4Control/ScpDevice.cs create mode 100644 DS4Control/ScpHub.Designer.cs create mode 100644 DS4Control/ScpHub.cs create mode 100644 DS4Control/ScpUtil.cs create mode 100644 DS4Control/TPadModeSwitcher.cs create mode 100644 DS4Control/TouchpadDisabled.cs create mode 100644 DS4Control/X360Device.cs create mode 100644 DS4Control/X360Device.designer.cs create mode 100644 DS4Library/DS4Device.cs create mode 100644 DS4Library/DS4Devices.cs create mode 100644 DS4Library/DS4Library.csproj create mode 100644 DS4Library/DS4State.cs create mode 100644 DS4Library/DS4StateExposed.cs create mode 100644 DS4Library/DS4Touchpad.cs create mode 100644 DS4Library/NativeMethods.cs create mode 100644 DS4Library/Properties/AssemblyInfo.cs create mode 100644 DS4Service/DS4Service.Designer.cs create mode 100644 DS4Service/DS4Service.cs create mode 100644 DS4Service/DS4Service.csproj create mode 100644 DS4Service/Program.cs create mode 100644 DS4Service/ProjectInstaller.cs create mode 100644 DS4Service/ProjectInstaller.designer.cs create mode 100644 DS4Service/ProjectInstaller.resx create mode 100644 DS4Service/Properties/AssemblyInfo.cs create mode 100644 DS4Tool.sln create mode 100644 DS4Tool/AboutBox.Designer.cs create mode 100644 DS4Tool/AboutBox.cs create mode 100644 DS4Tool/AboutBox.resx create mode 100644 DS4Tool/AdvancedColorDialog.cs create mode 100644 DS4Tool/AdvancedComboBox.cs create mode 100644 DS4Tool/CustomMapping.Designer.cs create mode 100644 DS4Tool/CustomMapping.cs create mode 100644 DS4Tool/CustomMapping.resx create mode 100644 DS4Tool/DS4Tool.csproj create mode 100644 DS4Tool/Hotkeys.Designer.cs create mode 100644 DS4Tool/Hotkeys.cs create mode 100644 DS4Tool/Hotkeys.resx create mode 100644 DS4Tool/Options.Designer.cs create mode 100644 DS4Tool/Options.cs create mode 100644 DS4Tool/Options.resx create mode 100644 DS4Tool/Program.cs create mode 100644 DS4Tool/Properties/AssemblyInfo.cs create mode 100644 DS4Tool/Properties/Resources.Designer.cs create mode 100644 DS4Tool/Properties/Resources.resx create mode 100644 DS4Tool/Properties/Settings.Designer.cs create mode 100644 DS4Tool/Properties/Settings.settings create mode 100644 DS4Tool/ReadInputForm.Designer.cs create mode 100644 DS4Tool/ReadInputForm.cs create mode 100644 DS4Tool/ReadInputForm.resx create mode 100644 DS4Tool/Resources/1.png create mode 100644 DS4Tool/Resources/10.png create mode 100644 DS4Tool/Resources/11.png create mode 100644 DS4Tool/Resources/12.png create mode 100644 DS4Tool/Resources/13.png create mode 100644 DS4Tool/Resources/14.png create mode 100644 DS4Tool/Resources/15.png create mode 100644 DS4Tool/Resources/16.png create mode 100644 DS4Tool/Resources/17.png create mode 100644 DS4Tool/Resources/18.png create mode 100644 DS4Tool/Resources/19.png create mode 100644 DS4Tool/Resources/2.png create mode 100644 DS4Tool/Resources/20.png create mode 100644 DS4Tool/Resources/21.png create mode 100644 DS4Tool/Resources/22.png create mode 100644 DS4Tool/Resources/23.png create mode 100644 DS4Tool/Resources/24.png create mode 100644 DS4Tool/Resources/25.png create mode 100644 DS4Tool/Resources/26.png create mode 100644 DS4Tool/Resources/27.png create mode 100644 DS4Tool/Resources/28.png create mode 100644 DS4Tool/Resources/29.png create mode 100644 DS4Tool/Resources/3.png create mode 100644 DS4Tool/Resources/4.png create mode 100644 DS4Tool/Resources/5.png create mode 100644 DS4Tool/Resources/6.png create mode 100644 DS4Tool/Resources/7.png create mode 100644 DS4Tool/Resources/8.png create mode 100644 DS4Tool/Resources/9.png create mode 100644 DS4Tool/Resources/DS4.ico create mode 100644 DS4Tool/Resources/Scp_All.ico create mode 100644 DS4Tool/ScpForm.Designer.cs create mode 100644 DS4Tool/ScpForm.cs create mode 100644 DS4Tool/ScpForm.resx create mode 100644 DS4Tool/Settings.cs create mode 100644 DS4Tool/app.config create mode 100644 HidLibrary/Extensions.cs create mode 100644 HidLibrary/HidDevice.cs create mode 100644 HidLibrary/HidDeviceAttributes.cs create mode 100644 HidLibrary/HidDeviceCapabilities.cs create mode 100644 HidLibrary/HidDeviceEventMonitor.cs create mode 100644 HidLibrary/HidDevices.cs create mode 100644 HidLibrary/HidLibrary.csproj create mode 100644 HidLibrary/LICENSE.htm create mode 100644 HidLibrary/NativeMethods.cs create mode 100644 HidLibrary/Properties/AssemblyInfo.cs diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1bc915c --- /dev/null +++ b/.gitignore @@ -0,0 +1,156 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +build/ +[Bb]in/ +[Oo]bj/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml + +# NuGet Packages Directory +## TODO: If you have NuGet Package Restore enabled, uncomment the next line +#packages/ + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml +*.pfx +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + + +#LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac desktop service store files +.DS_Store diff --git a/DS4Control/ButtonMouse.cs b/DS4Control/ButtonMouse.cs new file mode 100644 index 0000000..b2d8ffc --- /dev/null +++ b/DS4Control/ButtonMouse.cs @@ -0,0 +1,200 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; +using DS4Library; +namespace DS4Control +{ + public class ButtonMouse : ITouchpadBehaviour + { + private int deviceNum; + private bool leftButton, middleButton, rightButton; + private DS4State s = new DS4State(); + private bool buttonLock; // Toggled with a two-finger touchpad push, we accept and absorb button input without any fingers on a touchpad, helping with drag-and-drop. + private DS4Device dev = null; + public ButtonMouse(int deviceID, DS4Device d) + { + deviceNum = deviceID; + dev = d; + } + + public override string ToString() + { + return "Button Mode"; + } + + public void touchesMoved(object sender, TouchpadEventArgs arg) + { + if (arg.touches.Length == 1) + { + double sensitivity = Global.getTouchSensitivity(deviceNum) / 100.0; + int mouseDeltaX = (int)(sensitivity * (arg.touches[0].deltaX)); + int mouseDeltaY = (int)(sensitivity * (arg.touches[0].deltaY)); + InputMethods.MoveCursorBy(mouseDeltaX, mouseDeltaY); + } + else if (arg.touches.Length == 2) + { + 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; // XXX Will controller swap touch IDs? + double coefficient = Global.getScrollSensitivity(deviceNum); + // 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; + InputMethods.MouseWheel((int)(coefficient * (lastMidY - currentMidY)), (int)(coefficient * (currentMidX - lastMidX))); + } + synthesizeMouseButtons(false); + } + + public void untouched() + { + if (buttonLock) + synthesizeMouseButtons(false); + else + dev.getCurrentState(s); + } + + public void touchesBegan(object sender, TouchpadEventArgs arg) + { + synthesizeMouseButtons(false); + } + + public void touchesEnded(object sender, TouchpadEventArgs arg) + { + if (!buttonLock) + synthesizeMouseButtons(true); + else + dev.getCurrentState(s); + } + + private void synthesizeMouseButtons(bool justRelease) + { + dev.getCurrentState(s); + bool previousLeftButton = leftButton, previousMiddleButton = middleButton, previousRightButton = rightButton; + if (justRelease) + { + leftButton = middleButton = rightButton = false; + } + else + { + leftButton = s.L1 || s.R1 || s.DpadLeft || s.Square; + middleButton = s.DpadUp || s.DpadDown || s.Triangle || s.Cross; + rightButton = s.DpadRight || s.Circle; + s.L1 = s.R1 = s.DpadLeft = s.Square = s.DpadUp = s.DpadDown = s.Triangle = s.Cross = s.DpadRight = s.Circle = false; + } + if (leftButton != previousLeftButton) + InputMethods.MouseEvent(leftButton ? InputMethods.MOUSEEVENTF_LEFTDOWN : InputMethods.MOUSEEVENTF_LEFTUP); + if (middleButton != previousMiddleButton) + InputMethods.MouseEvent(middleButton ? InputMethods.MOUSEEVENTF_MIDDLEDOWN : InputMethods.MOUSEEVENTF_MIDDLEUP); + if (rightButton != previousRightButton) + InputMethods.MouseEvent(rightButton ? InputMethods.MOUSEEVENTF_RIGHTDOWN : InputMethods.MOUSEEVENTF_RIGHTUP); + + } + + // touch area stuff + private bool leftDown, rightDown, upperDown; + private bool isLeft(Touch t) + { + return t.hwX < 1920 * 2 / 5; + } + + private bool isRight(Touch t) + { + return t.hwX >= 1920 * 3 / 5; + } + + public void touchButtonUp(object sender, TouchpadEventArgs arg) + { + if (upperDown) + { + mapTouchPad(DS4Controls.TouchUpper, true); + upperDown = false; + } + if (leftDown) + { + mapTouchPad(DS4Controls.TouchButton, true); + leftDown = false; + } + if (rightDown) + { + mapTouchPad(DS4Controls.TouchMulti, true); + rightDown = false; + } + dev.setRumble(0, 0); + } + + public void touchButtonDown(object sender, TouchpadEventArgs arg) + { + byte leftRumble, rightRumble; + if (arg.touches == null) //No touches, finger on upper portion of touchpad + { + mapTouchPad(DS4Controls.TouchUpper, false); + upperDown = true; + leftRumble = rightRumble = 127; + } + else if (arg.touches.Length == 1) + { + if (isLeft(arg.touches[0])) + { + mapTouchPad(DS4Controls.TouchButton, false); + leftDown = true; + leftRumble = 63; + rightRumble = 0; + } + else if (isRight(arg.touches[0])) + { + mapTouchPad(DS4Controls.TouchMulti, false); + rightDown = true; + leftRumble = 0; + rightRumble = 63; + } + else + { + mapTouchPad(DS4Controls.TouchUpper, false); // ambiguous = same as upper + upperDown = true; + leftRumble = rightRumble = 127; + } + } + else + { + buttonLock = !buttonLock; + leftRumble = rightRumble = (byte)(buttonLock ? 255 : 63); + } + dev.setRumble(rightRumble, leftRumble); // sustain while pressed + } + + bool mapTouchPad(DS4Controls padControl, bool release) + { + ushort key = Global.getCustomKey(padControl); + if (key == 0) + return false; + else + { + DS4KeyType keyType = Global.getCustomKeyType(padControl); + if (!release) + if (keyType.HasFlag(DS4KeyType.ScanCode)) + InputMethods.performSCKeyPress(key); + else InputMethods.performKeyPress(key); + else + if (!keyType.HasFlag(DS4KeyType.Repeat)) + if (keyType.HasFlag(DS4KeyType.ScanCode)) + InputMethods.performSCKeyRelease(key); + else InputMethods.performKeyRelease(key); + return true; + } + } + + public DS4State getDS4State() + { + return s; + } + + } +} + diff --git a/DS4Control/Control.cs b/DS4Control/Control.cs new file mode 100644 index 0000000..22784ec --- /dev/null +++ b/DS4Control/Control.cs @@ -0,0 +1,287 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using DS4Library; +namespace DS4Control +{ + public class Control: IDisposable + { + X360Device x360Bus; + DS4Device[] DS4Controllers = new DS4Device[4]; + TPadModeSwitcher[] modeSwitcher = new TPadModeSwitcher[4]; + private bool running = false; + private DS4State[] MappedState = new DS4State[4]; + private DS4State[] CurrentState = new DS4State[4]; + private DS4State[] PreviousState = new DS4State[4]; + public DS4StateExposed[] ExposedState = new DS4StateExposed[4]; + + public event EventHandler Debug = null; + + private class X360Data + { + public byte[] Report = new byte[28]; + public byte[] Rumble = new byte[8]; + } + private X360Data[] processingData = new X360Data[4]; + + public Control() + { + x360Bus = new X360Device(); + for (int i = 0; i < DS4Controllers.Length; i++) + { + processingData[i] = new X360Data(); + MappedState[i] = new DS4State(); + CurrentState[i] = new DS4State(); + PreviousState[i] = new DS4State(); + ExposedState[i] = new DS4StateExposed(CurrentState[i]); + } + } + + public bool Start() + { + if (x360Bus.Open() && x360Bus.Start()) + { + LogDebug("Starting..."); + DS4Devices.isExclusiveMode = Global.getUseExclusiveMode(); + LogDebug("Searching for controllers...."); + LogDebug("Using " + (DS4Devices.isExclusiveMode ? "Exclusive Mode": "Shared Mode")); + try + { + DS4Devices.findControllers(); + IEnumerable devices = DS4Devices.getDS4Controllers(); + int ind = 0; + foreach (DS4Device device in devices) + { + LogDebug("Found Controller: " + device.MacAddress); + if (device.MacAddress == "00:00:00:00:00:00") + { + LogDebug("WARNING: If you are seing all zeroes as controller ID"); + LogDebug("You might be running not fully supported BT dongle"); + LogDebug("Only some basic functionality is enabled"); + } + DS4Controllers[ind] = device; + device.Removal += this.On_DS4Removal; + TPadModeSwitcher m_switcher = new TPadModeSwitcher(device, ind); + m_switcher.Debug += OnDebug; + m_switcher.setMode(Global.getTouchEnabled(ind) ? 1 : 0); + modeSwitcher[ind] = m_switcher; + DS4Color color = Global.loadColor(ind); + device.LightBarColor = color; + x360Bus.Plugin(ind + 1); + device.Report += this.On_Report; + ind++; + LogDebug("Controller: " + device.MacAddress + " is ready to use"); + Log.LogToTray("Controller: " + device.MacAddress + " is ready to use"); + if (ind >= 4) + break; + } + } + catch (Exception e) + { + LogDebug(e.Message); + } + running = true; + + } + return true; + } + + public bool Stop() + { + if (running) + { + running = false; + LogDebug("Stopping X360 Controllers"); + for (int i = 0; i < DS4Controllers.Length; i++) + { + if (DS4Controllers[i] != null) + { + x360Bus.Unplug(i + 1); + DS4Controllers[i] = null; + modeSwitcher[i] = null; + } + } + x360Bus.Stop(); + LogDebug("Stopping DS4 Controllers"); + DS4Devices.stopControllers(); + LogDebug("Stopped DS4 Tool"); + } + return true; + + } + + public bool HotPlug() + { + if(running) + { + DS4Devices.findControllers(); + IEnumerable devices = DS4Devices.getDS4Controllers(); + foreach (DS4Device device in devices) + { + if (((Func)delegate + { + for (Int32 Index = 0; Index < DS4Controllers.Length; Index++) + if (DS4Controllers[Index] != null && + DS4Controllers[Index].MacAddress == device.MacAddress) + return true; + return false; + })()) + continue; + for (Int32 Index = 0; Index < DS4Controllers.Length; Index++) + if (DS4Controllers[Index] == null) + { + DS4Controllers[Index] = device; + device.Removal += this.On_DS4Removal; + TPadModeSwitcher m_switcher = new TPadModeSwitcher(device, Index); + m_switcher.Debug += OnDebug; + modeSwitcher[Index] = m_switcher; + m_switcher.setMode(Global.getTouchEnabled(Index) ? 1 : 0); + device.LightBarColor = Global.loadColor(Index); + device.Report += this.On_Report; + x360Bus.Plugin(Index + 1); + break; + } + } + } + return true; + } + + public string getDS4ControllerInfo(int index) + { + if (DS4Controllers[index] != null) + { + DS4Device d = DS4Controllers[index]; + return d.MacAddress + ", Battery = " + d.Battery + "%," + " Touchpad = " + modeSwitcher[index].ToString() + " (" + d.ConnectionType + ")"; + } + else + return null; + } + + //Called when DS4 is disconnected or timed out + protected virtual void On_DS4Removal(object sender, EventArgs e) + { + DS4Device device = (DS4Device)sender; + int ind = -1; + for (int i = 0; i < DS4Controllers.Length; i++) + if (DS4Controllers[i] != null && device.MacAddress == DS4Controllers[i].MacAddress) + ind = i; + if (ind != -1) + { + x360Bus.Unplug(ind + 1); + LogDebug("Controller " + device.MacAddress + " was removed or lost connection"); + Log.LogToTray("Controller " + device.MacAddress + " was removed or lost connection"); + DS4Controllers[ind] = null; + modeSwitcher[ind] = null; + } + } + + //Called every time the new input report has arrived + protected virtual void On_Report(object sender, EventArgs e) + { + + DS4Device device = (DS4Device)sender; + + int ind=-1; + for (int i=0; i 255) + lightBoosted = 255; + uint heavyBoosted = ((uint)heavyMotor * (uint)boost) / 100; + if (heavyBoosted > 255) + heavyBoosted = 255; + DS4Controllers[deviceNum].setRumble((byte)lightBoosted, (byte)heavyBoosted); + } + + public DS4Device getDS4Controller(int deviceNum) + { + return DS4Controllers[deviceNum]; + } + + //CA1001 TypesThatOwnDisposableFieldsShouldBeDisposable + public void Dispose() + { + x360Bus.Dispose(); + } + } +} diff --git a/DS4Control/CursorOnlyMode.cs b/DS4Control/CursorOnlyMode.cs new file mode 100644 index 0000000..0b56b1b --- /dev/null +++ b/DS4Control/CursorOnlyMode.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; +using DS4Library; +namespace DS4Control +{ + public class MouseCursorOnly : ITouchpadBehaviour + { + private int deviceNum; + public MouseCursorOnly(int deviceID) + { + deviceNum = deviceID; + } + + public override string ToString() + { + return "Cursor Mode"; + } + + public void touchesMoved(object sender, TouchpadEventArgs arg) + { + if (arg.touches.Length == 1) + { + double sensitivity = Global.getTouchSensitivity(deviceNum) / 100.0; + int mouseDeltaX = (int)(sensitivity * (arg.touches[0].deltaX)); + int mouseDeltaY = (int)(sensitivity * (arg.touches[0].deltaY)); + InputMethods.MoveCursorBy(mouseDeltaX, mouseDeltaY); + } + } + + public void touchesBegan(object sender, TouchpadEventArgs arg) { } + + public void touchesEnded(object sender, TouchpadEventArgs arg) { } + + public void touchButtonUp(object sender, TouchpadEventArgs arg) { } + + public void touchButtonDown(object sender, TouchpadEventArgs arg) { } + + public void untouched(object sender, TouchpadEventArgs nullUnused) { } + } +} diff --git a/DS4Control/DS4Control.csproj b/DS4Control/DS4Control.csproj new file mode 100644 index 0000000..8964569 --- /dev/null +++ b/DS4Control/DS4Control.csproj @@ -0,0 +1,91 @@ + + + + + Debug + AnyCPU + {B0AD793E-BAEB-435F-BB40-D647DE2BC2BF} + Library + Properties + DS4Control + DS4Control + v4.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + Component + + + X360Device.cs + + + + + + Component + + + ScpDevice.cs + + + Component + + + ScpHub.cs + + + + + + {43e14dad-e6e8-4b66-ac50-20f5cf9b9712} + DS4Library + + + + + \ No newline at end of file diff --git a/DS4Control/DS4LightBar.cs b/DS4Control/DS4LightBar.cs new file mode 100644 index 0000000..756cf2a --- /dev/null +++ b/DS4Control/DS4LightBar.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using DS4Library; +namespace DS4Control +{ + class DS4LightBar + { + private readonly static byte[/* Light On duration */, /* Light Off duration */] BatteryIndicatorDurations = + { + { 255, 255 }, // 0 doesn't happen + { 28, 252 }, + { 56, 224 }, + { 84, 196 }, + { 112, 168 }, + { 140, 140 }, + { 168, 112 }, + { 196, 84 }, + { 224, 56}, // on 80% of the time at 80, etc. + { 252, 28 }, // on 90% of the time at 90 + { 0, 0 } // no flash at 100 + }; + + public static void updateBatteryStatus(int battery, DS4Device device, int deviceNum) + { + if (Global.getLedAsBatteryIndicator(deviceNum)) + { + byte[] fullColor = { + Global.loadColor(deviceNum).red, + Global.loadColor(deviceNum).green, + Global.loadColor(deviceNum).blue + }; + + // New Setting + DS4Color color = Global.loadLowColor(deviceNum); + byte[] lowColor = { color.red, color.green, color.blue }; + + uint ratio = (uint)battery; + color = Global.getTransitionedColor(lowColor, fullColor, ratio); + device.LightBarColor = color; + + + } + else + { + DS4Color color = Global.loadColor(deviceNum); + device.LightBarColor = color; + } + + if (Global.getFlashWhenLowBattery(deviceNum)) + { + device.LightBarOnDuration = BatteryIndicatorDurations[battery / 10, 0]; + device.LightBarOffDuration = BatteryIndicatorDurations[battery / 10, 1]; + } + else + { + device.LightBarOffDuration = device.LightBarOnDuration = 0; + } + } + + } +} diff --git a/DS4Control/DragMouse.cs b/DS4Control/DragMouse.cs new file mode 100644 index 0000000..7463eed --- /dev/null +++ b/DS4Control/DragMouse.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; +using DS4Library; +using System.Threading; + +namespace DS4Control +{ + class DragMouse: Mouse, IDisposable + { + protected bool leftClick = false; + protected Timer timer; + + public DragMouse(int deviceID):base(deviceID) + { + timer = new System.Threading.Timer((a) => + { + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_LEFTUP); + leftClick = false; + }, null, + System.Threading.Timeout.Infinite, + System.Threading.Timeout.Infinite); + } + + public override string ToString() + { + return "Drag Mode"; + } + + public override void touchesMoved(object sender, TouchpadEventArgs arg) + { + if (arg.touches.Length == 1) + { + double sensitivity = Global.getTouchSensitivity(deviceNum) / 100.0; + int mouseDeltaX = (int)(sensitivity * (arg.touches[0].deltaX)); + int mouseDeltaY = (int)(sensitivity * (arg.touches[0].deltaY)); + InputMethods.MoveCursorBy(mouseDeltaX, mouseDeltaY); + } + else if (arg.touches.Length == 2 && !leftClick) + { + 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; // XXX Will controller swap touch IDs? + double coefficient = Global.getScrollSensitivity(deviceNum); + // 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; + InputMethods.MouseWheel((int)(coefficient * (lastMidY - currentMidY)), (int)(coefficient * (currentMidX - lastMidX))); + } + else + { + double sensitivity = Global.getTouchSensitivity(deviceNum) / 100.0; + int mouseDeltaX = (int)(sensitivity * (arg.touches[1].deltaX)); + int mouseDeltaY = (int)(sensitivity * (arg.touches[1].deltaY)); + InputMethods.MoveCursorBy(mouseDeltaX, mouseDeltaY); + } + } + + public override void touchesBegan(object sender, TouchpadEventArgs arg) + { + pastTime = arg.timeStamp; + firstTouch = arg.touches[0]; + if (leftClick) + timer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite); + } + + public override void touchesEnded(object sender, TouchpadEventArgs arg) + { + if (Global.getTapSensitivity(deviceNum) != 0) + { + DateTime test = arg.timeStamp; + if (test <= (pastTime + TimeSpan.FromMilliseconds((double)Global.getTapSensitivity(deviceNum) * 2)) && !arg.touchButtonPressed) + { + if (Math.Abs(firstTouch.hwX - arg.touches[0].hwX) < 10 && + Math.Abs(firstTouch.hwY - arg.touches[0].hwY) < 10) + { + if (leftClick) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_LEFTUP); + + leftClick = true; + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_LEFTDOWN); + timer.Change(Global.getTapSensitivity(deviceNum) * 2, System.Threading.Timeout.Infinite); + } + } + else if (leftClick) + { + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_LEFTUP); + leftClick = false; + } + } + } + + public override void touchButtonUp(object sender, TouchpadEventArgs arg) + { + if (arg.touches == null) + { + //No touches, finger on upper portion of touchpad + mapTouchPad(DS4Controls.TouchUpper, true); + } + else if (arg.touches.Length > 1) + mapTouchPad(DS4Controls.TouchMulti, true); + else if (!rightClick && arg.touches.Length == 1 && !mapTouchPad(DS4Controls.TouchButton, true)) + { + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_LEFTUP); + leftClick = false; + } + } + + public override void touchButtonDown(object sender, TouchpadEventArgs arg) + { + if (arg.touches == null) + { + //No touches, finger on upper portion of touchpad + if (!mapTouchPad(DS4Controls.TouchUpper)) + InputMethods.performMiddleClick(); + } + else if (!Global.getLowerRCOff(deviceNum) && arg.touches[0].hwX > (1920 * 3) / 4 + && arg.touches[0].hwY > (960 * 3) / 4) + { + rightClick = true; + InputMethods.performRightClick(); + } + else if (arg.touches.Length > 1 && !mapTouchPad(DS4Controls.TouchMulti)) + { + rightClick = true; + InputMethods.performRightClick(); + } + else if (arg.touches.Length == 1 && !mapTouchPad(DS4Controls.TouchButton)) + { + rightClick = false; + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_LEFTDOWN); + leftClick = true; + } + } + + //CA1001 TypesThatOwnDisposableFieldsShouldBeDisposable + public void Dispose() + { + timer.Dispose(); + } + } +} diff --git a/DS4Control/ITouchpadBehaviour.cs b/DS4Control/ITouchpadBehaviour.cs new file mode 100644 index 0000000..1185549 --- /dev/null +++ b/DS4Control/ITouchpadBehaviour.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using DS4Library; +namespace DS4Control +{ + interface ITouchpadBehaviour + { + void touchesBegan(object sender, TouchpadEventArgs arg); + void touchesMoved(object sender, TouchpadEventArgs arg); + void touchButtonUp(object sender, TouchpadEventArgs arg); + void touchButtonDown(object sender, TouchpadEventArgs arg); + void touchesEnded(object sender, TouchpadEventArgs arg); + } +} diff --git a/DS4Control/InputMethods.cs b/DS4Control/InputMethods.cs new file mode 100644 index 0000000..e169490 --- /dev/null +++ b/DS4Control/InputMethods.cs @@ -0,0 +1,255 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; +namespace DS4Control +{ + class InputMethods + { + private static INPUT[] sendInputs = new INPUT[2]; // will allow for keyboard + mouse/tablet input within one SendInput call, or two mouse events + private static object lockob = new object(); + public static void MoveCursorBy(int x, int y) + { + lock (lockob) + { + if (x != 0 || y != 0) + { + sendInputs[0].Type = INPUT_MOUSE; + sendInputs[0].Data.Mouse.ExtraInfo = IntPtr.Zero; + sendInputs[0].Data.Mouse.Flags = MOUSEEVENTF_MOVE; + sendInputs[0].Data.Mouse.MouseData = 0; + sendInputs[0].Data.Mouse.Time = 0; + sendInputs[0].Data.Mouse.X = x; + sendInputs[0].Data.Mouse.Y = y; + uint result = SendInput(1, sendInputs, Marshal.SizeOf(sendInputs[0])); + } + } + } + + public static void MouseWheel(int vertical, int horizontal) + { + lock (lockob) + { + uint inputs = 0; + if (vertical != 0) + { + sendInputs[inputs].Type = INPUT_MOUSE; + sendInputs[inputs].Data.Mouse.ExtraInfo = IntPtr.Zero; + sendInputs[inputs].Data.Mouse.Flags = MOUSEEVENTF_WHEEL; + sendInputs[inputs].Data.Mouse.MouseData = (uint)vertical; + sendInputs[inputs].Data.Mouse.Time = 0; + sendInputs[inputs].Data.Mouse.X = 0; + sendInputs[inputs].Data.Mouse.Y = 0; + inputs++; + } + if (horizontal != 0) + { + sendInputs[inputs].Type = INPUT_MOUSE; + sendInputs[inputs].Data.Mouse.ExtraInfo = IntPtr.Zero; + sendInputs[inputs].Data.Mouse.Flags = MOUSEEVENTF_HWHEEL; + sendInputs[inputs].Data.Mouse.MouseData = (uint)horizontal; + sendInputs[inputs].Data.Mouse.Time = 0; + sendInputs[inputs].Data.Mouse.X = 0; + sendInputs[inputs].Data.Mouse.Y = 0; + inputs++; + } + SendInput(inputs, sendInputs, (int)inputs * Marshal.SizeOf(sendInputs[0])); + } + } + + public static void MouseEvent(uint mouseButton) + { + lock (lockob) + { + sendInputs[0].Type = INPUT_MOUSE; + sendInputs[0].Data.Mouse.ExtraInfo = IntPtr.Zero; + sendInputs[0].Data.Mouse.Flags = mouseButton; + sendInputs[0].Data.Mouse.MouseData = 0; + sendInputs[0].Data.Mouse.Time = 0; + sendInputs[0].Data.Mouse.X = 0; + sendInputs[0].Data.Mouse.Y = 0; + uint result = SendInput(1, sendInputs, Marshal.SizeOf(sendInputs[0])); + } + } + + public static void performLeftClick() + { + lock (lockob) + { + sendInputs[0].Type = INPUT_MOUSE; + sendInputs[0].Data.Mouse.ExtraInfo = IntPtr.Zero; + sendInputs[0].Data.Mouse.Flags = 0; + sendInputs[0].Data.Mouse.Flags |= MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP; + sendInputs[0].Data.Mouse.MouseData = 0; + sendInputs[0].Data.Mouse.Time = 0; + sendInputs[0].Data.Mouse.X = 0; + sendInputs[0].Data.Mouse.Y = 0; + uint result = SendInput(1, sendInputs, Marshal.SizeOf(sendInputs[0])); + } + } + + public static void performRightClick() + { + lock (lockob) + { + sendInputs[0].Type = INPUT_MOUSE; + sendInputs[0].Data.Mouse.ExtraInfo = IntPtr.Zero; + sendInputs[0].Data.Mouse.Flags = 0; + sendInputs[0].Data.Mouse.Flags |= MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_RIGHTUP; + sendInputs[0].Data.Mouse.MouseData = 0; + sendInputs[0].Data.Mouse.Time = 0; + sendInputs[0].Data.Mouse.X = 0; + sendInputs[0].Data.Mouse.Y = 0; + uint result = SendInput(1, sendInputs, Marshal.SizeOf(sendInputs[0])); + } + } + + public static void performMiddleClick() + { + lock (lockob) + { + sendInputs[0].Type = INPUT_MOUSE; + sendInputs[0].Data.Mouse.ExtraInfo = IntPtr.Zero; + sendInputs[0].Data.Mouse.Flags = 0; + sendInputs[0].Data.Mouse.Flags |= MOUSEEVENTF_MIDDLEDOWN | MOUSEEVENTF_MIDDLEUP; + sendInputs[0].Data.Mouse.MouseData = 0; + sendInputs[0].Data.Mouse.Time = 0; + sendInputs[0].Data.Mouse.X = 0; + sendInputs[0].Data.Mouse.Y = 0; + uint result = SendInput(1, sendInputs, Marshal.SizeOf(sendInputs[0])); + } + } + + public static void performSCKeyPress(ushort key) + { + lock (lockob) + { + sendInputs[0].Type = INPUT_KEYBOARD; + sendInputs[0].Data.Keyboard.ExtraInfo = IntPtr.Zero; + sendInputs[0].Data.Keyboard.Flags = KEYEVENTF_SCANCODE; + sendInputs[0].Data.Keyboard.Scan = MapVirtualKey(key, MAPVK_VK_TO_VSC); ; + sendInputs[0].Data.Keyboard.Time = 0; + sendInputs[0].Data.Keyboard.Vk = key; + uint result = SendInput(1, sendInputs, Marshal.SizeOf(sendInputs[0])); + } + } + + public static void performKeyPress(ushort key) + { + lock (lockob) + { + sendInputs[0].Type = INPUT_KEYBOARD; + sendInputs[0].Data.Keyboard.ExtraInfo = IntPtr.Zero; + sendInputs[0].Data.Keyboard.Flags = 0; + sendInputs[0].Data.Keyboard.Scan = 0; + sendInputs[0].Data.Keyboard.Time = 0; + sendInputs[0].Data.Keyboard.Vk = key; + uint result = SendInput(1, sendInputs, Marshal.SizeOf(sendInputs[0])); + } + } + + public static void performSCKeyRelease(ushort key) + { + lock (lockob) + { + sendInputs[0].Type = INPUT_KEYBOARD; + sendInputs[0].Data.Keyboard.ExtraInfo = IntPtr.Zero; + sendInputs[0].Data.Keyboard.Flags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP; + sendInputs[0].Data.Keyboard.Scan = MapVirtualKey(key, MAPVK_VK_TO_VSC); + sendInputs[0].Data.Keyboard.Time = 0; + sendInputs[0].Data.Keyboard.Vk = key; + uint result = SendInput(1, sendInputs, Marshal.SizeOf(sendInputs[0])); + } + } + + public static void performKeyRelease(ushort key) + { + lock (lockob) + { + sendInputs[0].Type = INPUT_KEYBOARD; + sendInputs[0].Data.Keyboard.ExtraInfo = IntPtr.Zero; + sendInputs[0].Data.Keyboard.Flags = KEYEVENTF_KEYUP; + sendInputs[0].Data.Keyboard.Scan = 0; + sendInputs[0].Data.Keyboard.Time = 0; + sendInputs[0].Data.Keyboard.Vk = key; + uint result = SendInput(1, sendInputs, Marshal.SizeOf(sendInputs[0])); + } + } + + /// + /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646270(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + internal struct INPUT + { + public uint Type; + public MOUSEKEYBDHARDWAREINPUT Data; + } + internal const uint INPUT_MOUSE = 0, INPUT_KEYBOARD = 1, INPUT_HARDWARE = 2; + + /// + /// http://social.msdn.microsoft.com/Forums/en/csharplanguage/thread/f0e82d6e-4999-4d22-b3d3-32b25f61fb2a + /// + [StructLayout(LayoutKind.Explicit)] + internal struct MOUSEKEYBDHARDWAREINPUT + { + [FieldOffset(0)] + public HARDWAREINPUT Hardware; + [FieldOffset(0)] + public KEYBDINPUT Keyboard; + [FieldOffset(0)] + public MOUSEINPUT Mouse; + } + + /// + /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646310(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + internal struct HARDWAREINPUT + { + public uint Msg; + public ushort ParamL; + public ushort ParamH; + } + + /// + /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646310(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + internal struct KEYBDINPUT + { + public ushort Vk; + public ushort Scan; + public uint Flags; + public uint Time; + public IntPtr ExtraInfo; + } + + /// + /// http://social.msdn.microsoft.com/forums/en-US/netfxbcl/thread/2abc6be8-c593-4686-93d2-89785232dacd + /// + [StructLayout(LayoutKind.Sequential)] + internal struct MOUSEINPUT + { + public int X; + public int Y; + public uint MouseData; + public uint Flags; + public uint Time; + public IntPtr ExtraInfo; + } + + internal const uint MOUSEEVENTF_MOVE = 1, // just apply X/Y (delta due to not setting absolute flag) + MOUSEEVENTF_LEFTDOWN = 2, MOUSEEVENTF_LEFTUP = 4, + MOUSEEVENTF_RIGHTDOWN = 8, MOUSEEVENTF_RIGHTUP = 16, + MOUSEEVENTF_MIDDLEDOWN = 32, MOUSEEVENTF_MIDDLEUP = 64, + KEYEVENTF_KEYUP = 2, MOUSEEVENTF_WHEEL = 0x0800, MOUSEEVENTF_HWHEEL = 0x1000, + KEYEVENTF_SCANCODE = 0x0008, MAPVK_VK_TO_VSC = 0; + + [DllImport("user32.dll", SetLastError = true)] + private static extern uint SendInput(uint numberOfInputs, INPUT[] inputs, int sizeOfInputs); + [DllImport("user32.dll", CharSet = CharSet.Auto)] + private static extern ushort MapVirtualKey(uint uCode, uint uMapType); + } +} diff --git a/DS4Control/Log.cs b/DS4Control/Log.cs new file mode 100644 index 0000000..13002bc --- /dev/null +++ b/DS4Control/Log.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace DS4Control +{ + public class Log + { + public static event EventHandler TrayIconLog; + public static event EventHandler GuiLog; + + public static void LogToGui(string data) + { + if (GuiLog != null) + { + GuiLog(null, new DebugEventArgs(data)); + } + } + + public static void LogToTray(string data) + { + if (TrayIconLog != null) + { + TrayIconLog(null, new DebugEventArgs(data)); + } + } + } +} + diff --git a/DS4Control/Mapping.cs b/DS4Control/Mapping.cs new file mode 100644 index 0000000..1b08c51 --- /dev/null +++ b/DS4Control/Mapping.cs @@ -0,0 +1,488 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using DS4Library; +namespace DS4Control +{ + class Mapping + { + public static void mapButtons(DS4State cState, DS4State prevState, DS4State MappedState) + { + foreach (KeyValuePair customKey in Global.getCustomKeys()) + { + DS4KeyType keyType = Global.getCustomKeyType(customKey.Key); + bool PrevOn = getBoolMapping(customKey.Key, prevState); + if (getBoolMapping(customKey.Key, cState)) + { + resetToDefaultValue(customKey.Key, cState); + if (!PrevOn) + { + + if (keyType.HasFlag(DS4KeyType.ScanCode)) + InputMethods.performSCKeyPress(customKey.Value); + else InputMethods.performKeyPress(customKey.Value); + } + else if (keyType.HasFlag(DS4KeyType.Repeat)) + if (keyType.HasFlag(DS4KeyType.ScanCode)) + InputMethods.performSCKeyPress(customKey.Value); + else InputMethods.performKeyPress(customKey.Value); + } + else if (PrevOn) + if (keyType.HasFlag(DS4KeyType.ScanCode)) + InputMethods.performSCKeyRelease(customKey.Value); + else InputMethods.performKeyRelease(customKey.Value); + } + + cState.Copy(MappedState); + bool LX = false, LY = false, RX = false, RY = false; + MappedState.LX = 127; + MappedState.LY = 127; + MappedState.RX = 127; + MappedState.RY = 127; + int MouseDeltaX = 0; + int MouseDeltaY = 0; + + foreach (KeyValuePair customButton in Global.getCustomButtons()) + { + + bool LXChanged = MappedState.LX == 127; + bool LYChanged = MappedState.LY == 127; + bool RXChanged = MappedState.RX == 127; + bool RYChanged = MappedState.RY == 127; + switch (customButton.Value) + { + case X360Controls.A: + MappedState.Cross = getBoolMapping(customButton.Key, cState); + break; + case X360Controls.B: + MappedState.Circle = getBoolMapping(customButton.Key, cState); + break; + case X360Controls.X: + MappedState.Square = getBoolMapping(customButton.Key, cState); + break; + case X360Controls.Y: + MappedState.Triangle = getBoolMapping(customButton.Key, cState); + break; + case X360Controls.LB: + MappedState.L1 = getBoolMapping(customButton.Key, cState); + break; + case X360Controls.LS: + MappedState.L3 = getBoolMapping(customButton.Key, cState); + break; + case X360Controls.RB: + MappedState.R1 = getBoolMapping(customButton.Key, cState); + break; + case X360Controls.RS: + MappedState.R3 = getBoolMapping(customButton.Key, cState); + break; + case X360Controls.DpadUp: + MappedState.DpadUp = getBoolMapping(customButton.Key, cState); + break; + case X360Controls.DpadDown: + MappedState.DpadDown = getBoolMapping(customButton.Key, cState); + break; + case X360Controls.DpadLeft: + MappedState.DpadLeft = getBoolMapping(customButton.Key, cState); + break; + case X360Controls.DpadRight: + MappedState.DpadRight = getBoolMapping(customButton.Key, cState); + break; + case X360Controls.Guide: + MappedState.PS = getBoolMapping(customButton.Key, cState); + break; + case X360Controls.Back: + MappedState.Share = getBoolMapping(customButton.Key, cState); + break; + case X360Controls.Start: + MappedState.Options = getBoolMapping(customButton.Key, cState); + break; + case X360Controls.LXNeg: + if (LXChanged) + { + MappedState.LX = getXYAxisMapping(customButton.Key, cState); + LX = true; + } + break; + case X360Controls.LYNeg: + if (LYChanged) + { + MappedState.LY = getXYAxisMapping(customButton.Key, cState); + LY = true; + } + break; + case X360Controls.RXNeg: + if (RXChanged) + { + MappedState.RX = getXYAxisMapping(customButton.Key, cState); + RX = true; + } + break; + case X360Controls.RYNeg: + if (RYChanged) + { + MappedState.RY = getXYAxisMapping(customButton.Key, cState); + RY = true; + } + break; + case X360Controls.LXPos: + if (LXChanged) + { + MappedState.LX = getXYAxisMapping(customButton.Key, cState, true); + LX = true; + } + break; + case X360Controls.LYPos: + if (LYChanged) + { + MappedState.LY = getXYAxisMapping(customButton.Key, cState, true); + LY = true; + } + break; + case X360Controls.RXPos: + if (RXChanged) + { + MappedState.RX = getXYAxisMapping(customButton.Key, cState, true); + RX = true; + } + break; + case X360Controls.RYPos: + if (RYChanged) + { + MappedState.RY = getXYAxisMapping(customButton.Key, cState, true); + RY = true; + } + break; + case X360Controls.LT: + MappedState.L2 = getByteMapping(customButton.Key, cState); + break; + case X360Controls.RT: + MappedState.R2 = getByteMapping(customButton.Key, cState); + break; + case X360Controls.LeftMouse: + bool PrevOn = getBoolMapping(customButton.Key, prevState); + bool CurOn = getBoolMapping(customButton.Key, cState); + if (!PrevOn && CurOn) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_LEFTDOWN); + else if (PrevOn && !CurOn) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_LEFTUP); + break; + case X360Controls.RightMouse: + PrevOn = getBoolMapping(customButton.Key, prevState); + CurOn = getBoolMapping(customButton.Key, cState); + if (!PrevOn && CurOn) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_RIGHTDOWN); + else if (PrevOn && !CurOn) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_RIGHTUP); + break; + case X360Controls.MiddleMouse: + PrevOn = getBoolMapping(customButton.Key, prevState); + CurOn = getBoolMapping(customButton.Key, cState); + if (!PrevOn && CurOn) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_MIDDLEDOWN); + else if (PrevOn && !CurOn) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_MIDDLEUP); + break; + case X360Controls.MouseUp: + if (MouseDeltaY == 0) + { + MouseDeltaY = calculateRelativeMouseDelta(customButton.Key, cState, prevState); + MouseDeltaY = -Math.Abs(MouseDeltaY); + } + break; + case X360Controls.MouseDown: + if (MouseDeltaY == 0) + { + MouseDeltaY = calculateRelativeMouseDelta(customButton.Key, cState, prevState); + MouseDeltaY = Math.Abs(MouseDeltaY); + } + break; + case X360Controls.MouseLeft: + if (MouseDeltaX == 0) + { + MouseDeltaX = calculateRelativeMouseDelta(customButton.Key, cState, prevState); + MouseDeltaX = -Math.Abs(MouseDeltaX); + } + break; + case X360Controls.MouseRight: + if (MouseDeltaX == 0) + { + MouseDeltaX = calculateRelativeMouseDelta(customButton.Key, cState, prevState); + MouseDeltaX = Math.Abs(MouseDeltaX); + } + break; + case X360Controls.Unbound: + resetToDefaultValue(customButton.Key, MappedState); + break; + } + } + + if (!LX) + MappedState.LX = cState.LX; + if (!LY) + MappedState.LY = cState.LY; + if (!RX) + MappedState.RX = cState.RX; + if (!RY) + MappedState.RY = cState.RY; + InputMethods.MoveCursorBy(MouseDeltaX, MouseDeltaY); + } + + private static int calculateRelativeMouseDelta(DS4Controls control, DS4State cState, DS4State pState) + { + int axisVal = -1; + int DEAD_ZONE = 10; + float SPEED_MULTIPLIER = 0.000004f; + bool positive = false; + float deltaTime = cState.ReportTimeStamp.Ticks - pState.ReportTimeStamp.Ticks; + switch (control) + { + case DS4Controls.LXNeg: + axisVal = cState.LX; + break; + case DS4Controls.LXPos: + positive = true; + axisVal = cState.LX; + break; + case DS4Controls.RXNeg: + axisVal = cState.RX; + break; + case DS4Controls.RXPos: + positive = true; + axisVal = cState.RX; + break; + case DS4Controls.LYNeg: + axisVal = cState.LY; + break; + case DS4Controls.LYPos: + positive = true; + axisVal = cState.LY; + break; + case DS4Controls.RYNeg: + axisVal = cState.RY; + break; + case DS4Controls.RYPos: + positive = true; + axisVal = cState.RY; + break; + } + axisVal = axisVal - 127; + int delta = 0; + if ( (!positive && axisVal < -DEAD_ZONE ) || (positive && axisVal > DEAD_ZONE)) + { + delta = (int)(float) (axisVal * SPEED_MULTIPLIER * deltaTime); + } + return delta; + } + + public static bool compare(byte b1, byte b2) + { + if (Math.Abs(b1 - b2) > 10) + { + return false; + } + return true; + } + public static byte getByteMapping(DS4Controls control, DS4State cState) + { + switch (control) + { + case DS4Controls.Share: return (byte)(cState.Share ? 255 : 0); + case DS4Controls.Options: return (byte)(cState.Options ? 255 : 0); + case DS4Controls.L1: return (byte)(cState.L1 ? 255 : 0); + case DS4Controls.R1: return (byte)(cState.R1 ? 255 : 0); + case DS4Controls.L3: return (byte)(cState.L3 ? 255 : 0); + case DS4Controls.R3: return (byte)(cState.R3 ? 255 : 0); + case DS4Controls.DpadUp: return (byte)(cState.DpadUp ? 255 : 0); + case DS4Controls.DpadDown: return (byte)(cState.DpadDown ? 255 : 0); + case DS4Controls.DpadLeft: return (byte)(cState.DpadLeft ? 255 : 0); + case DS4Controls.DpadRight: return (byte)(cState.DpadRight ? 255 : 0); + case DS4Controls.PS: return (byte)(cState.PS ? 255 : 0); + case DS4Controls.Cross: return (byte)(cState.Cross ? 255 : 0); + case DS4Controls.Square: return (byte)(cState.Square ? 255 : 0); + case DS4Controls.Triangle: return (byte)(cState.Triangle ? 255 : 0); + case DS4Controls.Circle: return (byte)(cState.Circle ? 255 : 0); + case DS4Controls.LXNeg: return cState.LX; + case DS4Controls.LYNeg: return cState.LY; + case DS4Controls.RXNeg: return cState.RX; + case DS4Controls.RYNeg: return cState.RY; + case DS4Controls.LXPos: return (byte)(cState.LX - 127 < 0 ? 0 : (cState.LX - 127)); + case DS4Controls.LYPos: return (byte)(cState.LY - 123 < 0 ? 0 : (cState.LY - 123)); + case DS4Controls.RXPos: return (byte)(cState.RX - 125 < 0 ? 0 : (cState.RX - 125)); + case DS4Controls.RYPos: return (byte)(cState.RY - 127 < 0 ? 0 : (cState.RY - 127)); + case DS4Controls.L2: return cState.L2; + case DS4Controls.R2: return cState.R2; + } + return 0; + } + + public static bool getBoolMapping(DS4Controls control, DS4State cState) + { + switch (control) + { + case DS4Controls.Share: return cState.Share; + case DS4Controls.Options: return cState.Options; + case DS4Controls.L1: return cState.L1; + case DS4Controls.R1: return cState.R1; + case DS4Controls.L3: return cState.L3; + case DS4Controls.R3: return cState.R3; + case DS4Controls.DpadUp: return cState.DpadUp; + case DS4Controls.DpadDown: return cState.DpadDown; + case DS4Controls.DpadLeft: return cState.DpadLeft; + case DS4Controls.DpadRight: return cState.DpadRight; + case DS4Controls.PS: return cState.PS; + case DS4Controls.Cross: return cState.Cross; + case DS4Controls.Square: return cState.Square; + case DS4Controls.Triangle: return cState.Triangle; + case DS4Controls.Circle: return cState.Circle; + case DS4Controls.LXNeg: return cState.LX < 55; + case DS4Controls.LYNeg: return cState.LY < 55; + case DS4Controls.RXNeg: return cState.RX < 55; + case DS4Controls.RYNeg: return cState.RY < 55; + case DS4Controls.LXPos: return cState.LX > 200; + case DS4Controls.LYPos: return cState.LY > 200; + case DS4Controls.RXPos: return cState.RX > 200; + case DS4Controls.RYPos: return cState.RY > 200; + case DS4Controls.L2: return cState.L2 > 100; + case DS4Controls.R2: return cState.R2 > 100; + } + return false; + } + + public static byte getXYAxisMapping(DS4Controls control, DS4State cState, bool alt = false) + { + byte trueVal = 0; + byte falseVal = 127; + if (alt) + { + trueVal = 255; + } + switch (control) + { + case DS4Controls.Share: return (byte)(cState.Share ? trueVal : falseVal); + case DS4Controls.Options: return (byte)(cState.Options ? trueVal : falseVal); + case DS4Controls.L1: return (byte)(cState.L1 ? trueVal : falseVal); + case DS4Controls.R1: return (byte)(cState.R1 ? trueVal : falseVal); + case DS4Controls.L3: return (byte)(cState.L3 ? trueVal : falseVal); + case DS4Controls.R3: return (byte)(cState.R3 ? trueVal : falseVal); + case DS4Controls.DpadUp: return (byte)(cState.DpadUp ? trueVal : falseVal); + case DS4Controls.DpadDown: return (byte)(cState.DpadDown ? trueVal : falseVal); + case DS4Controls.DpadLeft: return (byte)(cState.DpadLeft ? trueVal : falseVal); + case DS4Controls.DpadRight: return (byte)(cState.DpadRight ? trueVal : falseVal); + case DS4Controls.PS: return (byte)(cState.PS ? trueVal : falseVal); + case DS4Controls.Cross: return (byte)(cState.Cross ? trueVal : falseVal); + case DS4Controls.Square: return (byte)(cState.Square ? trueVal : falseVal); + case DS4Controls.Triangle: return (byte)(cState.Triangle ? trueVal : falseVal); + case DS4Controls.Circle: return (byte)(cState.Circle ? trueVal : falseVal); + case DS4Controls.L2: return (byte)(cState.L2 == 255 ? trueVal : falseVal); + case DS4Controls.R2: return (byte)(cState.R2 == 255 ? trueVal : falseVal); + } + + if (!alt) + { + switch (control) + { + case DS4Controls.LXNeg: return cState.LX; + case DS4Controls.LYNeg: return cState.LY; + case DS4Controls.RXNeg: return cState.RX; + case DS4Controls.RYNeg: return cState.RY; + case DS4Controls.LXPos: return (byte)(255 - cState.LX); + case DS4Controls.LYPos: return (byte)(255 - cState.LY); + case DS4Controls.RXPos: return (byte)(255 - cState.RX); + case DS4Controls.RYPos: return (byte)(255 - cState.RY); + } + } + else + { + switch (control) + { + case DS4Controls.LXNeg: return (byte)(255 - cState.LX); + case DS4Controls.LYNeg: return (byte)(255 - cState.LY); + case DS4Controls.RXNeg: return (byte)(255 - cState.RX); + case DS4Controls.RYNeg: return (byte)(255 - cState.RY); + case DS4Controls.LXPos: return cState.LX; + case DS4Controls.LYPos: return cState.LY; + case DS4Controls.RXPos: return cState.RX; + case DS4Controls.RYPos: return cState.RY; + } + } + return 0; + } + + //Returns false for any bool, + //if control is one of the xy axis returns 127 + //if its a trigger returns 0 + public static void resetToDefaultValue(DS4Controls control, DS4State cState) + { + switch (control) + { + case DS4Controls.Share: cState.Share = false; break; + case DS4Controls.Options: cState.Options = false; break; + case DS4Controls.L1: cState.L1 = false; break; + case DS4Controls.R1: cState.R1 = false; break; + case DS4Controls.L3: cState.L3 = false; break; + case DS4Controls.R3: cState.R3 = false; break; + case DS4Controls.DpadUp: cState.DpadUp = false; break; + case DS4Controls.DpadDown: cState.DpadDown = false; break; + case DS4Controls.DpadLeft: cState.DpadLeft = false; break; + case DS4Controls.DpadRight: cState.DpadRight = false; break; + case DS4Controls.PS: cState.PS = false; break; + case DS4Controls.Cross: cState.Cross = false; break; + case DS4Controls.Square: cState.Square = false; break; + case DS4Controls.Triangle: cState.Triangle = false; break; + case DS4Controls.Circle: cState.Circle = false; break; + case DS4Controls.LXNeg: cState.LX = 127; break; + case DS4Controls.LYNeg: cState.LY = 127; break; + case DS4Controls.RXNeg: cState.RX = 127; break; + case DS4Controls.RYNeg: cState.RY = 127; break; + case DS4Controls.LXPos: cState.LX = 127; break; + case DS4Controls.LYPos: cState.LY = 127; break; + case DS4Controls.RXPos: cState.RX = 127; break; + case DS4Controls.RYPos: cState.RY = 127; break; + case DS4Controls.L2: cState.L2 = 0; break; + case DS4Controls.R2: cState.R2 = 0; break; + } + } + + + // Arthritis mode, compensate for cumulative pressure F=kx on the triggers by allowing the user to remap the entire trigger to just the initial portion. + private static byte[,] leftTriggerMap = new byte[4,256], rightTriggerMap = new byte[4,256]; + private static double[] leftTriggerMiddle = new double[4], // linear trigger remapping, 0.5 is in the middle of 0 and 255 from the native controller. + oldLeftTriggerMiddle = new double[4], + rightTriggerMiddle = new double[4], oldRightTriggerMiddle = new double[4]; + private static void initializeTriggerMap(byte[,] map, double triggerMiddle, int deviceNum) + { + double midpoint = 256.0 * triggerMiddle; + for (uint x = 0; x <= 255; x++) + { + double mapped; + if (x < midpoint) // i.e. with standard 0.5, 0..127->0..127, etc.; with 0.25, 0..63->0..127 and 64..255->128..255\ + mapped = (x * 0.5 / triggerMiddle); + else + mapped = 128.0 + 128.0 * (x - midpoint) / (256.0 - midpoint); + map[deviceNum, x] = (byte)mapped; + } + + } + public static byte mapLeftTrigger(byte orig, int deviceNum) + { + leftTriggerMiddle[deviceNum] = Global.getLeftTriggerMiddle(deviceNum); + if (leftTriggerMiddle[deviceNum] != oldLeftTriggerMiddle[deviceNum]) + { + oldLeftTriggerMiddle[deviceNum] = leftTriggerMiddle[deviceNum]; + initializeTriggerMap(leftTriggerMap, leftTriggerMiddle[deviceNum],deviceNum); + } + return leftTriggerMap[deviceNum, orig]; + } + public static byte mapRightTrigger(byte orig, int deviceNum) + { + rightTriggerMiddle[deviceNum] = Global.getRightTriggerMiddle(deviceNum); + if (rightTriggerMiddle[deviceNum] != oldRightTriggerMiddle[deviceNum]) + { + oldRightTriggerMiddle[deviceNum] = rightTriggerMiddle[deviceNum]; + initializeTriggerMap(rightTriggerMap, rightTriggerMiddle[deviceNum], deviceNum); + } + return rightTriggerMap[deviceNum,orig]; + } + } +} diff --git a/DS4Control/Mouse.cs b/DS4Control/Mouse.cs new file mode 100644 index 0000000..574ef16 --- /dev/null +++ b/DS4Control/Mouse.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; +using DS4Library; +namespace DS4Control +{ + public class Mouse : ITouchpadBehaviour + { + protected DateTime pastTime; + protected Touch firstTouch; + protected int deviceNum; + protected bool rightClick = false; + + public Mouse(int deviceID) + { + deviceNum = deviceID; + } + + public override string ToString() + { + return "Standard Mode"; + } + + public virtual void touchesMoved(object sender, TouchpadEventArgs arg) + { + if (arg.touches.Length == 1) + { + double sensitivity = Global.getTouchSensitivity(deviceNum) / 100.0; + int mouseDeltaX = (int)(sensitivity * (arg.touches[0].deltaX)); + int mouseDeltaY = (int)(sensitivity * (arg.touches[0].deltaY)); + InputMethods.MoveCursorBy(mouseDeltaX, mouseDeltaY); + } + else if (arg.touches.Length == 2) + { + 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; // XXX Will controller swap touch IDs? + double coefficient = Global.getScrollSensitivity(deviceNum); + // 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; + InputMethods.MouseWheel((int)(coefficient * (lastMidY - currentMidY)), (int)(coefficient * (currentMidX - lastMidX))); + } + } + + public virtual void touchesBegan(object sender, TouchpadEventArgs arg) + { + pastTime = arg.timeStamp; + firstTouch = arg.touches[0]; + } + + public virtual void touchesEnded(object sender, TouchpadEventArgs arg) + { + if (Global.getTapSensitivity(deviceNum) != 0) + { + DateTime test = arg.timeStamp; + if (test <= (pastTime + TimeSpan.FromMilliseconds((double)Global.getTapSensitivity(deviceNum) * 2)) && !arg.touchButtonPressed) + { + if (Math.Abs(firstTouch.hwX - arg.touches[0].hwX) < 10 && + Math.Abs(firstTouch.hwY - arg.touches[0].hwY) < 10) + InputMethods.performLeftClick(); + } + } + } + + public virtual void touchButtonUp(object sender, TouchpadEventArgs arg) + { + if (arg.touches == null) + { + //No touches, finger on upper portion of touchpad + mapTouchPad(DS4Controls.TouchUpper,true); + } + else if (arg.touches.Length > 1) + mapTouchPad(DS4Controls.TouchMulti, true); + else if (!rightClick && arg.touches.Length == 1 && !mapTouchPad(DS4Controls.TouchButton, true)) + { + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_LEFTUP); + } + } + + public virtual void touchButtonDown(object sender, TouchpadEventArgs arg) + { + if (arg.touches == null) + { + //No touches, finger on upper portion of touchpad + if(!mapTouchPad(DS4Controls.TouchUpper)) + InputMethods.performMiddleClick(); + } + else if (!Global.getLowerRCOff(deviceNum) && arg.touches[0].hwX > (1920 * 3)/4 + && arg.touches[0].hwY > (960 * 3)/4) + { + rightClick = true; + InputMethods.performRightClick(); + } + else if (arg.touches.Length>1 && !mapTouchPad(DS4Controls.TouchMulti)) + { + rightClick = true; + InputMethods.performRightClick(); + } + else if (arg.touches.Length==1 && !mapTouchPad(DS4Controls.TouchButton)) + { + rightClick = false; + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_LEFTDOWN); + } + } + + protected bool mapTouchPad(DS4Controls padControl, bool release = false) + { + ushort key = Global.getCustomKey(padControl); + if (key == 0) + return false; + else + { + DS4KeyType keyType = Global.getCustomKeyType(padControl); + if (!release) + if (keyType.HasFlag(DS4KeyType.ScanCode)) + InputMethods.performSCKeyPress(key); + else InputMethods.performKeyPress(key); + else + if (!keyType.HasFlag(DS4KeyType.Repeat)) + if (keyType.HasFlag(DS4KeyType.ScanCode)) + InputMethods.performSCKeyRelease(key); + else InputMethods.performKeyRelease(key); + return true; + } + } + + } +} diff --git a/DS4Control/Properties/AssemblyInfo.cs b/DS4Control/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f817ec8 --- /dev/null +++ b/DS4Control/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DS4Control")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DS4Control")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c85c773c-b572-4148-8fa6-8dfbb7f7141f")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/DS4Control/ScpDevice.Designer.cs b/DS4Control/ScpDevice.Designer.cs new file mode 100644 index 0000000..5ee5e6e --- /dev/null +++ b/DS4Control/ScpDevice.Designer.cs @@ -0,0 +1,36 @@ +namespace DS4Control +{ + partial class ScpDevice + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + } + + #endregion + } +} diff --git a/DS4Control/ScpDevice.cs b/DS4Control/ScpDevice.cs new file mode 100644 index 0000000..a97b277 --- /dev/null +++ b/DS4Control/ScpDevice.cs @@ -0,0 +1,707 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Windows.Forms; + +using System.Runtime.InteropServices; +using Microsoft.Win32.SafeHandles; + +namespace DS4Control +{ + public partial class ScpDevice : Component + { + public virtual Boolean IsActive + { + get { return m_IsActive; } + } + + public virtual String Path + { + get { return m_Path; } + } + + + public ScpDevice() + { + InitializeComponent(); + } + + public ScpDevice(IContainer container) + { + container.Add(this); + + InitializeComponent(); + } + + public ScpDevice(String Class) + { + InitializeComponent(); + + this.m_Class = new Guid(Class); + } + + + public virtual Boolean Open(Int32 Instance = 0) + { + String DevicePath = String.Empty; + m_WinUsbHandle = (IntPtr) INVALID_HANDLE_VALUE; + + if (Find(m_Class, ref DevicePath, Instance)) + { + Open(DevicePath); + } + + return m_IsActive; + } + + public virtual Boolean Open(String DevicePath) + { + m_Path = DevicePath.ToUpper(); + m_WinUsbHandle = (IntPtr) INVALID_HANDLE_VALUE; + + if (GetDeviceHandle(m_Path)) + { + if (WinUsb_Initialize(m_FileHandle, ref m_WinUsbHandle)) + { + if (InitializeDevice()) + { + m_IsActive = true; + } + else + { + WinUsb_Free(m_WinUsbHandle); + m_WinUsbHandle = (IntPtr) INVALID_HANDLE_VALUE; + } + } + else + { + m_FileHandle.Close(); + } + } + + return m_IsActive; + } + + public virtual Boolean Start() + { + return m_IsActive; + } + + public virtual Boolean Stop() + { + m_IsActive = false; + + if (!(m_WinUsbHandle == (IntPtr) INVALID_HANDLE_VALUE)) + { + WinUsb_AbortPipe(m_WinUsbHandle, m_IntIn); + WinUsb_AbortPipe(m_WinUsbHandle, m_BulkIn); + WinUsb_AbortPipe(m_WinUsbHandle, m_BulkOut); + + WinUsb_Free(m_WinUsbHandle); + m_WinUsbHandle = (IntPtr) INVALID_HANDLE_VALUE; + } + + if (m_FileHandle != null && !m_FileHandle.IsInvalid && !m_FileHandle.IsClosed) + { + m_FileHandle.Close(); + m_FileHandle = null; + } + + return true; + } + + public virtual Boolean Close() + { + return Stop(); + } + + + public virtual Boolean ReadIntPipe (Byte[] Buffer, Int32 Length, ref Int32 Transfered) + { + if (!m_IsActive) return false; + + return WinUsb_ReadPipe(m_WinUsbHandle, m_IntIn, Buffer, Length, ref Transfered, IntPtr.Zero); + } + + public virtual Boolean ReadBulkPipe (Byte[] Buffer, Int32 Length, ref Int32 Transfered) + { + if (!m_IsActive) return false; + + return WinUsb_ReadPipe(m_WinUsbHandle, m_BulkIn, Buffer, Length, ref Transfered, IntPtr.Zero); + } + + public virtual Boolean WriteIntPipe (Byte[] Buffer, Int32 Length, ref Int32 Transfered) + { + if (!m_IsActive) return false; + + return WinUsb_WritePipe(m_WinUsbHandle, m_IntOut, Buffer, Length, ref Transfered, IntPtr.Zero); + } + + public virtual Boolean WriteBulkPipe(Byte[] Buffer, Int32 Length, ref Int32 Transfered) + { + if (!m_IsActive) return false; + + return WinUsb_WritePipe(m_WinUsbHandle, m_BulkOut, Buffer, Length, ref Transfered, IntPtr.Zero); + } + + + public virtual Boolean SendTransfer(Byte RequestType, Byte Request, UInt16 Value, Byte[] Buffer, ref Int32 Transfered) + { + if (!m_IsActive) return false; + + WINUSB_SETUP_PACKET Setup = new WINUSB_SETUP_PACKET(); + + Setup.RequestType = RequestType; + Setup.Request = Request; + Setup.Value = Value; + Setup.Index = 0; + Setup.Length = (UInt16) Buffer.Length; + + return WinUsb_ControlTransfer(m_WinUsbHandle, Setup, Buffer, Buffer.Length, ref Transfered, IntPtr.Zero); + } + + + #region Constant and Structure Definitions + public const Int32 SERVICE_CONTROL_STOP = 0x00000001; + public const Int32 SERVICE_CONTROL_SHUTDOWN = 0x00000005; + public const Int32 SERVICE_CONTROL_DEVICEEVENT = 0x0000000B; + public const Int32 SERVICE_CONTROL_POWEREVENT = 0x0000000D; + + public const Int32 DBT_DEVICEARRIVAL = 0x8000; + public const Int32 DBT_DEVICEQUERYREMOVE = 0x8001; + public const Int32 DBT_DEVICEREMOVECOMPLETE = 0x8004; + public const Int32 DBT_DEVTYP_DEVICEINTERFACE = 0x0005; + public const Int32 DBT_DEVTYP_HANDLE = 0x0006; + + public const Int32 PBT_APMRESUMEAUTOMATIC = 0x0012; + public const Int32 PBT_APMSUSPEND = 0x0004; + + public const Int32 DEVICE_NOTIFY_WINDOW_HANDLE = 0x0000; + public const Int32 DEVICE_NOTIFY_SERVICE_HANDLE = 0x0001; + public const Int32 DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = 0x0004; + + public const Int32 WM_DEVICECHANGE = 0x0219; + + public const Int32 DIGCF_PRESENT = 0x0002; + public const Int32 DIGCF_DEVICEINTERFACE = 0x0010; + + public delegate Int32 ServiceControlHandlerEx(Int32 Control, Int32 Type, IntPtr Data, IntPtr Context); + + [StructLayout(LayoutKind.Sequential)] + public class DEV_BROADCAST_DEVICEINTERFACE + { + internal Int32 dbcc_size; + internal Int32 dbcc_devicetype; + internal Int32 dbcc_reserved; + internal Guid dbcc_classguid; + internal Int16 dbcc_name; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + public class DEV_BROADCAST_DEVICEINTERFACE_M + { + public Int32 dbcc_size; + public Int32 dbcc_devicetype; + public Int32 dbcc_reserved; + + [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 16)] + public Byte[] dbcc_classguid; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)] + public Char[] dbcc_name; + } + + [StructLayout(LayoutKind.Sequential)] + public class DEV_BROADCAST_HDR + { + public Int32 dbch_size; + public Int32 dbch_devicetype; + public Int32 dbch_reserved; + } + + [StructLayout(LayoutKind.Sequential)] + protected struct SP_DEVICE_INTERFACE_DATA + { + internal Int32 cbSize; + internal Guid InterfaceClassGuid; + internal Int32 Flags; + internal IntPtr Reserved; + } + + protected const UInt32 FILE_ATTRIBUTE_NORMAL = 0x80; + protected const UInt32 FILE_FLAG_OVERLAPPED = 0x40000000; + protected const UInt32 FILE_SHARE_READ = 1; + protected const UInt32 FILE_SHARE_WRITE = 2; + protected const UInt32 GENERIC_READ = 0x80000000; + protected const UInt32 GENERIC_WRITE = 0x40000000; + protected const Int32 INVALID_HANDLE_VALUE = -1; + protected const UInt32 OPEN_EXISTING = 3; + protected const UInt32 DEVICE_SPEED = 1; + protected const Byte USB_ENDPOINT_DIRECTION_MASK = 0x80; + + protected enum POLICY_TYPE + { + SHORT_PACKET_TERMINATE = 1, + AUTO_CLEAR_STALL = 2, + PIPE_TRANSFER_TIMEOUT = 3, + IGNORE_SHORT_PACKETS = 4, + ALLOW_PARTIAL_READS = 5, + AUTO_FLUSH = 6, + RAW_IO = 7, + } + + protected enum USBD_PIPE_TYPE + { + UsbdPipeTypeControl = 0, + UsbdPipeTypeIsochronous = 1, + UsbdPipeTypeBulk = 2, + UsbdPipeTypeInterrupt = 3, + } + + protected enum USB_DEVICE_SPEED + { + UsbLowSpeed = 1, + UsbFullSpeed = 2, + UsbHighSpeed = 3, + } + + [StructLayout(LayoutKind.Sequential)] + protected struct USB_CONFIGURATION_DESCRIPTOR + { + internal Byte bLength; + internal Byte bDescriptorType; + internal UInt16 wTotalLength; + internal Byte bNumInterfaces; + internal Byte bConfigurationValue; + internal Byte iConfiguration; + internal Byte bmAttributes; + internal Byte MaxPower; + } + + [StructLayout(LayoutKind.Sequential)] + protected struct USB_INTERFACE_DESCRIPTOR + { + internal Byte bLength; + internal Byte bDescriptorType; + internal Byte bInterfaceNumber; + internal Byte bAlternateSetting; + internal Byte bNumEndpoints; + internal Byte bInterfaceClass; + internal Byte bInterfaceSubClass; + internal Byte bInterfaceProtocol; + internal Byte iInterface; + } + + [StructLayout(LayoutKind.Sequential)] + protected struct WINUSB_PIPE_INFORMATION + { + internal USBD_PIPE_TYPE PipeType; + internal Byte PipeId; + internal UInt16 MaximumPacketSize; + internal Byte Interval; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + protected struct WINUSB_SETUP_PACKET + { + internal Byte RequestType; + internal Byte Request; + internal UInt16 Value; + internal UInt16 Index; + internal UInt16 Length; + } + + protected const Int32 DIF_PROPERTYCHANGE = 0x12; + protected const Int32 DICS_ENABLE = 1; + protected const Int32 DICS_DISABLE = 2; + protected const Int32 DICS_PROPCHANGE = 3; + protected const Int32 DICS_FLAG_GLOBAL = 1; + + [StructLayout(LayoutKind.Sequential)] + protected struct SP_CLASSINSTALL_HEADER + { + internal Int32 cbSize; + internal Int32 InstallFunction; + } + + [StructLayout(LayoutKind.Sequential)] + protected struct SP_PROPCHANGE_PARAMS + { + internal SP_CLASSINSTALL_HEADER ClassInstallHeader; + internal Int32 StateChange; + internal Int32 Scope; + internal Int32 HwProfile; + } + #endregion + + #region Protected Data Members + protected Guid m_Class = Guid.Empty; + protected String m_Path = String.Empty; + + protected SafeFileHandle m_FileHandle = null; + protected IntPtr m_WinUsbHandle = IntPtr.Zero; + + protected Byte m_IntIn = 0xFF; + protected Byte m_IntOut = 0xFF; + protected Byte m_BulkIn = 0xFF; + protected Byte m_BulkOut = 0xFF; + + protected Boolean m_IsActive = false; + #endregion + + #region Static Helper Methods + public enum Notified { Ignore = 0x0000, Arrival = 0x8000, QueryRemove = 0x8001, Removal = 0x8004 }; + + public static Boolean RegisterNotify(IntPtr Form, Guid Class, ref IntPtr Handle, Boolean Window = true) + { + IntPtr devBroadcastDeviceInterfaceBuffer = IntPtr.Zero; + + try + { + DEV_BROADCAST_DEVICEINTERFACE devBroadcastDeviceInterface = new DEV_BROADCAST_DEVICEINTERFACE(); + Int32 Size = Marshal.SizeOf(devBroadcastDeviceInterface); + + devBroadcastDeviceInterface.dbcc_size = Size; + devBroadcastDeviceInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + devBroadcastDeviceInterface.dbcc_reserved = 0; + devBroadcastDeviceInterface.dbcc_classguid = Class; + + devBroadcastDeviceInterfaceBuffer = Marshal.AllocHGlobal(Size); + Marshal.StructureToPtr(devBroadcastDeviceInterface, devBroadcastDeviceInterfaceBuffer, true); + + Handle = RegisterDeviceNotification(Form, devBroadcastDeviceInterfaceBuffer, Window ? DEVICE_NOTIFY_WINDOW_HANDLE : DEVICE_NOTIFY_SERVICE_HANDLE); + + Marshal.PtrToStructure(devBroadcastDeviceInterfaceBuffer, devBroadcastDeviceInterface); + + return Handle != IntPtr.Zero; + } + catch (Exception ex) + { + Console.WriteLine("{0} {1}", ex.HelpLink, ex.Message); + throw; + } + finally + { + if (devBroadcastDeviceInterfaceBuffer != IntPtr.Zero) + { + Marshal.FreeHGlobal(devBroadcastDeviceInterfaceBuffer); + } + } + } + + public static Boolean UnregisterNotify(IntPtr Handle) + { + try + { + return UnregisterDeviceNotification(Handle); + } + catch (Exception ex) + { + Console.WriteLine("{0} {1}", ex.HelpLink, ex.Message); + throw; + } + } + #endregion + + #region Protected Methods + protected virtual Boolean Find(Guid Target, ref String Path, Int32 Instance = 0) + { + IntPtr detailDataBuffer = IntPtr.Zero; + IntPtr deviceInfoSet = IntPtr.Zero; + + try + { + SP_DEVICE_INTERFACE_DATA DeviceInterfaceData = new SP_DEVICE_INTERFACE_DATA(), da = new SP_DEVICE_INTERFACE_DATA(); + Int32 bufferSize = 0, memberIndex = 0; + + deviceInfoSet = SetupDiGetClassDevs(ref Target, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + + DeviceInterfaceData.cbSize = da.cbSize = Marshal.SizeOf(DeviceInterfaceData); + + while (SetupDiEnumDeviceInterfaces(deviceInfoSet, IntPtr.Zero, ref Target, memberIndex, ref DeviceInterfaceData)) + { + SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref DeviceInterfaceData, IntPtr.Zero, 0, ref bufferSize, ref da); + { + detailDataBuffer = Marshal.AllocHGlobal(bufferSize); + + Marshal.WriteInt32(detailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8); + + if (SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref DeviceInterfaceData, detailDataBuffer, bufferSize, ref bufferSize, ref da)) + { + IntPtr pDevicePathName = new IntPtr(IntPtr.Size == 4 ? detailDataBuffer.ToInt32() + 4: detailDataBuffer.ToInt64() + 4); + + Path = Marshal.PtrToStringAuto(pDevicePathName).ToUpper(); + Marshal.FreeHGlobal(detailDataBuffer); + + if (memberIndex == Instance) return true; + } + else Marshal.FreeHGlobal(detailDataBuffer); + } + + memberIndex++; + } + } + catch (Exception ex) + { + Console.WriteLine("{0} {1}", ex.HelpLink, ex.Message); + throw; + } + finally + { + if (deviceInfoSet != IntPtr.Zero) + { + SetupDiDestroyDeviceInfoList(deviceInfoSet); + } + } + + return false; + } + + protected virtual Boolean GetDeviceInstance(ref String Instance) + { + IntPtr detailDataBuffer = IntPtr.Zero; + IntPtr deviceInfoSet = IntPtr.Zero; + + try + { + SP_DEVICE_INTERFACE_DATA DeviceInterfaceData = new SP_DEVICE_INTERFACE_DATA(), da = new SP_DEVICE_INTERFACE_DATA(); + Int32 bufferSize = 0, memberIndex = 0; + + deviceInfoSet = SetupDiGetClassDevs(ref m_Class, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + + DeviceInterfaceData.cbSize = da.cbSize = Marshal.SizeOf(DeviceInterfaceData); + + while (SetupDiEnumDeviceInterfaces(deviceInfoSet, IntPtr.Zero, ref m_Class, memberIndex, ref DeviceInterfaceData)) + { + SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref DeviceInterfaceData, IntPtr.Zero, 0, ref bufferSize, ref da); + { + detailDataBuffer = Marshal.AllocHGlobal(bufferSize); + + Marshal.WriteInt32(detailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8); + + if (SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref DeviceInterfaceData, detailDataBuffer, bufferSize, ref bufferSize, ref da)) + { + IntPtr pDevicePathName = new IntPtr(IntPtr.Size == 4 ? detailDataBuffer.ToInt32() + 4 : detailDataBuffer.ToInt64() + 4); + + String Current = Marshal.PtrToStringAuto(pDevicePathName).ToUpper(); + Marshal.FreeHGlobal(detailDataBuffer); + + if (Current == Path) + { + Int32 nBytes = 256; + IntPtr ptrInstanceBuf = Marshal.AllocHGlobal(nBytes); + + CM_Get_Device_ID(da.Flags, ptrInstanceBuf, nBytes, 0); + Instance = Marshal.PtrToStringAuto(ptrInstanceBuf).ToUpper(); + + Marshal.FreeHGlobal(ptrInstanceBuf); + return true; + } + } + else Marshal.FreeHGlobal(detailDataBuffer); + } + + memberIndex++; + } + } + catch (Exception ex) + { + Console.WriteLine("{0} {1}", ex.HelpLink, ex.Message); + throw; + } + finally + { + if (deviceInfoSet != IntPtr.Zero) + { + SetupDiDestroyDeviceInfoList(deviceInfoSet); + } + } + + return false; + } + + protected virtual Boolean GetDeviceHandle(String Path) + { + m_FileHandle = CreateFile(Path, (GENERIC_WRITE | GENERIC_READ), FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0); + + return !m_FileHandle.IsInvalid; + } + + protected virtual Boolean UsbEndpointDirectionIn(Int32 addr) + { + return (addr & 0x80) == 0x80; + } + + protected virtual Boolean UsbEndpointDirectionOut(Int32 addr) + { + return (addr & 0x80) == 0x00; + } + + protected virtual Boolean InitializeDevice() + { + try + { + USB_INTERFACE_DESCRIPTOR ifaceDescriptor = new USB_INTERFACE_DESCRIPTOR(); + WINUSB_PIPE_INFORMATION pipeInfo = new WINUSB_PIPE_INFORMATION(); + + if (WinUsb_QueryInterfaceSettings(m_WinUsbHandle, 0, ref ifaceDescriptor)) + { + for (Int32 i = 0; i < ifaceDescriptor.bNumEndpoints; i++) + { + WinUsb_QueryPipe(m_WinUsbHandle, 0, System.Convert.ToByte(i), ref pipeInfo); + + if (((pipeInfo.PipeType == USBD_PIPE_TYPE.UsbdPipeTypeBulk) & UsbEndpointDirectionIn(pipeInfo.PipeId))) + { + m_BulkIn = pipeInfo.PipeId; + WinUsb_FlushPipe(m_WinUsbHandle, m_BulkIn); + } + else if (((pipeInfo.PipeType == USBD_PIPE_TYPE.UsbdPipeTypeBulk) & UsbEndpointDirectionOut(pipeInfo.PipeId))) + { + m_BulkOut = pipeInfo.PipeId; + WinUsb_FlushPipe(m_WinUsbHandle, m_BulkOut); + } + else if ((pipeInfo.PipeType == USBD_PIPE_TYPE.UsbdPipeTypeInterrupt) & UsbEndpointDirectionIn(pipeInfo.PipeId)) + { + m_IntIn = pipeInfo.PipeId; + WinUsb_FlushPipe(m_WinUsbHandle, m_IntIn); + } + else if ((pipeInfo.PipeType == USBD_PIPE_TYPE.UsbdPipeTypeInterrupt) & UsbEndpointDirectionOut(pipeInfo.PipeId)) + { + m_IntOut = pipeInfo.PipeId; + WinUsb_FlushPipe(m_WinUsbHandle, m_IntOut); + } + } + + return true; + } + + return false; + } + catch (Exception ex) + { + Console.WriteLine("{0} {1}", ex.HelpLink, ex.Message); + throw; + } + } + + protected virtual Boolean RestartDevice(String InstanceId) + { + IntPtr deviceInfoSet = IntPtr.Zero; + + try + { + SP_DEVICE_INTERFACE_DATA deviceInterfaceData = new SP_DEVICE_INTERFACE_DATA(); + + deviceInterfaceData.cbSize = Marshal.SizeOf(deviceInterfaceData); + deviceInfoSet = SetupDiGetClassDevs(ref m_Class, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + + if (SetupDiOpenDeviceInfo(deviceInfoSet, InstanceId, IntPtr.Zero, 0, ref deviceInterfaceData)) + { + SP_PROPCHANGE_PARAMS props = new SP_PROPCHANGE_PARAMS(); + + props.ClassInstallHeader = new SP_CLASSINSTALL_HEADER(); + props.ClassInstallHeader.cbSize = Marshal.SizeOf(props.ClassInstallHeader); + props.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; + + props.Scope = DICS_FLAG_GLOBAL; + props.StateChange = DICS_PROPCHANGE; + props.HwProfile = 0x00; + + if (SetupDiSetClassInstallParams(deviceInfoSet, ref deviceInterfaceData, ref props, Marshal.SizeOf(props))) + { + return SetupDiChangeState(deviceInfoSet, ref deviceInterfaceData); + } + } + } + catch (Exception ex) + { + Console.WriteLine("{0} {1}", ex.HelpLink, ex.Message); + throw; + } + finally + { + if (deviceInfoSet != IntPtr.Zero) + { + SetupDiDestroyDeviceInfoList(deviceInfoSet); + } + } + + return false; + } + #endregion + + #region Interop Definitions + [DllImport("setupapi.dll", SetLastError = true)] + protected static extern Int32 SetupDiCreateDeviceInfoList(ref System.Guid ClassGuid, Int32 hwndParent); + + [DllImport("setupapi.dll", SetLastError = true)] + protected static extern Int32 SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet); + + [DllImport("setupapi.dll", SetLastError = true)] + protected static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr DeviceInfoSet, IntPtr DeviceInfoData, ref System.Guid InterfaceClassGuid, Int32 MemberIndex, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData); + + [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] + protected static extern IntPtr SetupDiGetClassDevs(ref System.Guid ClassGuid, IntPtr Enumerator, IntPtr hwndParent, Int32 Flags); + + [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] + protected static extern Boolean SetupDiGetDeviceInterfaceDetail(IntPtr DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, IntPtr DeviceInterfaceDetailData, Int32 DeviceInterfaceDetailDataSize, ref Int32 RequiredSize, IntPtr DeviceInfoData); + + [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] + protected static extern Boolean SetupDiGetDeviceInterfaceDetail(IntPtr DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, IntPtr DeviceInterfaceDetailData, Int32 DeviceInterfaceDetailDataSize, ref Int32 RequiredSize, ref SP_DEVICE_INTERFACE_DATA DeviceInfoData); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + protected static extern IntPtr RegisterDeviceNotification(IntPtr hRecipient, IntPtr NotificationFilter, Int32 Flags); + + [DllImport("user32.dll", SetLastError = true)] + protected static extern Boolean UnregisterDeviceNotification(IntPtr Handle); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + protected static extern SafeFileHandle CreateFile(String lpFileName, UInt32 dwDesiredAccess, UInt32 dwShareMode, IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition, UInt32 dwFlagsAndAttributes, UInt32 hTemplateFile); + + [DllImport("winusb.dll", SetLastError = true)] + protected static extern Boolean WinUsb_Initialize(SafeFileHandle DeviceHandle, ref IntPtr InterfaceHandle); + + [DllImport("winusb.dll", SetLastError = true)] + protected static extern Boolean WinUsb_QueryInterfaceSettings(IntPtr InterfaceHandle, Byte AlternateInterfaceNumber, ref USB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor); + + [DllImport("winusb.dll", SetLastError = true)] + protected static extern Boolean WinUsb_QueryPipe(IntPtr InterfaceHandle, Byte AlternateInterfaceNumber, Byte PipeIndex, ref WINUSB_PIPE_INFORMATION PipeInformation); + + [DllImport("winusb.dll", SetLastError = true)] + protected static extern Boolean WinUsb_AbortPipe(IntPtr InterfaceHandle, Byte PipeID); + + [DllImport("winusb.dll", SetLastError = true)] + protected static extern Boolean WinUsb_FlushPipe(IntPtr InterfaceHandle, Byte PipeID); + + [DllImport("winusb.dll", SetLastError = true)] + protected static extern Boolean WinUsb_ControlTransfer(IntPtr InterfaceHandle, WINUSB_SETUP_PACKET SetupPacket, Byte[] Buffer, Int32 BufferLength, ref Int32 LengthTransferred, IntPtr Overlapped); + + [DllImport("winusb.dll", SetLastError = true)] + protected static extern Boolean WinUsb_ReadPipe(IntPtr InterfaceHandle, Byte PipeID, Byte[] Buffer, Int32 BufferLength, ref Int32 LengthTransferred, IntPtr Overlapped); + + [DllImport("winusb.dll", SetLastError = true)] + protected static extern Boolean WinUsb_WritePipe(IntPtr InterfaceHandle, Byte PipeID, Byte[] Buffer, Int32 BufferLength, ref Int32 LengthTransferred, IntPtr Overlapped); + + [DllImport("winusb.dll", SetLastError = true)] + protected static extern Boolean WinUsb_Free(IntPtr InterfaceHandle); + + [DllImport("advapi32.dll", SetLastError = true)] + public static extern IntPtr RegisterServiceCtrlHandlerEx(String ServiceName, ServiceControlHandlerEx Callback, IntPtr Context); + + [DllImport("kernel32.dll", SetLastError = true)] + protected static extern Boolean DeviceIoControl(SafeFileHandle DeviceHandle, Int32 IoControlCode, Byte[] InBuffer, Int32 InBufferSize, Byte[] OutBuffer, Int32 OutBufferSize, ref Int32 BytesReturned, IntPtr Overlapped); + + [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] + protected static extern Int32 CM_Get_Device_ID(Int32 dnDevInst, IntPtr Buffer, Int32 BufferLen, Int32 ulFlags); + + [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] + protected static extern Boolean SetupDiOpenDeviceInfo(IntPtr DeviceInfoSet, String DeviceInstanceId, IntPtr hwndParent, Int32 Flags, ref SP_DEVICE_INTERFACE_DATA DeviceInfoData); + + [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] + protected static extern Boolean SetupDiChangeState(IntPtr DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData); + + [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] + protected static extern Boolean SetupDiSetClassInstallParams(IntPtr DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, ref SP_PROPCHANGE_PARAMS ClassInstallParams, Int32 ClassInstallParamsSize); + #endregion + } +} diff --git a/DS4Control/ScpHub.Designer.cs b/DS4Control/ScpHub.Designer.cs new file mode 100644 index 0000000..efee6ef --- /dev/null +++ b/DS4Control/ScpHub.Designer.cs @@ -0,0 +1,36 @@ +namespace DS4Control +{ + partial class ScpHub + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + } + + #endregion + } +} diff --git a/DS4Control/ScpHub.cs b/DS4Control/ScpHub.cs new file mode 100644 index 0000000..0e1a038 --- /dev/null +++ b/DS4Control/ScpHub.cs @@ -0,0 +1,87 @@ +using System; +using System.ComponentModel; + +namespace DS4Control +{ + public partial class ScpHub : Component + { + protected IntPtr m_Reference = IntPtr.Zero; + protected volatile Boolean m_Started = false; + + public event EventHandler Debug = null; + + public event EventHandler Report = null; + + protected virtual Boolean LogDebug(String Data) + { + DebugEventArgs args = new DebugEventArgs(Data); + + On_Debug(this, args); + + return true; + } + + public Boolean Active + { + get { return m_Started; } + } + + + public ScpHub() + { + InitializeComponent(); + } + + public ScpHub(IContainer container) + { + container.Add(this); + + InitializeComponent(); + } + + + public virtual Boolean Open() + { + return true; + } + + public virtual Boolean Start() + { + return m_Started; + } + + public virtual Boolean Stop() + { + return !m_Started; + } + + public virtual Boolean Close() + { + if (m_Reference != IntPtr.Zero) ScpDevice.UnregisterNotify(m_Reference); + + return !m_Started; + } + + + public virtual Boolean Suspend() + { + return true; + } + + public virtual Boolean Resume() + { + return true; + } + + protected virtual void On_Debug(object sender, DebugEventArgs e) + { + if (Debug != null) Debug(sender, e); + } + + + protected virtual void On_Report(object sender, ReportEventArgs e) + { + if (Report != null) Report(sender, e); + } + } +} diff --git a/DS4Control/ScpUtil.cs b/DS4Control/ScpUtil.cs new file mode 100644 index 0000000..4573eb9 --- /dev/null +++ b/DS4Control/ScpUtil.cs @@ -0,0 +1,817 @@ +using System; +using System.Collections.Generic; +using System.Text; + +using System.IO; +using System.Reflection; +using System.Xml; +using DS4Library; +namespace DS4Control +{ + [Flags] + public enum DS4KeyType : byte { None = 0, ScanCode = 1, Repeat = 2 }; //Increment by exponents of 2*, starting at 2^0 + public enum Ds3PadId : byte { None = 0xFF, One = 0x00, Two = 0x01, Three = 0x02, Four = 0x03, All = 0x04 }; + public enum DS4Controls : byte { LXNeg, LXPos, LYNeg, LYPos, RXNeg, RXPos, RYNeg, RYPos, L1, L2, L3, R1, R2, R3, Square, Triangle, Circle, Cross, DpadUp, DpadRight, DpadDown, DpadLeft, PS, TouchButton, TouchUpper, TouchMulti, Share, Options }; + public enum X360Controls : byte { LXNeg, LXPos, LYNeg, LYPos, RXNeg, RXPos, RYNeg, RYPos, LB, LT, LS, RB, RT, RS, X, Y, B, A, DpadUp, DpadRight, DpadDown, DpadLeft, Guide, Back, Start, LeftMouse, RightMouse, MiddleMouse, Unbound, + MouseLeft, MouseRight, MouseDown, MouseUp}; + + public class DebugEventArgs : EventArgs + { + protected DateTime m_Time = DateTime.Now; + protected String m_Data = String.Empty; + + public DebugEventArgs(String Data) + { + m_Data = Data; + } + + public DateTime Time + { + get { return m_Time; } + } + + public String Data + { + get { return m_Data; } + } + } + + public class MappingDoneEventArgs : EventArgs + { + protected int deviceNum = -1; + + public MappingDoneEventArgs(int DeviceID) + { + deviceNum = DeviceID; + } + + public int DeviceID + { + get { return deviceNum; } + } + } + + public class ReportEventArgs : EventArgs + { + protected Ds3PadId m_Pad = Ds3PadId.None; + protected Byte[] m_Report = new Byte[64]; + + public ReportEventArgs() + { + } + + public ReportEventArgs(Ds3PadId Pad) + { + m_Pad = Pad; + } + + public Ds3PadId Pad + { + get { return m_Pad; } + set { m_Pad = value; } + } + + public Byte[] Report + { + get { return m_Report; } + } + } + + public class Global + { + protected static BackingStore m_Config = new BackingStore(); + protected static Int32 m_IdleTimeout = 600000; + + public static DS4Color loadColor(int device) + { + DS4Color color = new DS4Color(); + color.red = m_Config.m_Leds[device][0]; + color.green = m_Config.m_Leds[device][1]; + color.blue = m_Config.m_Leds[device][2]; + return color; + } + public static void saveColor(int device, byte red, byte green, byte blue) + { + m_Config.m_Leds[device][0] = red; + m_Config.m_Leds[device][1] = green; + m_Config.m_Leds[device][2] = blue; + } + + public static byte loadRumbleBoost(int device) + { + return m_Config.m_Rumble[device]; + } + public static void saveRumbleBoost(int device, byte boost) + { + m_Config.m_Rumble[device] = boost; + + } + + public static bool getFlushHIDQueue(int device) + { + return m_Config.flushHIDQueue[device]; + } + public static void setFlushHIDQueue(int device, bool setting) + { + m_Config.flushHIDQueue[device] = setting; + } + + public static byte getTouchSensitivity(int device) + { + return m_Config.touchSensitivity[device]; + } + public static void setTouchSensitivity(int device, byte sen) + { + m_Config.touchSensitivity[device] = sen; + } + + public static void setFlashWhenLowBattery(int device, bool flash) + { + m_Config.flashLedLowBattery[device] = flash; + + } + public static bool getFlashWhenLowBattery(int device) + { + return m_Config.flashLedLowBattery[device]; + + } + + public static void setLedAsBatteryIndicator(int device, bool ledAsBattery) + { + m_Config.ledAsBattery[device] = ledAsBattery; + + } + public static bool getLedAsBatteryIndicator(int device) + { + return m_Config.ledAsBattery[device]; + } + + public static void setTouchEnabled(int device, bool touchEnabled) + { + m_Config.touchEnabled[device] = touchEnabled; + + } + public static bool getTouchEnabled(int device) + { + return m_Config.touchEnabled[device]; + + } + + public static void setUseExclusiveMode(bool exclusive) + { + m_Config.useExclusiveMode = exclusive; + } + public static bool getUseExclusiveMode() + { + return m_Config.useExclusiveMode; + } + + // New settings + public static void saveLowColor(int device, byte red, byte green, byte blue) + { + m_Config.m_LowLeds[device][0] = red; + m_Config.m_LowLeds[device][1] = green; + m_Config.m_LowLeds[device][2] = blue; + } + public static DS4Color loadLowColor(int device) + { + DS4Color color = new DS4Color(); + color.red = m_Config.m_LowLeds[device][0]; + color.green = m_Config.m_LowLeds[device][1]; + color.blue = m_Config.m_LowLeds[device][2]; + return color; + } + public static void setTapSensitivity(int device, byte sen) + { + m_Config.tapSensitivity[device] = sen; + } + public static byte getTapSensitivity(int device) + { + return m_Config.tapSensitivity[device]; + } + public static void setScrollSensitivity(int device, int sen) + { + m_Config.scrollSensitivity[device] = sen; + } + public static int getScrollSensitivity(int device) + { + return m_Config.scrollSensitivity[device]; + } + public static void setLowerRCOff(int device, bool twoFingerRC) + { + m_Config.lowerRCOff[device] = twoFingerRC; + } + public static bool getLowerRCOff(int device) + { + return m_Config.lowerRCOff[device]; + } + public static void setTouchpadJitterCompensation(int device, bool enabled) + { + m_Config.touchpadJitterCompensation[device] = enabled; + } + public static bool getTouchpadJitterCompensation(int device) + { + return m_Config.touchpadJitterCompensation[device]; + } + public static void setStartMinimized(bool startMinimized) + { + m_Config.startMinimized = startMinimized; + } + public static bool getStartMinimized() + { + return m_Config.startMinimized; + } + public static void setFormWidth(int size) + { + m_Config.formWidth = size; + } + public static int getFormWidth() + { + return m_Config.formWidth; + } + public static void setFormHeight(int size) + { + m_Config.formHeight = size; + } + public static int getFormHeight() + { + return m_Config.formHeight; + } + + public static double getLeftTriggerMiddle(int device) + { + return m_Config.m_LeftTriggerMiddle[device]; + } + public static void setLeftTriggerMiddle(int device, double value) + { + m_Config.m_LeftTriggerMiddle[device] = value; + } + + public static double getRightTriggerMiddle(int device) + { + return m_Config.m_RightTriggerMiddle[device]; + } + public static void setRightTriggerMiddle(int device, double value) + { + m_Config.m_RightTriggerMiddle[device] = value; + } + + public static void setCustomMap(int device, string customMap) + { + m_Config.customMapPath[device] = customMap; + } + public static string getCustomMap(int device) + { + return m_Config.customMapPath[device]; + } + public static bool saveCustomMapping(string customMapPath, System.Windows.Forms.Control[] buttons) + { + return m_Config.SaveCustomMapping(customMapPath, buttons); + } + public static bool loadCustomMapping(string customMapPath, System.Windows.Forms.Control[] buttons) + { + return m_Config.LoadCustomMapping(customMapPath, buttons); + } + public static bool loadCustomMapping(int device) + { + return m_Config.LoadCustomMapping(getCustomMap(device)); + } + public static X360Controls getCustomButton(DS4Controls controlName) + { + return m_Config.GetCustomButton(controlName); + } + public static ushort getCustomKey(DS4Controls controlName) + { + return m_Config.GetCustomKey(controlName); + } + public static DS4KeyType getCustomKeyType(DS4Controls controlName) + { + return m_Config.GetCustomKeyType(controlName); + } + public static bool getHasCustomKeysorButtons(int device) + { + return m_Config.customMapButtons.Count > 0 + || m_Config.customMapKeys.Count > 0; + } + public static Dictionary getCustomButtons() + { + return m_Config.customMapButtons; + } + public static Dictionary getCustomKeys() + { + return m_Config.customMapKeys; + } + public static Dictionary getCustomKeyTypes() + { + return m_Config.customMapKeyTypes; + } + + public static void Load() + { + m_Config.Load(); + } + public static void Save() + { + m_Config.Save(); + } + + private static byte applyRatio(byte b1, byte b2, uint r) + { + uint ratio = r; + if (b1 > b2) + { + ratio = 100 - r; + } + byte bmax = Math.Max(b1, b2); + byte bmin = Math.Min(b1, b2); + byte bdif = (byte)(bmax - bmin); + return (byte)(bmin + (bdif * ratio / 100)); + } + public static DS4Color getTransitionedColor(byte[] c1, byte[] c2, uint ratio) + { + DS4Color color = new DS4Color(); + color.red = 255; + color.green = 255; + color.blue = 255; + uint r = ratio % 101; + if (c1.Length != 3 || c2.Length != 3 || ratio < 0) + { + return color; + } + color.red = applyRatio(c1[0], c2[0], ratio); + color.green = applyRatio(c1[1], c2[1], ratio); + color.blue = applyRatio(c1[2], c2[2], ratio); + + return color; + } + } + + + + public class BackingStore + { + protected String m_File = Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName + @"\ScpControl.xml"; + protected XmlDocument m_Xdoc = new XmlDocument(); + + public Boolean[] touchpadJitterCompensation = { true, true, true, true }; + public Boolean[] lowerRCOff = { false, false, false, false }; + public Boolean[] ledAsBattery = { false, false, false, false }; + public Boolean[] flashLedLowBattery = { false, false, false, false }; + public Boolean[] touchEnabled = { false, false, false, false }; + public double[] m_LeftTriggerMiddle = { 0.5, 0.5, 0.5, 0.5 }, m_RightTriggerMiddle = { 0.5, 0.5, 0.5, 0.5 }; + public String[] customMapPath = { String.Empty, String.Empty, String.Empty, String.Empty }; + public Byte[] m_Rumble = { 100, 100, 100, 100 }; + public Byte[] touchSensitivity = { 100, 100, 100, 100 }; + public Byte[] tapSensitivity = { 0, 0, 0, 0 }; + public int[] scrollSensitivity = { 0, 0, 0, 0 }; + public Byte[][] m_LowLeds = new Byte[][] + { + new Byte[] {0,0,0}, + new Byte[] {0,0,0}, + new Byte[] {0,0,0}, + new Byte[] {0,0,0} + }; + public Byte[][] m_Leds = new Byte[][] + { + new Byte[] {0,0,255}, + new Byte[] {255,0,0}, + new Byte[] {0,255,0}, + new Byte[] {255,0,255}, + }; + public bool[] flushHIDQueue = { true, true, true, true }; + + public Boolean useExclusiveMode = false; + public Int32 formWidth = 782; + public Int32 formHeight = 550; + public Boolean startMinimized = false; + + public Dictionary customMapKeyTypes = new Dictionary(); + public Dictionary customMapKeys = new Dictionary(); + public Dictionary customMapButtons = new Dictionary(); + public X360Controls GetCustomButton(DS4Controls controlName) + { + if (customMapButtons.ContainsKey(controlName)) + return customMapButtons[controlName]; + else return 0; + } + public UInt16 GetCustomKey(DS4Controls controlName) + { + if (customMapKeys.ContainsKey(controlName)) + return customMapKeys[controlName]; + else return 0; + } + public DS4KeyType GetCustomKeyType(DS4Controls controlName) + { + if (customMapKeyTypes.ContainsKey(controlName)) + return customMapKeyTypes[controlName]; + else return 0; + } + + public Boolean LoadCustomMapping(String customMapPath) + { + Boolean Loaded = true; + customMapButtons.Clear(); + customMapKeys.Clear(); + customMapKeyTypes.Clear(); + try + { + if (customMapPath != string.Empty && File.Exists(customMapPath)) + { + m_Xdoc.Load(customMapPath); + DS4KeyType keyType; + UInt16 wvk; + XmlNode ParentItem = m_Xdoc.SelectSingleNode("/Control/Button"); + if (ParentItem != null) + foreach (XmlNode Item in ParentItem.ChildNodes) + customMapButtons.Add(getDS4ControlsByName(Item.Name), getX360ControlsByName(Item.InnerText)); + ParentItem = m_Xdoc.SelectSingleNode("/Control/Key"); + if (ParentItem != null) + foreach (XmlNode Item in ParentItem.ChildNodes) + if (UInt16.TryParse(Item.InnerText, out wvk)) + customMapKeys.Add(getDS4ControlsByName(Item.Name), wvk); + ParentItem = m_Xdoc.SelectSingleNode("/Control/KeyType"); + if (ParentItem != null) + foreach (XmlNode Item in ParentItem.ChildNodes) + if (Item != null) + { + keyType = DS4KeyType.None; + if (Item.InnerText.Contains(DS4KeyType.ScanCode.ToString())) + keyType |= DS4KeyType.ScanCode; + if (Item.InnerText.Contains(DS4KeyType.Repeat.ToString())) + keyType |= DS4KeyType.Repeat; + if (keyType != DS4KeyType.None) + customMapKeyTypes.Add(getDS4ControlsByName(Item.Name), keyType); + } + } + } + catch (Exception) + { + Loaded = false; + } + return Loaded; + } + public Boolean LoadCustomMapping(String customMapPath, System.Windows.Forms.Control[] buttons) + { + Boolean Loaded = true; + customMapButtons.Clear(); + customMapKeys.Clear(); + customMapKeyTypes.Clear(); + try + { + if (customMapPath != string.Empty && File.Exists(customMapPath)) + { + XmlNode Item; + m_Xdoc.Load(customMapPath); + DS4KeyType keyType; + UInt16 wvk; + foreach (var button in buttons) + try + { + Item = m_Xdoc.SelectSingleNode(String.Format("/Control/Key/{0}", button.Name)); + if (Item != null) + { + if (UInt16.TryParse(Item.InnerText, out wvk)) + { + customMapKeys.Add(getDS4ControlsByName(Item.Name), wvk); + button.Tag = wvk; + button.Text = ((System.Windows.Forms.Keys)wvk).ToString(); + + Item = m_Xdoc.SelectSingleNode(String.Format("/Control/KeyType/{0}", button.Name)); + if (Item != null) + { + keyType = DS4KeyType.None; + if (Item.InnerText.Contains(DS4KeyType.ScanCode.ToString())) + { + keyType |= DS4KeyType.ScanCode; + button.Font = new System.Drawing.Font(button.Font, System.Drawing.FontStyle.Bold); + } + if (Item.InnerText.Contains(DS4KeyType.Repeat.ToString())) + { + keyType |= DS4KeyType.Repeat; + button.ForeColor = System.Drawing.Color.Red; + } + if (keyType != DS4KeyType.None) + customMapKeyTypes.Add(getDS4ControlsByName(Item.Name), keyType); + } + } + } + else + { + Item = m_Xdoc.SelectSingleNode(String.Format("/Control/Button/{0}", button.Name)); + if (Item != null) + { + button.Tag = Item.InnerText; + button.Text = Item.InnerText; + customMapButtons.Add(getDS4ControlsByName(button.Name), getX360ControlsByName(Item.InnerText)); + } + } + } + catch + { + + } + } + } + catch + { + Loaded = false; + } + return Loaded; + } + public Boolean SaveCustomMapping(String customMapPath, System.Windows.Forms.Control[] buttons) + { + Boolean Saved = true; + try + { + XmlNode Node; + m_Xdoc.RemoveAll(); + Node = m_Xdoc.CreateXmlDeclaration("1.0", "utf-8", String.Empty); + m_Xdoc.AppendChild(Node); + Node = m_Xdoc.CreateComment(String.Format(" Custom Control Mapping Data. {0} ", DateTime.Now)); + m_Xdoc.AppendChild(Node); + Node = m_Xdoc.CreateWhitespace("\r\n"); + m_Xdoc.AppendChild(Node); + Node = m_Xdoc.CreateNode(XmlNodeType.Element, "Control", null); + + XmlNode Key = m_Xdoc.CreateNode(XmlNodeType.Element, "Key", null); + XmlNode KeyType = m_Xdoc.CreateNode(XmlNodeType.Element, "KeyType", null); + XmlNode Button = m_Xdoc.CreateNode(XmlNodeType.Element, "Button", null); + + foreach (var button in buttons) + try + { + // Save even if string (for xbox controller buttons) + if (button.Tag != null) + { + XmlNode buttonNode; + string keyType = String.Empty; + if (button.ForeColor == System.Drawing.Color.Red) + keyType += DS4KeyType.Repeat; + if (button.Font.Bold) + keyType += DS4KeyType.ScanCode; + if (keyType != String.Empty) + { + buttonNode = m_Xdoc.CreateNode(XmlNodeType.Element, button.Name, null); + buttonNode.InnerText = keyType; + KeyType.AppendChild(buttonNode); + } + buttonNode = m_Xdoc.CreateNode(XmlNodeType.Element, button.Name, null); + buttonNode.InnerText = button.Tag.ToString(); + if (button.Tag is Int32 || button.Tag is UInt16) + Key.AppendChild(buttonNode); + else Button.AppendChild(buttonNode); + } + } + catch + { + Saved = false; + } + m_Xdoc.AppendChild(Node); + if (Button.HasChildNodes) + Node.AppendChild(Button); + if (Key.HasChildNodes) + Node.AppendChild(Key); + if (KeyType.HasChildNodes) + Node.AppendChild(KeyType); + m_Xdoc.Save(customMapPath); + } + catch (Exception) + { + Saved = false; + } + return Saved; + } + + private DS4Controls getDS4ControlsByName(string key) + { + switch (key) + { + case "bnShare": return DS4Controls.Share; + case "bnL3": return DS4Controls.L3; + case "bnR3": return DS4Controls.R3; + case "bnOptions": return DS4Controls.Options; + case "bnUp": return DS4Controls.DpadUp; + case "bnRight": return DS4Controls.DpadRight; + case "bnDown": return DS4Controls.DpadDown; + case "bnLeft": return DS4Controls.DpadLeft; + + case "bnL1": return DS4Controls.L1; + case "bnR1": return DS4Controls.R1; + case "bnTriangle": return DS4Controls.Triangle; + case "bnCircle": return DS4Controls.Circle; + case "bnCross": return DS4Controls.Cross; + case "bnSquare": return DS4Controls.Square; + + case "bnPS": return DS4Controls.PS; + case "bnLX": return DS4Controls.LXNeg; + case "bnLY": return DS4Controls.LYNeg; + case "bnRX": return DS4Controls.RXNeg; + case "bnRY": return DS4Controls.RYNeg; + case "bnLX2": return DS4Controls.LXPos; + case "bnLY2": return DS4Controls.LYPos; + case "bnRX2": return DS4Controls.RXPos; + case "bnRY2": return DS4Controls.RYPos; + case "bnL2": return DS4Controls.L2; + case "bnR2": return DS4Controls.R2; + + case "bnTouchpad": return DS4Controls.TouchButton; + case "bnTouchMulti": return DS4Controls.TouchMulti; + case "bnTouchUpper": return DS4Controls.TouchUpper; + } + return 0; + } + private X360Controls getX360ControlsByName(string key) + { + switch (key) + { + case "Back": return X360Controls.Back; + case "Left Stick": return X360Controls.LS; + case "Right Stick": return X360Controls.RS; + case "Start": return X360Controls.Start; + case "Up Button": return X360Controls.DpadUp; + case "Right Button": return X360Controls.DpadRight; + case "Down Button": return X360Controls.DpadDown; + case "Left Button": return X360Controls.DpadLeft; + + case "Left Bumper": return X360Controls.LB; + case "Right Bumper": return X360Controls.RB; + case "Y Button": return X360Controls.Y; + case "B Button": return X360Controls.B; + case "A Button": return X360Controls.A; + case "X Button": return X360Controls.X; + + case "Guide": return X360Controls.Guide; + case "Left X-Axis-": return X360Controls.LXNeg; + case "Left Y-Axis-": return X360Controls.LYNeg; + case "Right X-Axis-": return X360Controls.RXNeg; + case "Right Y-Axis-": return X360Controls.RYNeg; + + case "Left X-Axis+": return X360Controls.LXPos; + case "Left Y-Axis+": return X360Controls.LYPos; + case "Right X-Axis+": return X360Controls.RXPos; + case "Right Y-Axis+": return X360Controls.RYPos; + case "Left Trigger": return X360Controls.LT; + case "Right Trigger": return X360Controls.RT; + case "Click": return X360Controls.LeftMouse; + case "Right Click": return X360Controls.RightMouse; + case "Middle Click": return X360Controls.MiddleMouse; + case "Mouse Up": return X360Controls.MouseUp; + case "Mouse Down": return X360Controls.MouseDown; + case "Mouse Left": return X360Controls.MouseLeft; + case "Mouse Right": return X360Controls.MouseRight; + case "(Unbound)": return X360Controls.Unbound; + + } + return X360Controls.Unbound; + } + public Boolean Load() + { + Boolean Loaded = true; + Boolean missingSetting = false; + + try + { + if (File.Exists(m_File)) + { + XmlNode Item; + + m_Xdoc.Load(m_File); + + + for (int i = 0; i < 4; i++) + { + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/Controller" + (i + 1) + "/flushHIDQueue"); Boolean.TryParse(Item.InnerText, out flushHIDQueue[i]); } + catch { missingSetting = true; } + + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/Controller" + (i + 1) + "/Red"); Byte.TryParse(Item.InnerText, out m_Leds[i][0]); } + catch { missingSetting = true; } + + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/Controller" + (i + 1) + "/Green"); Byte.TryParse(Item.InnerText, out m_Leds[i][1]); } + catch { missingSetting = true; } + + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/Controller" + (i + 1) + "/Blue"); Byte.TryParse(Item.InnerText, out m_Leds[i][2]); } + catch { missingSetting = true; } + + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/Controller" + (i + 1) + "/RumbleBoost"); Byte.TryParse(Item.InnerText, out m_Rumble[i]); } + catch { missingSetting = true; } + + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/Controller" + (i + 1) + "/ledAsBatteryIndicator"); Boolean.TryParse(Item.InnerText, out ledAsBattery[i]); } + catch { missingSetting = true; } + + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/Controller" + (i + 1) + "/lowBatteryFlash"); Boolean.TryParse(Item.InnerText, out flashLedLowBattery[i]); } + catch { missingSetting = true; } + + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/Controller" + (i + 1) + "/touchSensitivity"); Byte.TryParse(Item.InnerText, out touchSensitivity[i]); } + catch { missingSetting = true; } + + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/Controller" + (i + 1) + "/touchEnabled"); Boolean.TryParse(Item.InnerText, out touchEnabled[i]); } + catch { missingSetting = true; } + + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/Controller" + (i + 1) + "/LowRed"); Byte.TryParse(Item.InnerText, out m_LowLeds[i][0]); } + catch { missingSetting = true; } + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/Controller" + (i + 1) + "/LowGreen"); Byte.TryParse(Item.InnerText, out m_LowLeds[i][1]); } + catch { missingSetting = true; } + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/Controller" + (i + 1) + "/LowBlue"); Byte.TryParse(Item.InnerText, out m_LowLeds[i][2]); } + catch { missingSetting = true; } + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/Controller" + (i + 1) + "/touchpadJitterCompensation"); Boolean.TryParse(Item.InnerText, out touchpadJitterCompensation[i]); } + catch { missingSetting = true; } + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/Controller" + (i + 1) + "/lowerRCOff"); Boolean.TryParse(Item.InnerText, out lowerRCOff[i]); } + catch { missingSetting = true; } + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/Controller" + (i + 1) + "/tapSensitivity"); Byte.TryParse(Item.InnerText, out tapSensitivity[i]); } + catch { missingSetting = true; } + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/Controller" + (i + 1) + "/scrollSensitivity"); Int32.TryParse(Item.InnerText, out scrollSensitivity[i]); } + catch { missingSetting = true; } + // XXX This sucks, let's do better at removing old values that are no longer valid.... + if (scrollSensitivity[i] > 10) + scrollSensitivity[i] = 5; + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/Controller" + (i + 1) + "/customMapPath"); customMapPath[i] = Item.InnerText; } + catch { missingSetting = true; } + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/Controller" + (i + 1) + "/LeftTriggerMiddle"); Double.TryParse(Item.InnerText, out m_LeftTriggerMiddle[i]); } + catch { missingSetting = true; } + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/Controller" + (i + 1) + "/RightTriggerMiddle"); Double.TryParse(Item.InnerText, out m_RightTriggerMiddle[i]); } + catch { missingSetting = true; } + } + + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/useExclusiveMode"); Boolean.TryParse(Item.InnerText, out useExclusiveMode); } + catch { missingSetting = true; } + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/startMinimized"); Boolean.TryParse(Item.InnerText, out startMinimized); } + catch { missingSetting = true; } + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/formWidth"); Int32.TryParse(Item.InnerText, out formWidth); } + catch { missingSetting = true; } + try { Item = m_Xdoc.SelectSingleNode("/ScpControl/formHeight"); Int32.TryParse(Item.InnerText, out formHeight); } + catch { missingSetting = true; } + } + } + catch { Loaded = false; } + + // Only add missing settings if the actual load was graceful + if (missingSetting && Loaded) + Save(); + + return Loaded; + } + public Boolean Save() + { + Boolean Saved = true; + + try + { + XmlNode Node, Entry; + + m_Xdoc.RemoveAll(); + + Node = m_Xdoc.CreateXmlDeclaration("1.0", "utf-8", String.Empty); + m_Xdoc.AppendChild(Node); + + Node = m_Xdoc.CreateComment(String.Format(" ScpControl Configuration Data. {0} ", DateTime.Now)); + m_Xdoc.AppendChild(Node); + + Node = m_Xdoc.CreateWhitespace("\r\n"); + m_Xdoc.AppendChild(Node); + + Node = m_Xdoc.CreateNode(XmlNodeType.Element, "ScpControl", null); + + XmlNode xmlUseExclNode = m_Xdoc.CreateNode(XmlNodeType.Element, "useExclusiveMode", null); xmlUseExclNode.InnerText = useExclusiveMode.ToString(); Node.AppendChild(xmlUseExclNode); + XmlNode xmlStartMinimized = m_Xdoc.CreateNode(XmlNodeType.Element, "startMinimized", null); xmlStartMinimized.InnerText = startMinimized.ToString(); Node.AppendChild(xmlStartMinimized); + XmlNode xmlFormWidth = m_Xdoc.CreateNode(XmlNodeType.Element, "formWidth", null); xmlFormWidth.InnerText = formWidth.ToString(); Node.AppendChild(xmlFormWidth); + XmlNode xmlFormHeight = m_Xdoc.CreateNode(XmlNodeType.Element, "formHeight", null); xmlFormHeight.InnerText = formHeight.ToString(); Node.AppendChild(xmlFormHeight); + + XmlNode cNode1 = m_Xdoc.CreateNode(XmlNodeType.Element, "Controller1", null); Node.AppendChild(cNode1); + XmlNode cNode2 = m_Xdoc.CreateNode(XmlNodeType.Element, "Controller2", null); Node.AppendChild(cNode2); + XmlNode cNode3 = m_Xdoc.CreateNode(XmlNodeType.Element, "Controller3", null); Node.AppendChild(cNode3); + XmlNode cNode4 = m_Xdoc.CreateNode(XmlNodeType.Element, "Controller4", null); Node.AppendChild(cNode4); + + XmlNode[] cNodes = { cNode1, cNode2, cNode3, cNode4 }; + + for (int i = 0; i < 4; i++) + { + Entry = m_Xdoc.CreateNode(XmlNodeType.Element, "flushHIDQueue", null); Entry.InnerText = flushHIDQueue[i].ToString(); cNodes[i].AppendChild(Entry); + Entry = m_Xdoc.CreateNode(XmlNodeType.Element, "Red", null); Entry.InnerText = m_Leds[i][0].ToString(); cNodes[i].AppendChild(Entry); + Entry = m_Xdoc.CreateNode(XmlNodeType.Element, "Green", null); Entry.InnerText = m_Leds[i][1].ToString(); cNodes[i].AppendChild(Entry); + Entry = m_Xdoc.CreateNode(XmlNodeType.Element, "Blue", null); Entry.InnerText = m_Leds[i][2].ToString(); cNodes[i].AppendChild(Entry); + Entry = m_Xdoc.CreateNode(XmlNodeType.Element, "RumbleBoost", null); Entry.InnerText = m_Rumble[i].ToString(); cNodes[i].AppendChild(Entry); + Entry = m_Xdoc.CreateNode(XmlNodeType.Element, "ledAsBatteryIndicator", null); Entry.InnerText = ledAsBattery[i].ToString(); cNodes[i].AppendChild(Entry); + Entry = m_Xdoc.CreateNode(XmlNodeType.Element, "lowBatteryFlash", null); Entry.InnerText = flashLedLowBattery[i].ToString(); cNodes[i].AppendChild(Entry); + Entry = m_Xdoc.CreateNode(XmlNodeType.Element, "touchSensitivity", null); Entry.InnerText = touchSensitivity[i].ToString(); cNodes[i].AppendChild(Entry); + Entry = m_Xdoc.CreateNode(XmlNodeType.Element, "touchEnabled", null); Entry.InnerText = touchEnabled[i].ToString(); cNodes[i].AppendChild(Entry); + Entry = m_Xdoc.CreateNode(XmlNodeType.Element, "LowRed", null); Entry.InnerText = m_LowLeds[i][0].ToString(); cNodes[i].AppendChild(Entry); + Entry = m_Xdoc.CreateNode(XmlNodeType.Element, "LowGreen", null); Entry.InnerText = m_LowLeds[i][1].ToString(); cNodes[i].AppendChild(Entry); + Entry = m_Xdoc.CreateNode(XmlNodeType.Element, "LowBlue", null); Entry.InnerText = m_LowLeds[i][2].ToString(); cNodes[i].AppendChild(Entry); + Entry = m_Xdoc.CreateNode(XmlNodeType.Element, "touchpadJitterCompensation", null); Entry.InnerText = touchpadJitterCompensation[i].ToString(); cNodes[i].AppendChild(Entry); + Entry = m_Xdoc.CreateNode(XmlNodeType.Element, "lowerRCOff", null); Entry.InnerText = lowerRCOff[i].ToString(); cNodes[i].AppendChild(Entry); + Entry = m_Xdoc.CreateNode(XmlNodeType.Element, "tapSensitivity", null); Entry.InnerText = tapSensitivity[i].ToString(); cNodes[i].AppendChild(Entry); + Entry = m_Xdoc.CreateNode(XmlNodeType.Element, "scrollSensitivity", null); Entry.InnerText = scrollSensitivity[i].ToString(); cNodes[i].AppendChild(Entry); + Entry = m_Xdoc.CreateNode(XmlNodeType.Element, "customMapPath", null); Entry.InnerText = customMapPath[i]; cNodes[i].AppendChild(Entry); + Entry = m_Xdoc.CreateNode(XmlNodeType.Element, "LeftTriggerMiddle", null); Entry.InnerText = m_LeftTriggerMiddle[i].ToString(); cNodes[i].AppendChild(Entry); + Entry = m_Xdoc.CreateNode(XmlNodeType.Element, "RightTriggerMiddle", null); Entry.InnerText = m_RightTriggerMiddle[i].ToString(); cNodes[i].AppendChild(Entry); + } + m_Xdoc.AppendChild(Node); + + m_Xdoc.Save(m_File); + } + catch { Saved = false; } + + return Saved; + } + } +} diff --git a/DS4Control/TPadModeSwitcher.cs b/DS4Control/TPadModeSwitcher.cs new file mode 100644 index 0000000..3c2f0bc --- /dev/null +++ b/DS4Control/TPadModeSwitcher.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using DS4Library; +namespace DS4Control +{ + class TPadModeSwitcher + { + List modes = new List(); + public event EventHandler Debug = null; + private DS4Device device; + Int32 currentTypeInd = 0; + public TPadModeSwitcher(DS4Device device, int deviceID) + { + this.device = device; + modes.Add(TouchpadDisabled.singleton); + modes.Add(new Mouse(deviceID)); + modes.Add(new ButtonMouse(deviceID, device)); + modes.Add(new MouseCursorOnly(deviceID)); + modes.Add(new DragMouse(deviceID)); + } + + public void switchMode(int ind) + { + ITouchpadBehaviour currentMode = modes.ElementAt(currentTypeInd); + device.Touchpad.TouchButtonDown -= currentMode.touchButtonDown; + device.Touchpad.TouchButtonUp -= currentMode.touchButtonUp; + device.Touchpad.TouchesBegan -= currentMode.touchesBegan; + device.Touchpad.TouchesMoved -= currentMode.touchesMoved; + device.Touchpad.TouchesEnded -= currentMode.touchesEnded; + setMode(ind); + } + + public void setMode(int ind) + { + ITouchpadBehaviour tmode = modes.ElementAt(ind); + device.Touchpad.TouchButtonDown += tmode.touchButtonDown; + device.Touchpad.TouchButtonUp += tmode.touchButtonUp; + device.Touchpad.TouchesBegan += tmode.touchesBegan; + device.Touchpad.TouchesMoved += tmode.touchesMoved; + device.Touchpad.TouchesEnded += tmode.touchesEnded; + currentTypeInd = ind; + LogDebug("Touchpad mode for " + device.MacAddress + " is now " + tmode.ToString()); + Log.LogToTray("Touchpad mode for " + device.MacAddress + " is now " + tmode.ToString()); + } + + public override string ToString() + { + return modes.ElementAt(currentTypeInd).ToString(); + } + + public void previousMode() + { + int i = currentTypeInd - 1; + if (i == -1) + i = modes.Count - 1; + switchMode(i); + } + + public void nextMode() + { + int i = currentTypeInd + 1; + if (i == modes.Count) + i = 0; + switchMode(i); + } + + private void LogDebug(string data) + { + if (Debug != null) + Debug(this, new DebugEventArgs(data)); + } + + public ITouchpadBehaviour getCurrentMode() + { + return modes.ElementAt(currentTypeInd); + } + } +} diff --git a/DS4Control/TouchpadDisabled.cs b/DS4Control/TouchpadDisabled.cs new file mode 100644 index 0000000..fab038a --- /dev/null +++ b/DS4Control/TouchpadDisabled.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using DS4Library; + +namespace DS4Control +{ + class TouchpadDisabled : ITouchpadBehaviour + { + public override string ToString() + { + return "Disabled"; + } + + public static readonly TouchpadDisabled singleton = new TouchpadDisabled(); + + public void touchesMoved(object sender, TouchpadEventArgs arg) { } + + public void touchesBegan(object sender, TouchpadEventArgs arg) { } + + public void touchesEnded(object sender, TouchpadEventArgs arg) { } + + public void touchButtonUp(object sender, TouchpadEventArgs arg) { } + + public void touchButtonDown(object sender, TouchpadEventArgs arg) { } + + public void untouched(object sender, TouchpadEventArgs nullUnused) { } + } +} diff --git a/DS4Control/X360Device.cs b/DS4Control/X360Device.cs new file mode 100644 index 0000000..0b4eee4 --- /dev/null +++ b/DS4Control/X360Device.cs @@ -0,0 +1,203 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Windows.Forms; +using DS4Library; +using System.Runtime.InteropServices; +using Microsoft.Win32.SafeHandles; + +namespace DS4Control +{ + public partial class X360Device : ScpDevice + { + public const String DS3_BUS_CLASS_GUID = "{F679F562-3164-42CE-A4DB-E7DDBE723909}"; + + protected virtual Int32 Scale(Int32 Value, Boolean Flip) + { + Value -= 0x80; + + if (Value == -128) Value = -127; + if (Flip) Value *= -1; + + return (Int32)((float)Value * 258.00787401574803149606299212599f); + } + + + public X360Device() + : base(DS3_BUS_CLASS_GUID) + { + InitializeComponent(); + } + + public X360Device(IContainer container) + : base(DS3_BUS_CLASS_GUID) + { + container.Add(this); + + InitializeComponent(); + } + + + public override Boolean Open(int Instance = 0) + { + if (base.Open(Instance)) + { + } + + return true; + } + + public override Boolean Open(String DevicePath) + { + m_Path = DevicePath; + m_WinUsbHandle = (IntPtr)INVALID_HANDLE_VALUE; + + if (GetDeviceHandle(m_Path)) + { + m_IsActive = true; + } + + return true; + } + + public override Boolean Start() + { + if (IsActive) + { + } + + return true; + } + + public override Boolean Stop() + { + if (IsActive) + { + //Unplug(0); + } + + return base.Stop(); + } + + public override Boolean Close() + { + if (IsActive) + { + Unplug(0); + } + + return base.Close(); + } + + + public virtual void Parse(DS4State state, Byte[] Output, int device) + { + Output[0] = 0x1C; + Output[4] = (Byte)(device + 1); + Output[9] = 0x14; + + for (int i = 10; i < Output.Length; i++) + { + Output[i] = 0; + } + if (state.Share) Output[10] |= (Byte)(1 << 5); // Back + if (state.L3) Output[10] |= (Byte)(1 << 6); // Left Thumb + if (state.R3) Output[10] |= (Byte)(1 << 7); // Right Thumb + if (state.Options) Output[10] |= (Byte)(1 << 4); // Start + + if (state.DpadUp) Output[10] |= (Byte)(1 << 0); // Up + if (state.DpadRight) Output[10] |= (Byte)(1 << 3); // Down + if (state.DpadDown) Output[10] |= (Byte)(1 << 1); // Right + if (state.DpadLeft) Output[10] |= (Byte)(1 << 2); // Left + + if (state.L1) Output[11] |= (Byte)(1 << 0); // Left Shoulder + if (state.R1) Output[11] |= (Byte)(1 << 1); // Right Shoulder + + if (state.Triangle) Output[11] |= (Byte)(1 << 7); // Y + if (state.Circle) Output[11] |= (Byte)(1 << 5); // B + if (state.Cross) Output[11] |= (Byte)(1 << 4); // A + if (state.Square) Output[11] |= (Byte)(1 << 6); // X + + if (state.PS) Output[11] |= (Byte)(1 << 2); // Guide + + Output[12] = state.L2; // Left Trigger + Output[13] = state.R2; // Right Trigger + + Int32 ThumbLX = Scale(state.LX, false); + Int32 ThumbLY = -Scale(state.LY, false); + Int32 ThumbRX = Scale(state.RX, false); + Int32 ThumbRY = -Scale(state.RY, false); + + Output[14] = (Byte)((ThumbLX >> 0) & 0xFF); // LX + Output[15] = (Byte)((ThumbLX >> 8) & 0xFF); + + Output[16] = (Byte)((ThumbLY >> 0) & 0xFF); // LY + Output[17] = (Byte)((ThumbLY >> 8) & 0xFF); + + Output[18] = (Byte)((ThumbRX >> 0) & 0xFF); // RX + Output[19] = (Byte)((ThumbRX >> 8) & 0xFF); + + Output[20] = (Byte)((ThumbRY >> 0) & 0xFF); // RY + Output[21] = (Byte)((ThumbRY >> 8) & 0xFF); + } + + public virtual Boolean Plugin(Int32 Serial) + { + if (IsActive) + { + Int32 Transfered = 0; + Byte[] Buffer = new Byte[16]; + + Buffer[0] = 0x10; + Buffer[1] = 0x00; + Buffer[2] = 0x00; + Buffer[3] = 0x00; + + Buffer[4] = (Byte)((Serial >> 0) & 0xFF); + Buffer[5] = (Byte)((Serial >> 8) & 0xFF); + Buffer[6] = (Byte)((Serial >> 16) & 0xFF); + Buffer[7] = (Byte)((Serial >> 24) & 0xFF); + + return DeviceIoControl(m_FileHandle, 0x2A4000, Buffer, Buffer.Length, null, 0, ref Transfered, IntPtr.Zero); + } + + return false; + } + + public virtual Boolean Unplug(Int32 Serial) + { + if (IsActive) + { + Int32 Transfered = 0; + Byte[] Buffer = new Byte[16]; + + Buffer[0] = 0x10; + Buffer[1] = 0x00; + Buffer[2] = 0x00; + Buffer[3] = 0x00; + + Buffer[4] = (Byte)((Serial >> 0) & 0xFF); + Buffer[5] = (Byte)((Serial >> 8) & 0xFF); + Buffer[6] = (Byte)((Serial >> 16) & 0xFF); + Buffer[7] = (Byte)((Serial >> 24) & 0xFF); + + return DeviceIoControl(m_FileHandle, 0x2A4004, Buffer, Buffer.Length, null, 0, ref Transfered, IntPtr.Zero); + } + + return false; + } + + + public virtual Boolean Report(Byte[] Input, Byte[] Output) + { + if (IsActive) + { + Int32 Transfered = 0; + + return DeviceIoControl(m_FileHandle, 0x2A400C, Input, Input.Length, Output, Output.Length, ref Transfered, IntPtr.Zero) && Transfered > 0; + } + + return false; + } + } +} diff --git a/DS4Control/X360Device.designer.cs b/DS4Control/X360Device.designer.cs new file mode 100644 index 0000000..5403e63 --- /dev/null +++ b/DS4Control/X360Device.designer.cs @@ -0,0 +1,36 @@ +namespace DS4Control +{ + partial class X360Device + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + } + + #endregion + } +} diff --git a/DS4Library/DS4Device.cs b/DS4Library/DS4Device.cs new file mode 100644 index 0000000..e245a58 --- /dev/null +++ b/DS4Library/DS4Device.cs @@ -0,0 +1,482 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Threading; + +using System.Runtime.InteropServices; +using Microsoft.Win32.SafeHandles; +using System.Diagnostics; +using HidLibrary; +using System.Threading.Tasks; + + +using System.Linq; +using System.Text; +using System.IO; +using System.Collections; +namespace DS4Library +{ + public struct DS4Color + { + public byte red; + public byte green; + public byte blue; + } + + public enum ConnectionType : byte { USB, BT }; + + public class DS4Device + { + private const int BT_OUTPUT_REPORT_LENGTH = 78; + private const int BT_INPUT_REPORT_LENGTH = 547; + private HidDevice hDevice; + private string Mac; + private DS4State cState = new DS4State(); + private DS4State pState = new DS4State(); + private ConnectionType conType; + private byte[] accel = new byte[6]; + private byte[] gyro = new byte[6]; + private byte[] inputReport = new byte[64]; + private byte[] btInputReport = null; + private byte[] outputReport = null; + private readonly DS4Touchpad touchpad = null; + private byte rightLightFastRumble; + private byte leftHeavySlowRumble; + private DS4Color ligtBarColor; + private byte ledFlashOn, ledFlashOff; + private bool isDirty = false; + private Thread updaterThread = null; + private int battery; + private int idleTimeout = 1200; + private DateTime lastActive = DateTime.Now; + public event EventHandler Report = null; + public event EventHandler Removal = null; + + public int IdleTimeout { get { return idleTimeout; } + set { idleTimeout = value; } } + public HidDevice HidDevice { get { return hDevice; } } + + public string MacAddress { get { return Mac; } } + + public ConnectionType ConnectionType { get { return conType; } } + + public int Battery { get { return battery; } } + + public byte RightLightFastRumble + { + get { return rightLightFastRumble; } + set + { + if (value == rightLightFastRumble) return; + rightLightFastRumble = value; + isDirty = true; + } + } + + public byte LeftHeavySlowRumble + { + get { return leftHeavySlowRumble; } + set + { + if (value == leftHeavySlowRumble) return; + leftHeavySlowRumble = value; + isDirty = true; + } + } + + public DS4Color LightBarColor + { + get { return ligtBarColor; } + set + { + if (ligtBarColor.red != value.red || ligtBarColor.green != value.green || ligtBarColor.blue != value.blue) + { + ligtBarColor = value; + isDirty = true; + } + } + } + + public byte LightBarOnDuration + { + get { return ledFlashOn; } + set + { + if (ledFlashOn != value) + { + ledFlashOn = value; + isDirty = true; + } + } + } + + public byte LightBarOffDuration + { + get { return ledFlashOff; } + set + { + if (ledFlashOff != value) + { + ledFlashOff = value; + isDirty = true; + } + } + } + + public DS4Touchpad Touchpad { get { return touchpad; } } + + public DS4Device(HidDevice hidDevice) + { + hDevice = hidDevice; + hDevice.MonitorDeviceEvents = true; + conType = hDevice.Capabilities.InputReportByteLength == 64 ? ConnectionType.USB : ConnectionType.BT; + Mac = hDevice.readSerial(); + if (conType == ConnectionType.USB) + { + outputReport = new byte[hDevice.Capabilities.OutputReportByteLength]; + } + else + { + btInputReport = new byte[BT_INPUT_REPORT_LENGTH]; + outputReport = new byte[BT_OUTPUT_REPORT_LENGTH]; + } + touchpad = new DS4Touchpad(); + isDirty = true; + sendOutputReport(); + } + + public void StartUpdate() + { + if (updaterThread == null) + { + updaterThread = new Thread(updateCurrentState); + updaterThread.Name = "DS4 Update thread :" + Mac; + Console.WriteLine(updaterThread.Name + " has started"); + updaterThread.Start(); + } + else + Console.WriteLine("Thread already running for DS4: " + Mac); + } + + public void StopUpdate() + { + if (updaterThread.ThreadState != System.Threading.ThreadState.Stopped || updaterThread.ThreadState != System.Threading.ThreadState.Aborted) + { + try + { + updaterThread.Abort(); + updaterThread = null; + } + catch (Exception e) + { + Console.WriteLine(e.Message); + } + } + } + + private void updateCurrentState() + { + while (true) + { + if (conType != ConnectionType.USB) + if (hDevice.ReadFile(btInputReport) == HidDevice.ReadStatus.Success) + { + Array.Copy(btInputReport, 2, inputReport, 0, 64); + } + else + { + isDirty = true; + sendOutputReport(); // not sure why but without this Windows + //will not mark timed out controller as disonnected + if (Removal != null) + Removal(this, EventArgs.Empty); + return; + + } + else if (hDevice.ReadFile(inputReport) != HidDevice.ReadStatus.Success) + { + if (Removal != null) + Removal(this, EventArgs.Empty); + return; + } + if (ConnectionType == ConnectionType.BT && btInputReport[0] != 0x11) + { + //Received incorrect report, skip it + continue; + } + + lock (cState) + { + if (cState == null) + cState = new DS4State(); + cState.LX = inputReport[1]; + cState.LY = inputReport[2]; + cState.RX = inputReport[3]; + cState.RY = inputReport[4]; + cState.L2 = inputReport[8]; + cState.R2 = inputReport[9]; + + cState.Triangle = ((byte)inputReport[5] & (1 << 7)) != 0; + cState.Circle = ((byte)inputReport[5] & (1 << 6)) != 0; + cState.Cross = ((byte)inputReport[5] & (1 << 5)) != 0; + cState.Square = ((byte)inputReport[5] & (1 << 4)) != 0; + cState.DpadUp = ((byte)inputReport[5] & (1 << 3)) != 0; + cState.DpadDown = ((byte)inputReport[5] & (1 << 2)) != 0; + cState.DpadLeft = ((byte)inputReport[5] & (1 << 1)) != 0; + cState.DpadRight = ((byte)inputReport[5] & (1 << 0)) != 0; + + //Convert dpad into individual On/Off bits instead of a clock representation + byte dpad_state = 0; + + dpad_state = (byte)( + ((cState.DpadRight ? 1 : 0) << 0) | + ((cState.DpadLeft ? 1 : 0) << 1) | + ((cState.DpadDown ? 1 : 0) << 2) | + ((cState.DpadUp ? 1 : 0) << 3)); + + switch (dpad_state) + { + case 0: cState.DpadUp = true; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = false; break; + case 1: cState.DpadUp = true; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = true; break; + case 2: cState.DpadUp = false; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = true; break; + case 3: cState.DpadUp = false; cState.DpadDown = true; cState.DpadLeft = false; cState.DpadRight = true; break; + case 4: cState.DpadUp = false; cState.DpadDown = true; cState.DpadLeft = false; cState.DpadRight = false; break; + case 5: cState.DpadUp = false; cState.DpadDown = true; cState.DpadLeft = true; cState.DpadRight = false; break; + case 6: cState.DpadUp = false; cState.DpadDown = false; cState.DpadLeft = true; cState.DpadRight = false; break; + case 7: cState.DpadUp = true; cState.DpadDown = false; cState.DpadLeft = true; cState.DpadRight = false; break; + case 8: cState.DpadUp = false; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = false; break; + } + + cState.R3 = ((byte)inputReport[6] & (1 << 7)) != 0; + cState.L3 = ((byte)inputReport[6] & (1 << 6)) != 0; + cState.Options = ((byte)inputReport[6] & (1 << 5)) != 0; + cState.Share = ((byte)inputReport[6] & (1 << 4)) != 0; + cState.R1 = ((byte)inputReport[6] & (1 << 1)) != 0; + cState.L1 = ((byte)inputReport[6] & (1 << 0)) != 0; + + cState.PS = ((byte)inputReport[7] & (1 << 0)) != 0; + cState.TouchButton = (inputReport[7] & (1 << 2 - 1)) != 0; + + // Store Gyro and Accel values + Array.Copy(inputReport, 14, accel, 0, 6); + Array.Copy(inputReport, 20, gyro, 0, 6); + + int charge = 0; + if (conType == ConnectionType.USB) + { + charge = (inputReport[30] - 16) * 10; + if (charge > 100) + charge = 100; + } + else + { + charge = (inputReport[30] + 1) * 10; + if (charge > 100) + charge = 100; + } + + cState.Battery = charge; + battery = charge; + + cState.Touch1 = (inputReport[0 + DS4Touchpad.TOUCHPAD_DATA_OFFSET] >> 7) != 0 ? false : true; // >= 1 touch detected + cState.Touch2 = (inputReport[4 + DS4Touchpad.TOUCHPAD_DATA_OFFSET] >> 7) != 0 ? false : true; // 2 touches detected + + cState.ReportTimeStamp = DateTime.UtcNow; + } + if (ConnectionType == ConnectionType.BT && !isIdle(cState)) + { + lastActive = DateTime.Now; + } + if (ConnectionType == ConnectionType.BT && lastActive + TimeSpan.FromSeconds(idleTimeout) < DateTime.Now) + { + DisconnectBT(); + } + + touchpad.handleTouchpad(inputReport, cState); + + sendOutputReport(); + + if ((!pState.PS || !pState.Options) && cState.PS && cState.Options) + { + DisconnectBT(); + } + if (Report != null) + Report(this, EventArgs.Empty); + lock (pState) + { + if (pState == null) + pState = new DS4State(); + cState.Copy(pState); + } + } + } + + private void sendOutputReport() + { + if (isDirty) + { + if (conType == ConnectionType.BT) + { + outputReport[0] = 0x11; + outputReport[1] = 128; + outputReport[3] = 0xff; + outputReport[6] = rightLightFastRumble; //fast motor + outputReport[7] = leftHeavySlowRumble; //slow motor + outputReport[8] = LightBarColor.red; //red + outputReport[9] = LightBarColor.green; //green + outputReport[10] = LightBarColor.blue; //blue + outputReport[11] = ledFlashOn; //flash on duration + outputReport[12] = ledFlashOff; //flash off duration + + if (hDevice.WriteOutputReportViaControl(outputReport)) + isDirty = false; + } + else + { + outputReport[0] = 0x5; + outputReport[1] = 0xFF; + outputReport[4] = rightLightFastRumble; //fast motor + outputReport[5] = leftHeavySlowRumble; //slow motor + outputReport[6] = LightBarColor.red; //red + outputReport[7] = LightBarColor.green; //green + outputReport[8] = LightBarColor.blue; //blue + outputReport[9] = ledFlashOn; //flash on duration + outputReport[10] = ledFlashOff; //flash off duration + if (hDevice.WriteOutputReportViaInterrupt(outputReport)) + { + isDirty = false; + } + } + } + } + + public bool DisconnectBT() + { + if (Mac != null) + { + Console.WriteLine("Trying to disonnect BT device"); + IntPtr btHandle = IntPtr.Zero; + int IOCTL_BTH_DISCONNECT_DEVICE = 0x41000c; + + byte[] btAddr = new byte[8]; + string[] sbytes = Mac.Split(':'); + for (int i = 0; i < 6; i++) + { + //parse hex byte in reverse order + btAddr[5 - i] = Convert.ToByte(sbytes[i], 16); + } + long lbtAddr = BitConverter.ToInt64(btAddr, 0); + + + NativeMethods.BLUETOOTH_FIND_RADIO_PARAMS p = new NativeMethods.BLUETOOTH_FIND_RADIO_PARAMS(); + p.dwSize = Marshal.SizeOf(typeof(NativeMethods.BLUETOOTH_FIND_RADIO_PARAMS)); + IntPtr searchHandle = NativeMethods.BluetoothFindFirstRadio(ref p, ref btHandle); + int bytesReturned = 0; + bool success = false; + while (!success && btHandle != IntPtr.Zero) + { + success = NativeMethods.DeviceIoControl(btHandle, IOCTL_BTH_DISCONNECT_DEVICE, ref lbtAddr, 8, IntPtr.Zero, 0, ref bytesReturned, IntPtr.Zero); + NativeMethods.CloseHandle(btHandle); + if (!success) + if (!NativeMethods.BluetoothFindNextRadio(searchHandle, ref btHandle)) + btHandle = IntPtr.Zero; + + } + NativeMethods.BluetoothFindRadioClose(searchHandle); + Console.WriteLine("Disconnect successul: " + success); + if(success) + if (Removal != null) + Removal(this, EventArgs.Empty); + return success; + } + return false; + } + + public void setLightbarColor(byte red, byte green, byte blue) + { + if (red != ligtBarColor.red || green != ligtBarColor.green || blue != ligtBarColor.blue) + { + isDirty = true; + ligtBarColor.red = red; + ligtBarColor.green = green; + ligtBarColor.blue = blue; + } + } + + public void setLightbarDuration(byte onDuration, byte offDuration) + { + LightBarOffDuration = offDuration; + LightBarOnDuration = onDuration; + } + + public void setRumble(byte rightLightFastMotor, byte leftHeavySlowMotor) + { + RightLightFastRumble = rightLightFastMotor; + LeftHeavySlowRumble = leftHeavySlowMotor; + } + + public DS4State getCurrentState() + { + lock (cState) + { + return cState.Clone(); + } + } + + public DS4State getPreviousState() + { + lock (pState) + { + return pState.Clone(); + } + } + + public void getExposedState(DS4StateExposed expState, DS4State state) + { + cState.Copy(state); + expState.Accel = accel; + expState.Gyro = gyro; + } + + public void getCurrentState(DS4State state) + { + lock (cState) + { + cState.Copy(state); + } + } + + public void getPreviousState(DS4State state) + { + lock (pState) + { + pState.Copy(state); + } + } + + private bool isIdle(DS4State cState) + { + if (cState.Square || cState.Cross || cState.Circle || cState.Triangle) + return false; + if (cState.DpadUp || cState.DpadLeft || cState.DpadDown || cState.DpadRight) + return false; + if (cState.L3 || cState.R3 || cState.L1 || cState.R1 || cState.Share || cState.Options) + return false; + if (cState.L2 != 0 || cState.R2 != 0) + return false; + if (Math.Abs(cState.LX - 127) > 10 || (Math.Abs(cState.LY - 127) > 10 )) + return false; + if (Math.Abs(cState.RX - 127) > 10 || (Math.Abs(cState.RY - 127) > 10)) + return false; + if (cState.Touch1 || cState.Touch2 || cState.TouchButton) + return false; + return true; + } + + override + public String ToString() + { + return Mac; + } + } +} diff --git a/DS4Library/DS4Devices.cs b/DS4Library/DS4Devices.cs new file mode 100644 index 0000000..f5bd518 --- /dev/null +++ b/DS4Library/DS4Devices.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using HidLibrary; +namespace DS4Library +{ + public class DS4Devices + { + private static Dictionary Devices = new Dictionary(); + public static bool isExclusiveMode = false; + + //enumerates ds4 controllers in the system + public static void findControllers() + { + lock (Devices) + { + int[] pid = { 0x5C4 }; + IEnumerable hDevices = HidDevices.Enumerate(0x054C, pid); + + foreach (HidDevice hDevice in hDevices) + { + if (!hDevice.IsOpen) + hDevice.OpenDevice(isExclusiveMode); + if (hDevice.IsOpen) + { + byte[] buffer = new byte[38]; + buffer[0] = 0x2; + hDevice.readFeatureData(buffer); + if (Devices.ContainsKey(hDevice.readSerial())) + continue; + else + { + DS4Device ds4Device = new DS4Device(hDevice); + ds4Device.StartUpdate(); + ds4Device.Removal += On_Removal; + Devices.Add(ds4Device.MacAddress, ds4Device); + } + } + else + { + throw new Exception("ERROR: Can't open DS4 Controller. Try quitting other applications like Steam, Uplay, etc.)"); + } + } + + } + } + + //allows to get DS4Device by specifying unique MAC address + //format for MAC address is XX:XX:XX:XX:XX:XX + public static DS4Device getDS4Controller(string mac) + { + DS4Device device = null; + try + { + Devices.TryGetValue(mac, out device); + } + catch (ArgumentNullException) { } + return device; + } + + //returns DS4 controllers that were found and are running + public static IEnumerable getDS4Controllers() + { + return Devices.Values; + } + + public static void stopControllers() + { + IEnumerable devices = getDS4Controllers(); + foreach (DS4Device device in devices) + { + device.StopUpdate(); + device.HidDevice.CloseDevice(); + } + Devices.Clear(); + } + + //called when devices is diconnected, timed out or has input reading failure + public static void On_Removal(object sender, EventArgs e) + { + lock (Devices) + { + DS4Device device = (DS4Device)sender; + device.HidDevice.CloseDevice(); + Devices.Remove(device.MacAddress); + } + } + } +} diff --git a/DS4Library/DS4Library.csproj b/DS4Library/DS4Library.csproj new file mode 100644 index 0000000..3c6074e --- /dev/null +++ b/DS4Library/DS4Library.csproj @@ -0,0 +1,65 @@ + + + + + Debug + AnyCPU + {43E14DAD-E6E8-4B66-AC50-20F5CF9B9712} + Library + Properties + DS4Library + DS4Library + v4.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + + + + + + + + + + + + + + + + + + + + {9e8f1d50-74ea-4c60-bd5c-ab2c5b53bc66} + HidLibrary + + + + + \ No newline at end of file diff --git a/DS4Library/DS4State.cs b/DS4Library/DS4State.cs new file mode 100644 index 0000000..761ccdb --- /dev/null +++ b/DS4Library/DS4State.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace DS4Library +{ + public class DS4State + { + public bool Square, Triangle, Circle, Cross; + public bool DpadUp, DpadDown, DpadLeft, DpadRight; + public bool L1, L3, R1, R3; + public bool Share, Options, PS, Touch1, Touch2, TouchButton; + public byte LX, RX, LY, RY, L2, R2; + public int Battery; + public DateTime ReportTimeStamp; + public DS4State() + { + ReportTimeStamp = DateTime.UtcNow; + Square = Triangle = Circle = Cross = false; + DpadUp = DpadDown = DpadLeft = DpadRight = false; + L1 = L3 = R1 = R3 = false; + Share = Options = PS = Touch1 = Touch2 = TouchButton = false; + LX = RX = LY = RY = 127; + L2 = R2 = 0; + Battery = 0; + } + + public DS4State(DS4State state) + { + Square = state.Square; + Triangle = state.Triangle; + Circle = state.Circle; + Cross = state.Cross; + DpadUp = state.DpadUp; + DpadDown = state.DpadDown; + DpadLeft = state.DpadLeft; + DpadRight = state.DpadRight; + L1 = state.L1; + L2 = state.L2; + L3 = state.L3; + R1 = state.R1; + R2 = state.R2; + R3 = state.R3; + Share = state.Share; + Options = state.Options; + PS = state.PS; + Touch1 = state.Touch1; + Touch2 = state.Touch2; + TouchButton = state.TouchButton; + LX = state.LX; + RX = state.RX; + LY = state.LY; + RY = state.RY; + Battery = state.Battery; + ReportTimeStamp = state.ReportTimeStamp; + } + + public DS4State Clone() + { + return new DS4State(this); + } + + public void Copy(DS4State state) + { + state.Square = Square; + state.Triangle = Triangle; + state.Circle = Circle; + state.Cross = Cross; + state.DpadUp = DpadUp; + state.DpadDown = DpadDown; + state.DpadLeft = DpadLeft; + state.DpadRight = DpadRight; + state.L1 = L1; + state.L2 = L2; + state.L3 = L3; + state.R1 = R1; + state.R2 = R2; + state.R3 = R3; + state.Share = Share; + state.Options = Options; + state.PS = PS; + state.Touch1 = Touch1; + state.Touch2 = Touch2; + state.TouchButton = TouchButton; + state.LX = LX; + state.RX = RX; + state.LY = LY; + state.RY = RY; + state.Battery = Battery; + state.ReportTimeStamp = ReportTimeStamp; + } + + } +} diff --git a/DS4Library/DS4StateExposed.cs b/DS4Library/DS4StateExposed.cs new file mode 100644 index 0000000..5057563 --- /dev/null +++ b/DS4Library/DS4StateExposed.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace DS4Library +{ + public class DS4StateExposed + { + private DS4State _state; + private byte[] accel = new byte[] { 0, 0, 0, 0, 0, 0 }, + gyro = new byte[] { 0, 0, 0, 0, 0, 0 }; + + public DS4StateExposed() + { + _state = new DS4State(); + } + public DS4StateExposed(DS4State state) + { + _state = state; + } + + bool Square { get { return _state.Square; } } + bool Triangle { get { return _state.Triangle; } } + bool Circle { get { return _state.Circle; } } + bool Cross { get { return _state.Cross; } } + bool DpadUp { get { return _state.DpadUp; } } + bool DpadDown { get { return _state.DpadDown; } } + bool DpadLeft { get { return _state.DpadLeft; } } + bool DpadRight { get { return _state.DpadRight; } } + bool L1 { get { return _state.L1; } } + bool L3 { get { return _state.L3; } } + bool R1 { get { return _state.R1; } } + bool R3 { get { return _state.R3; } } + bool Share { get { return _state.Share; } } + bool Options { get { return _state.Options; } } + bool PS { get { return _state.PS; } } + bool Touch1 { get { return _state.Touch1; } } + bool Touch2 { get { return _state.Touch2; } } + bool TouchButton { get { return _state.TouchButton; } } + byte LX { get { return _state.LX; } } + byte RX { get { return _state.RX; } } + byte LY { get { return _state.LY; } } + byte RY { get { return _state.RY; } } + byte L2 { get { return _state.L2; } } + byte R2 { get { return _state.R2; } } + int Battery { get { return _state.Battery; } } + + /// Holds raw DS4 input data from 14 to 19 + public byte[] Accel { set { accel = value; } } + /// Holds raw DS4 input data from 20 to 25 + public byte[] Gyro { set { gyro = value; } } + + /// Pitch upward/backward + /// Add double the previous result to this delta and divide by three. + public int AccelX { get { return (UInt16)(accel[0] << 8) | accel[1]; } } + /// Yaw leftward/counter-clockwise/turn to port or larboard side + /// Add double the previous result to this delta and divide by three. + public int AccelY { get { return (UInt16)(accel[2] << 8) | accel[3]; } } + /// roll left/L side of controller down/starboard raising up + /// Add double the previous result to this delta and divide by three. + public int AccelZ { get { return (UInt16)(accel[4] << 8) | accel[5]; } } + /// R side of controller upward + /// Add double the previous result to this delta and divide by three. + public int GyroX { get { return (UInt16)(gyro[0] << 8) | gyro[1]; } } + /// touchpad and button face side of controller upward + /// Add double the previous result to this delta and divide by three. + public int GyroY { get { return (UInt16)(gyro[2] << 8) | gyro[3]; } } + /// Audio/expansion ports upward and light bar/shoulders/bumpers/USB port downward + /// Add double the previous result to this delta and divide by three. + public int GyroZ { get { return (UInt16)(gyro[4] << 8) | gyro[5]; } } + } +} diff --git a/DS4Library/DS4Touchpad.cs b/DS4Library/DS4Touchpad.cs new file mode 100644 index 0000000..e7df81d --- /dev/null +++ b/DS4Library/DS4Touchpad.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; +namespace DS4Library +{ + public class TouchpadEventArgs : EventArgs + { + public readonly Touch[] touches = null; + public readonly bool touchButtonPressed; + public readonly DateTime timeStamp; + public TouchpadEventArgs(DateTime timeStamp, bool tButtonDown, Touch t0, Touch t1 = null) + { + this.timeStamp = timeStamp; + if (t1 != null) + { + touches = new Touch[2]; + touches[0] = t0; + touches[1] = t1; + } + else if (t0 != null) + { + touches = new Touch[1]; + touches[0] = t0; + } + touchButtonPressed = tButtonDown; + } + } + + public class Touch + { + public readonly int hwX, hwY, deltaX, deltaY; + public readonly byte touchID; + public readonly Touch previousTouch; + public Touch(int X, int Y, byte tID, Touch prevTouch = null) + { + hwX = X; + hwY = Y; + touchID = tID; + previousTouch = prevTouch; + if (previousTouch != null) + { + deltaX = X - previousTouch.hwX; + deltaY = Y - previousTouch.hwY; + } + } + } + + public class DS4Touchpad + { + public event EventHandler TouchesBegan = null; + public event EventHandler TouchesMoved = null; + public event EventHandler TouchesEnded = null; + public event EventHandler TouchButtonDown = null; + public event EventHandler TouchButtonUp = null; + public readonly static int TOUCHPAD_DATA_OFFSET = 35; + internal static int lastTouchPadX, lastTouchPadY, + lastTouchPadX2, lastTouchPadY2; // tracks 0, 1 or 2 touches; we maintain touch 1 and 2 separately + internal static bool lastTouchPadIsDown; + internal static bool lastIsActive; + internal static bool lastIsActive2; + internal static byte lastTouchID, lastTouchID2; + + public void handleTouchpad(byte[] data, DS4State sensors) + { + bool touchPadIsDown = sensors.TouchButton; + byte touchID = (byte)(data[0 + TOUCHPAD_DATA_OFFSET] & 0x7F); + byte touchID2 = (byte)(data[4 + TOUCHPAD_DATA_OFFSET] & 0x7F); + int currentX = data[1 + TOUCHPAD_DATA_OFFSET] + ((data[2 + TOUCHPAD_DATA_OFFSET] & 0xF) * 255); + int currentY = ((data[2 + TOUCHPAD_DATA_OFFSET] & 0xF0) >> 4) + (data[3 + TOUCHPAD_DATA_OFFSET] * 16); + int currentX2 = data[5 + TOUCHPAD_DATA_OFFSET] + ((data[6 + TOUCHPAD_DATA_OFFSET] & 0xF) * 255); + int currentY2 = ((data[6 + TOUCHPAD_DATA_OFFSET] & 0xF0) >> 4) + (data[7 + TOUCHPAD_DATA_OFFSET] * 16); + + if (sensors.Touch1) + { + if (!lastTouchPadIsDown && touchPadIsDown && TouchButtonDown != null) + { + TouchpadEventArgs args = null; + Touch t0 = new Touch(currentX, currentY, touchID); + if (sensors.Touch2) + { + Touch t1 = new Touch(currentX2, currentY2, touchID2); + args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, t0, t1); + } + else + args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, t0); + TouchButtonDown(this, args); + } + else if (lastTouchPadIsDown && !touchPadIsDown && TouchButtonUp != null) + { + TouchpadEventArgs args = null; + Touch t0 = new Touch(currentX, currentY, touchID); + if (sensors.Touch2) + { + Touch t1 = new Touch(currentX2, currentY2, touchID2); + args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, t0, t1); + } + else + args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, t0); + TouchButtonUp(this, args); + } + + if (!lastIsActive || (sensors.Touch2 && !lastIsActive2)) + { + TouchpadEventArgs args = null; + Touch t0 = new Touch(currentX, currentY, touchID); + if (sensors.Touch2 && !lastIsActive2) + { + Touch t1 = new Touch(currentX2, currentY2, touchID2); + args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, t0, t1); + } + else + args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, t0); + if (TouchesBegan != null) + TouchesBegan(this, args); + } + else if (lastIsActive) + { + if (TouchesMoved != null) + { + TouchpadEventArgs args = null; + + Touch t0Prev = new Touch(lastTouchPadX, lastTouchPadY, lastTouchID); + Touch t0 = new Touch(currentX, currentY, touchID, t0Prev); + if (sensors.Touch1 && sensors.Touch2) + { + Touch t1Prev = new Touch(lastTouchPadX2, lastTouchPadY2, lastTouchID2); + Touch t1 = new Touch(currentX2, currentY2, touchID2, t1Prev); + args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, t0, t1); + } + else + args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, t0); + TouchesMoved(this, args); + } + } + + lastTouchPadX = currentX; + lastTouchPadY = currentY; + lastTouchPadX2 = currentX2; + lastTouchPadY2 = currentY2; + lastTouchPadIsDown = touchPadIsDown; + } + else + { + if (lastIsActive) + { + TouchpadEventArgs args = null; + Touch t0 = new Touch(currentX, currentY, touchID); + if (lastIsActive2) + { + Touch t1 = new Touch(currentX2, currentY2, touchID2); + args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, t0, t1); + } + else + args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, t0); + if (TouchesEnded != null) + TouchesEnded(this, args); + } + + if (touchPadIsDown && !lastTouchPadIsDown && TouchButtonDown != null) + { + TouchButtonDown(this, new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, null, null)); + } + else if (!touchPadIsDown && lastTouchPadIsDown && TouchButtonUp != null) + { + TouchButtonUp(this, new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, null, null)); + } + } + + lastIsActive = sensors.Touch1; + lastIsActive2 = sensors.Touch2; + lastTouchID = touchID; + lastTouchID2 = touchID2; + lastTouchPadIsDown = touchPadIsDown; + } + } +} diff --git a/DS4Library/NativeMethods.cs b/DS4Library/NativeMethods.cs new file mode 100644 index 0000000..ebbe1ae --- /dev/null +++ b/DS4Library/NativeMethods.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +namespace DS4Library +{ + internal class NativeMethods + { + [StructLayout(LayoutKind.Sequential)] + internal struct BLUETOOTH_FIND_RADIO_PARAMS + { + [MarshalAs(UnmanagedType.U4)] + public int dwSize; + } + + [DllImport("bthprops.cpl", CharSet = CharSet.Auto)] + internal extern static IntPtr BluetoothFindFirstRadio(ref BLUETOOTH_FIND_RADIO_PARAMS pbtfrp, ref IntPtr phRadio); + + [DllImport("bthprops.cpl", CharSet = CharSet.Auto)] + internal extern static bool BluetoothFindNextRadio(IntPtr hFind, ref IntPtr phRadio); + + [DllImport("bthprops.cpl", CharSet = CharSet.Auto)] + internal extern static bool BluetoothFindRadioClose(IntPtr hFind); + + [DllImport("kernel32.dll", SetLastError = true)] + internal static extern Boolean DeviceIoControl(IntPtr DeviceHandle, Int32 IoControlCode, ref long InBuffer, Int32 InBufferSize, IntPtr OutBuffer, Int32 OutBufferSize, ref Int32 BytesReturned, IntPtr Overlapped); + + [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)] + internal static extern bool CloseHandle(IntPtr hObject); + } +} diff --git a/DS4Library/Properties/AssemblyInfo.cs b/DS4Library/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..8c7e8ec --- /dev/null +++ b/DS4Library/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DS4Library")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DS4Library")] +[assembly: AssemblyCopyright("Copyright © InhexSTER 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("6205583e-ffa0-469e-8466-87eaade56f9b")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/DS4Service/DS4Service.Designer.cs b/DS4Service/DS4Service.Designer.cs new file mode 100644 index 0000000..386a0fe --- /dev/null +++ b/DS4Service/DS4Service.Designer.cs @@ -0,0 +1,41 @@ +namespace DS4Service +{ + partial class DS4Service + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (components != null) + components.Dispose(); + //CA2213 Disposable fields should be disposed + if (rootHub != null) + rootHub.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + this.ServiceName = "Service1"; + } + + #endregion + } +} diff --git a/DS4Service/DS4Service.cs b/DS4Service/DS4Service.cs new file mode 100644 index 0000000..f85a9bb --- /dev/null +++ b/DS4Service/DS4Service.cs @@ -0,0 +1,39 @@ +using System; +using System.ComponentModel; +using System.ServiceProcess; +using DS4Control; +using System.IO; +using System.Runtime.InteropServices; +using System.Reflection; +namespace DS4Service +{ + public partial class DS4Service : ServiceBase + { + private Control rootHub; + StreamWriter logWriter; + string logFile = Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName + @"\DS4Service.log"; + public DS4Service() + { + InitializeComponent(); + rootHub = new Control(); + rootHub.Debug += On_Debug; + logWriter = File.AppendText(logFile); + } + + protected override void OnStart(string[] args) + { + rootHub.Start(); + } + + protected override void OnStop() + { + rootHub.Stop(); + } + + protected void On_Debug(object sender, DebugEventArgs e) + { + logWriter.WriteLine(e.Time + ":\t" + e.Data); + logWriter.Flush(); + } + } +} diff --git a/DS4Service/DS4Service.csproj b/DS4Service/DS4Service.csproj new file mode 100644 index 0000000..fe489fa --- /dev/null +++ b/DS4Service/DS4Service.csproj @@ -0,0 +1,84 @@ + + + + + Debug + AnyCPU + {04CCD3D1-2ABC-4B5F-90D9-641D8DEC7127} + WinExe + Properties + DS4Service + DS4Service + v4.0 + 512 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + Component + + + DS4Service.cs + + + + Component + + + ProjectInstaller.cs + + + + + + {b0ad793e-baeb-435f-bb40-d647de2bc2bf} + DS4Control + + + {43e14dad-e6e8-4b66-ac50-20f5cf9b9712} + DS4Library + + + + + ProjectInstaller.cs + + + + + \ No newline at end of file diff --git a/DS4Service/Program.cs b/DS4Service/Program.cs new file mode 100644 index 0000000..d8adc96 --- /dev/null +++ b/DS4Service/Program.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.ServiceProcess; +using System.Text; + +namespace DS4Service +{ + static class Program + { + /// + /// The main entry point for the application. + /// + static void Main() + { + ServiceBase[] ServicesToRun; + ServicesToRun = new ServiceBase[] + { + new DS4Service() + }; + ServiceBase.Run(ServicesToRun); + } + } +} diff --git a/DS4Service/ProjectInstaller.cs b/DS4Service/ProjectInstaller.cs new file mode 100644 index 0000000..a1ed2eb --- /dev/null +++ b/DS4Service/ProjectInstaller.cs @@ -0,0 +1,15 @@ +using System; +using System.ComponentModel; +using System.Configuration.Install; + +namespace DS4Service +{ + [RunInstaller(true)] + public partial class ProjectInstaller : System.Configuration.Install.Installer + { + public ProjectInstaller() + { + InitializeComponent(); + } + } +} diff --git a/DS4Service/ProjectInstaller.designer.cs b/DS4Service/ProjectInstaller.designer.cs new file mode 100644 index 0000000..d7ddd71 --- /dev/null +++ b/DS4Service/ProjectInstaller.designer.cs @@ -0,0 +1,60 @@ +namespace DS4Service +{ + partial class ProjectInstaller + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.serviceProcessInstaller = new System.ServiceProcess.ServiceProcessInstaller(); + this.serviceInstaller = new System.ServiceProcess.ServiceInstaller(); + // + // serviceProcessInstaller + // + this.serviceProcessInstaller.Account = System.ServiceProcess.ServiceAccount.LocalSystem; + this.serviceProcessInstaller.Password = null; + this.serviceProcessInstaller.Username = null; + // + // serviceInstaller + // + this.serviceInstaller.DisplayName = " DS4 Tool Service"; + this.serviceInstaller.ServiceName = "DS4Service"; + this.serviceInstaller.ServicesDependedOn = new string[] { + "ScpVBus"}; + // + // ProjectInstaller + // + this.Installers.AddRange(new System.Configuration.Install.Installer[] { + this.serviceProcessInstaller, + this.serviceInstaller}); + + } + + #endregion + + private System.ServiceProcess.ServiceProcessInstaller serviceProcessInstaller; + private System.ServiceProcess.ServiceInstaller serviceInstaller; + } +} \ No newline at end of file diff --git a/DS4Service/ProjectInstaller.resx b/DS4Service/ProjectInstaller.resx new file mode 100644 index 0000000..0eb4745 --- /dev/null +++ b/DS4Service/ProjectInstaller.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 56 + + + 17, 17 + + + False + + \ No newline at end of file diff --git a/DS4Service/Properties/AssemblyInfo.cs b/DS4Service/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f39bd54 --- /dev/null +++ b/DS4Service/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DS4Service")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DS4Service")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("22c2429d-c349-4fff-9742-d5c1a822b2b6")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/DS4Tool.sln b/DS4Tool.sln new file mode 100644 index 0000000..4c1b239 --- /dev/null +++ b/DS4Tool.sln @@ -0,0 +1,68 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2013 for Windows Desktop +VisualStudioVersion = 12.0.21005.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DS4Library", "DS4Library\DS4Library.csproj", "{43E14DAD-E6E8-4B66-AC50-20F5CF9B9712}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HidLibrary", "HidLibrary\HidLibrary.csproj", "{9E8F1D50-74EA-4C60-BD5C-AB2C5B53BC66}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DS4Control", "DS4Control\DS4Control.csproj", "{B0AD793E-BAEB-435F-BB40-D647DE2BC2BF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DS4Tool", "DS4Tool\DS4Tool.csproj", "{B1081607-B630-4F57-9580-8A4897145890}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DS4Service", "DS4Service\DS4Service.csproj", "{04CCD3D1-2ABC-4B5F-90D9-641D8DEC7127}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {43E14DAD-E6E8-4B66-AC50-20F5CF9B9712}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {43E14DAD-E6E8-4B66-AC50-20F5CF9B9712}.Debug|Any CPU.Build.0 = Debug|Any CPU + {43E14DAD-E6E8-4B66-AC50-20F5CF9B9712}.Debug|x86.ActiveCfg = Debug|Any CPU + {43E14DAD-E6E8-4B66-AC50-20F5CF9B9712}.Debug|x86.Build.0 = Debug|Any CPU + {43E14DAD-E6E8-4B66-AC50-20F5CF9B9712}.Release|Any CPU.ActiveCfg = Release|Any CPU + {43E14DAD-E6E8-4B66-AC50-20F5CF9B9712}.Release|Any CPU.Build.0 = Release|Any CPU + {43E14DAD-E6E8-4B66-AC50-20F5CF9B9712}.Release|x86.ActiveCfg = Release|Any CPU + {43E14DAD-E6E8-4B66-AC50-20F5CF9B9712}.Release|x86.Build.0 = Release|Any CPU + {9E8F1D50-74EA-4C60-BD5C-AB2C5B53BC66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9E8F1D50-74EA-4C60-BD5C-AB2C5B53BC66}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9E8F1D50-74EA-4C60-BD5C-AB2C5B53BC66}.Debug|x86.ActiveCfg = Debug|Any CPU + {9E8F1D50-74EA-4C60-BD5C-AB2C5B53BC66}.Debug|x86.Build.0 = Debug|Any CPU + {9E8F1D50-74EA-4C60-BD5C-AB2C5B53BC66}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9E8F1D50-74EA-4C60-BD5C-AB2C5B53BC66}.Release|Any CPU.Build.0 = Release|Any CPU + {9E8F1D50-74EA-4C60-BD5C-AB2C5B53BC66}.Release|x86.ActiveCfg = Release|Any CPU + {9E8F1D50-74EA-4C60-BD5C-AB2C5B53BC66}.Release|x86.Build.0 = Release|Any CPU + {B0AD793E-BAEB-435F-BB40-D647DE2BC2BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B0AD793E-BAEB-435F-BB40-D647DE2BC2BF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B0AD793E-BAEB-435F-BB40-D647DE2BC2BF}.Debug|x86.ActiveCfg = Debug|Any CPU + {B0AD793E-BAEB-435F-BB40-D647DE2BC2BF}.Debug|x86.Build.0 = Debug|Any CPU + {B0AD793E-BAEB-435F-BB40-D647DE2BC2BF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B0AD793E-BAEB-435F-BB40-D647DE2BC2BF}.Release|Any CPU.Build.0 = Release|Any CPU + {B0AD793E-BAEB-435F-BB40-D647DE2BC2BF}.Release|x86.ActiveCfg = Release|Any CPU + {B0AD793E-BAEB-435F-BB40-D647DE2BC2BF}.Release|x86.Build.0 = Release|Any CPU + {B1081607-B630-4F57-9580-8A4897145890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B1081607-B630-4F57-9580-8A4897145890}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B1081607-B630-4F57-9580-8A4897145890}.Debug|x86.ActiveCfg = Debug|Any CPU + {B1081607-B630-4F57-9580-8A4897145890}.Debug|x86.Build.0 = Debug|Any CPU + {B1081607-B630-4F57-9580-8A4897145890}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B1081607-B630-4F57-9580-8A4897145890}.Release|Any CPU.Build.0 = Release|Any CPU + {B1081607-B630-4F57-9580-8A4897145890}.Release|x86.ActiveCfg = Release|Any CPU + {B1081607-B630-4F57-9580-8A4897145890}.Release|x86.Build.0 = Release|Any CPU + {04CCD3D1-2ABC-4B5F-90D9-641D8DEC7127}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {04CCD3D1-2ABC-4B5F-90D9-641D8DEC7127}.Debug|Any CPU.Build.0 = Debug|Any CPU + {04CCD3D1-2ABC-4B5F-90D9-641D8DEC7127}.Debug|x86.ActiveCfg = Debug|Any CPU + {04CCD3D1-2ABC-4B5F-90D9-641D8DEC7127}.Debug|x86.Build.0 = Debug|Any CPU + {04CCD3D1-2ABC-4B5F-90D9-641D8DEC7127}.Release|Any CPU.ActiveCfg = Release|Any CPU + {04CCD3D1-2ABC-4B5F-90D9-641D8DEC7127}.Release|Any CPU.Build.0 = Release|Any CPU + {04CCD3D1-2ABC-4B5F-90D9-641D8DEC7127}.Release|x86.ActiveCfg = Release|Any CPU + {04CCD3D1-2ABC-4B5F-90D9-641D8DEC7127}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/DS4Tool/AboutBox.Designer.cs b/DS4Tool/AboutBox.Designer.cs new file mode 100644 index 0000000..79fce19 --- /dev/null +++ b/DS4Tool/AboutBox.Designer.cs @@ -0,0 +1,97 @@ +namespace ScpServer +{ + partial class AboutBox + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.OkButton = new System.Windows.Forms.Button(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.linkLabel1 = new System.Windows.Forms.LinkLabel(); + this.SuspendLayout(); + // + // OkButton + // + this.OkButton.Location = new System.Drawing.Point(113, 202); + this.OkButton.Name = "OkButton"; + this.OkButton.Size = new System.Drawing.Size(75, 23); + this.OkButton.TabIndex = 0; + this.OkButton.Text = "Ok"; + this.OkButton.UseVisualStyleBackColor = true; + this.OkButton.Click += new System.EventHandler(this.OkButton_Click); + // + // textBox1 + // + this.textBox1.BackColor = System.Drawing.SystemColors.Control; + this.textBox1.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.textBox1.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.textBox1.Location = new System.Drawing.Point(12, 12); + this.textBox1.Multiline = true; + this.textBox1.Name = "textBox1"; + this.textBox1.ReadOnly = true; + this.textBox1.Size = new System.Drawing.Size(260, 155); + this.textBox1.TabIndex = 1; + this.textBox1.Text = "DS4 Tool 1.3 RC3\r\n\r\nCreated By:\r\nArtur Dzmitryieu(InhexSTER)\r\nelectrobrains\r\nHect" + + "icSeptic\r\nJays2Kings\r\n\r\nBased on DS3 Scp Server from\r\nScarlet.Crush"; + this.textBox1.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; + // + // linkLabel1 + // + this.linkLabel1.AutoSize = true; + this.linkLabel1.Location = new System.Drawing.Point(59, 175); + this.linkLabel1.Name = "linkLabel1"; + this.linkLabel1.Size = new System.Drawing.Size(183, 13); + this.linkLabel1.TabIndex = 2; + this.linkLabel1.TabStop = true; + this.linkLabel1.Text = "https://code.google.com/p/ds4-tool/"; + this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked); + // + // AboutBox + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(284, 230); + this.Controls.Add(this.linkLabel1); + this.Controls.Add(this.textBox1); + this.Controls.Add(this.OkButton); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "AboutBox"; + this.Text = "About"; + this.Load += new System.EventHandler(this.AboutBox_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button OkButton; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.LinkLabel linkLabel1; + } +} \ No newline at end of file diff --git a/DS4Tool/AboutBox.cs b/DS4Tool/AboutBox.cs new file mode 100644 index 0000000..dd825ec --- /dev/null +++ b/DS4Tool/AboutBox.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace ScpServer +{ + public partial class AboutBox : Form + { + public AboutBox() + { + InitializeComponent(); + } + + private void OkButton_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + System.Diagnostics.Process.Start(e.Link.LinkData.ToString()); + } + + private void AboutBox_Load(object sender, EventArgs e) + { + linkLabel1.Links.Add(0,35,"https://code.google.com/p/ds4-tool/"); + } + } +} diff --git a/DS4Tool/AboutBox.resx b/DS4Tool/AboutBox.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/DS4Tool/AboutBox.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/DS4Tool/AdvancedColorDialog.cs b/DS4Tool/AdvancedColorDialog.cs new file mode 100644 index 0000000..a1202fc --- /dev/null +++ b/DS4Tool/AdvancedColorDialog.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace ScpServer +{ + [System.ComponentModel.DesignerCategory("")] + public class AdvancedColorDialog : ColorDialog + { + #region WinAPI + internal class ApiWindow + { + public IntPtr hWnd; + public string ClassName; + public string MainWindowTitle; + } + internal class WindowsEnumerator + { + private delegate int EnumCallBackDelegate(IntPtr hwnd, int lParam); + [DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] + + private static extern int EnumWindows(EnumCallBackDelegate lpEnumFunc, int lParam); + [DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] + + private static extern int EnumChildWindows(IntPtr hWndParent, EnumCallBackDelegate lpEnumFunc, int lParam); + [DllImport("user32", EntryPoint = "GetClassNameA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] + + private static extern int GetClassName(IntPtr hwnd, System.Text.StringBuilder lpClassName, int nMaxCount); + [DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] + + private static extern int IsWindowVisible(IntPtr hwnd); + [DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] + + private static extern int GetParent(IntPtr hwnd); + [DllImport("user32", EntryPoint = "SendMessageA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] + + private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam); + [DllImport("user32", EntryPoint = "SendMessageA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] + + private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, System.Text.StringBuilder lParam); + + private List _listChildren = new List(); + + private List _listTopLevel = new List(); + private string _topLevelClass = string.Empty; + + private string _childClass = string.Empty; + public ApiWindow[] GetTopLevelWindows() + { + EnumWindows(EnumWindowProc, 0x0); + return _listTopLevel.ToArray(); + } + + public ApiWindow[] GetTopLevelWindows(string className) + { + _topLevelClass = className; + return this.GetTopLevelWindows(); + } + + public ApiWindow[] GetChildWindows(IntPtr hwnd) + { + _listChildren.Clear(); + EnumChildWindows(hwnd, EnumChildWindowProc, 0x0); + return _listChildren.ToArray(); + } + + public ApiWindow[] GetChildWindows(IntPtr hwnd, string childClass) + { + _childClass = childClass; + return this.GetChildWindows(hwnd); + } + + private Int32 EnumWindowProc(IntPtr hwnd, Int32 lParam) + { + if (GetParent(hwnd) == 0 && IsWindowVisible(hwnd) != 0) + { + ApiWindow window = GetWindowIdentification(hwnd); + if (_topLevelClass.Length == 0 || window.ClassName.ToLower() == _topLevelClass.ToLower()) + { + _listTopLevel.Add(window); + } + } + return 1; + } + + private Int32 EnumChildWindowProc(IntPtr hwnd, Int32 lParam) + { + ApiWindow window = GetWindowIdentification(hwnd); + if (_childClass.Length == 0 || window.ClassName.ToLower() == _childClass.ToLower()) + { + _listChildren.Add(window); + } + return 1; + } + + private ApiWindow GetWindowIdentification(IntPtr hwnd) + { + System.Text.StringBuilder classBuilder = new System.Text.StringBuilder(64); + GetClassName(hwnd, classBuilder, 64); + + ApiWindow window = new ApiWindow(); + window.ClassName = classBuilder.ToString(); + window.MainWindowTitle = WindowText(hwnd); + window.hWnd = hwnd; + return window; + } + + public static string WindowText(IntPtr hwnd) + { + const int W_GETTEXT = 0xd; + const int W_GETTEXTLENGTH = 0xe; + + System.Text.StringBuilder SB = new System.Text.StringBuilder(); + int length = SendMessage(hwnd, W_GETTEXTLENGTH, 0, 0); + if (length > 0) + { + SB = new System.Text.StringBuilder(length + 1); + SendMessage(hwnd, W_GETTEXT, SB.Capacity, SB); + } + return SB.ToString(); + } + + } + #endregion + private const int GA_ROOT = 2; + private const int WM_CTLCOLOREDIT = 0x133; + private const int WM_LBUTTONDOWN = 0x0201; + private const int WM_INITDIALOG = 0x0110; + + private List EditWindows = null; + public delegate void ColorUpdateHandler(object sender, EventArgs e); + public event ColorUpdateHandler OnUpdateColor; + + [DllImport("user32.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] + public static extern IntPtr GetAncestor(IntPtr hWnd, int gaFlags); + + // Overrides the base class hook procedure... + //[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")] + protected override IntPtr HookProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam) + { + if (msg == WM_INITDIALOG) + { + IntPtr mainWindow = GetAncestor(hWnd, GA_ROOT); + if (!mainWindow.Equals(IntPtr.Zero)) + EditWindows = new List((new WindowsEnumerator()).GetChildWindows(mainWindow, "Edit")); + } + else if (msg == WM_CTLCOLOREDIT) + { + if ((EditWindows == null)) + { + IntPtr mainWindow = GetAncestor(hWnd, GA_ROOT); + if (!mainWindow.Equals(IntPtr.Zero)) + EditWindows = new List((new WindowsEnumerator()).GetChildWindows(mainWindow, "Edit")); + } + if ((EditWindows != null) && EditWindows.Count == 6) + { + byte red = 0, green = 0, blue = 0; + if (Byte.TryParse(WindowsEnumerator.WindowText(EditWindows[3].hWnd), out red)) + if (Byte.TryParse(WindowsEnumerator.WindowText(EditWindows[4].hWnd), out green)) + if (Byte.TryParse(WindowsEnumerator.WindowText(EditWindows[5].hWnd), out blue)) + OnUpdateColor(Color.FromArgb(red, green, blue), EventArgs.Empty); + } + } + // Always call the base class hook procedure. + return base.HookProc(hWnd, msg, wParam, lParam); + } + } +} diff --git a/DS4Tool/AdvancedComboBox.cs b/DS4Tool/AdvancedComboBox.cs new file mode 100644 index 0000000..1731713 --- /dev/null +++ b/DS4Tool/AdvancedComboBox.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace ScpServer +{ + [System.ComponentModel.DesignerCategory("")] + public class AdvancedComboBox : ComboBox + { + public Label Label { get; set; } + + public AdvancedComboBox() + { + base.Visible = false; + Label = new Label(); + Label.Tag = this; + Label.ForeColor = Color.Blue; + Label.TextAlign = ContentAlignment.MiddleCenter; + Label.BackColor = Color.Transparent; + Label.MouseDown += Label_MouseDown; + } + + public Color Color + { + get + { + return Label.ForeColor; + } + set + { + Label.ForeColor = value; + } + } + + public new bool Visible + { + get + { + return Label.Visible; + } + set + { + Label.Visible = value; + } + } + + private void Label_MouseDown(object sender, MouseEventArgs e) + { + if (e.Button == System.Windows.Forms.MouseButtons.Left) + DroppedDown = true; + } + + protected override void OnParentChanged(EventArgs e) + { + base.OnParentChanged(e); + + if (Parent != null) + { + Label.Location = this.Location; + Label.Size = this.Size; + Label.Dock = this.Dock; + Label.Anchor = this.Anchor; + Label.Enabled = this.Enabled; + Label.Visible = this.Visible; + Label.RightToLeft = this.RightToLeft; + Label.Font = this.Font; + Label.Text = this.Text + .Replace("Right Click", "Right-Click") + .Replace(" Button", string.Empty) + .Replace("Left ", string.Empty) + .Replace("Right ", string.Empty); + Label.TabStop = this.TabStop; + Label.TabIndex = this.TabIndex; + } + Label.Parent = this.Parent; + } + + protected override void OnSelectedIndexChanged(EventArgs e) + { + base.OnSelectedIndexChanged(e); + + Label.Text = this.Text + .Replace("Right Click", "Right-Click") + .Replace(" Button", string.Empty) + .Replace("Left ", string.Empty) + .Replace("Right ", string.Empty); + } + + } +} diff --git a/DS4Tool/CustomMapping.Designer.cs b/DS4Tool/CustomMapping.Designer.cs new file mode 100644 index 0000000..7ef941d --- /dev/null +++ b/DS4Tool/CustomMapping.Designer.cs @@ -0,0 +1,732 @@ +namespace ScpServer +{ + partial class CustomMapping + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.pictureBox = new System.Windows.Forms.PictureBox(); + this.btnLoad = new System.Windows.Forms.Button(); + this.btnSave = new System.Windows.Forms.Button(); + this.cbRepeat = new System.Windows.Forms.CheckBox(); + this.cbScanCode = new System.Windows.Forms.CheckBox(); + this.bnCross = new System.Windows.Forms.Button(); + this.bnCircle = new System.Windows.Forms.Button(); + this.bnSquare = new System.Windows.Forms.Button(); + this.bnTriangle = new System.Windows.Forms.Button(); + this.bnR1 = new System.Windows.Forms.Button(); + this.bnR2 = new System.Windows.Forms.Button(); + this.bnL1 = new System.Windows.Forms.Button(); + this.bnL2 = new System.Windows.Forms.Button(); + this.bnUp = new System.Windows.Forms.Button(); + this.bnDown = new System.Windows.Forms.Button(); + this.bnRight = new System.Windows.Forms.Button(); + this.bnLeft = new System.Windows.Forms.Button(); + this.bnOptions = new System.Windows.Forms.Button(); + this.bnShare = new System.Windows.Forms.Button(); + this.bnTouchpad = new System.Windows.Forms.Button(); + this.bnPS = new System.Windows.Forms.Button(); + this.bnTouchUpper = new System.Windows.Forms.Button(); + this.bnTouchMulti = new System.Windows.Forms.Button(); + this.bnLY = new System.Windows.Forms.Button(); + this.lbControls = new System.Windows.Forms.ListBox(); + this.bnLY2 = new System.Windows.Forms.Button(); + this.bnRY = new System.Windows.Forms.Button(); + this.bnRY2 = new System.Windows.Forms.Button(); + this.bnLX = new System.Windows.Forms.Button(); + this.bnLX2 = new System.Windows.Forms.Button(); + this.bnRX = new System.Windows.Forms.Button(); + this.bnRX2 = new System.Windows.Forms.Button(); + this.bnL3 = new System.Windows.Forms.Button(); + this.bnR3 = new System.Windows.Forms.Button(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox)).BeginInit(); + this.SuspendLayout(); + // + // pictureBox + // + this.pictureBox.Anchor = System.Windows.Forms.AnchorStyles.None; + this.pictureBox.Enabled = false; + this.pictureBox.Image = global::ScpServer.Properties.Resources._1; + this.pictureBox.Location = new System.Drawing.Point(16, 67); + this.pictureBox.Name = "pictureBox"; + this.pictureBox.Size = new System.Drawing.Size(396, 214); + this.pictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.pictureBox.TabIndex = 0; + this.pictureBox.TabStop = false; + // + // btnLoad + // + this.btnLoad.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnLoad.Location = new System.Drawing.Point(530, 12); + this.btnLoad.Name = "btnLoad"; + this.btnLoad.Size = new System.Drawing.Size(65, 21); + this.btnLoad.TabIndex = 24; + this.btnLoad.Text = "Load"; + this.btnLoad.UseVisualStyleBackColor = true; + this.btnLoad.Click += new System.EventHandler(this.btnLoad_Click); + // + // btnSave + // + this.btnSave.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnSave.Location = new System.Drawing.Point(601, 12); + this.btnSave.Name = "btnSave"; + this.btnSave.Size = new System.Drawing.Size(65, 21); + this.btnSave.TabIndex = 25; + this.btnSave.Text = "Save"; + this.btnSave.UseVisualStyleBackColor = true; + this.btnSave.Click += new System.EventHandler(this.btnSave_Click); + // + // cbRepeat + // + this.cbRepeat.Anchor = System.Windows.Forms.AnchorStyles.Top; + this.cbRepeat.AutoSize = true; + this.cbRepeat.ForeColor = System.Drawing.SystemColors.ControlText; + this.cbRepeat.Location = new System.Drawing.Point(19, 12); + this.cbRepeat.Name = "cbRepeat"; + this.cbRepeat.Size = new System.Drawing.Size(61, 17); + this.cbRepeat.TabIndex = 26; + this.cbRepeat.Text = "Repeat"; + this.cbRepeat.UseVisualStyleBackColor = true; + this.cbRepeat.CheckedChanged += new System.EventHandler(this.cbRepeat_CheckedChanged); + // + // cbScanCode + // + this.cbScanCode.Anchor = System.Windows.Forms.AnchorStyles.Top; + this.cbScanCode.AutoSize = true; + this.cbScanCode.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.cbScanCode.Location = new System.Drawing.Point(103, 12); + this.cbScanCode.Name = "cbScanCode"; + this.cbScanCode.Size = new System.Drawing.Size(79, 17); + this.cbScanCode.TabIndex = 50; + this.cbScanCode.Text = "Scan Code"; + this.cbScanCode.UseVisualStyleBackColor = true; + this.cbScanCode.CheckedChanged += new System.EventHandler(this.cbScanCode_CheckedChanged); + // + // bnCross + // + this.bnCross.BackColor = System.Drawing.Color.Transparent; + this.bnCross.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnCross.Cursor = System.Windows.Forms.Cursors.Default; + this.bnCross.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnCross.FlatAppearance.BorderSize = 0; + this.bnCross.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnCross.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnCross.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnCross.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnCross.Location = new System.Drawing.Point(323, 190); + this.bnCross.Name = "bnCross"; + this.bnCross.Size = new System.Drawing.Size(23, 23); + this.bnCross.TabIndex = 53; + this.bnCross.Text = "A Button"; + this.bnCross.UseVisualStyleBackColor = false; + // + // bnCircle + // + this.bnCircle.BackColor = System.Drawing.Color.Transparent; + this.bnCircle.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnCircle.Cursor = System.Windows.Forms.Cursors.Default; + this.bnCircle.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnCircle.FlatAppearance.BorderSize = 0; + this.bnCircle.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnCircle.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnCircle.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnCircle.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnCircle.Location = new System.Drawing.Point(350, 166); + this.bnCircle.Name = "bnCircle"; + this.bnCircle.Size = new System.Drawing.Size(23, 23); + this.bnCircle.TabIndex = 53; + this.bnCircle.Text = "B Button"; + this.bnCircle.UseVisualStyleBackColor = false; + // + // bnSquare + // + this.bnSquare.BackColor = System.Drawing.Color.Transparent; + this.bnSquare.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnSquare.Cursor = System.Windows.Forms.Cursors.Default; + this.bnSquare.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnSquare.FlatAppearance.BorderSize = 0; + this.bnSquare.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnSquare.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnSquare.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnSquare.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnSquare.Location = new System.Drawing.Point(294, 166); + this.bnSquare.Name = "bnSquare"; + this.bnSquare.Size = new System.Drawing.Size(23, 23); + this.bnSquare.TabIndex = 53; + this.bnSquare.Text = "X Button"; + this.bnSquare.UseVisualStyleBackColor = false; + // + // bnTriangle + // + this.bnTriangle.BackColor = System.Drawing.Color.Transparent; + this.bnTriangle.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnTriangle.Cursor = System.Windows.Forms.Cursors.Default; + this.bnTriangle.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnTriangle.FlatAppearance.BorderSize = 0; + this.bnTriangle.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnTriangle.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnTriangle.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnTriangle.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnTriangle.Location = new System.Drawing.Point(322, 140); + this.bnTriangle.Name = "bnTriangle"; + this.bnTriangle.Size = new System.Drawing.Size(23, 23); + this.bnTriangle.TabIndex = 53; + this.bnTriangle.Text = "Y Button"; + this.bnTriangle.UseVisualStyleBackColor = false; + // + // bnR1 + // + this.bnR1.BackColor = System.Drawing.Color.Transparent; + this.bnR1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnR1.Cursor = System.Windows.Forms.Cursors.Default; + this.bnR1.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnR1.FlatAppearance.BorderSize = 0; + this.bnR1.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnR1.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnR1.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnR1.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnR1.Location = new System.Drawing.Point(310, 90); + this.bnR1.Name = "bnR1"; + this.bnR1.Size = new System.Drawing.Size(43, 15); + this.bnR1.TabIndex = 53; + this.bnR1.Text = "Right Bumper"; + this.bnR1.UseVisualStyleBackColor = false; + // + // bnR2 + // + this.bnR2.BackColor = System.Drawing.Color.Transparent; + this.bnR2.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnR2.Cursor = System.Windows.Forms.Cursors.Default; + this.bnR2.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnR2.FlatAppearance.BorderSize = 0; + this.bnR2.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnR2.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnR2.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnR2.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnR2.Location = new System.Drawing.Point(309, 65); + this.bnR2.Name = "bnR2"; + this.bnR2.Size = new System.Drawing.Size(43, 20); + this.bnR2.TabIndex = 53; + this.bnR2.Text = "Right Trigger"; + this.bnR2.UseVisualStyleBackColor = false; + // + // bnL1 + // + this.bnL1.BackColor = System.Drawing.Color.Transparent; + this.bnL1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnL1.Cursor = System.Windows.Forms.Cursors.Default; + this.bnL1.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnL1.FlatAppearance.BorderSize = 0; + this.bnL1.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnL1.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnL1.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnL1.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnL1.Location = new System.Drawing.Point(73, 88); + this.bnL1.Name = "bnL1"; + this.bnL1.Size = new System.Drawing.Size(43, 15); + this.bnL1.TabIndex = 53; + this.bnL1.Text = "Left Bumper"; + this.bnL1.UseVisualStyleBackColor = false; + // + // bnL2 + // + this.bnL2.BackColor = System.Drawing.Color.Transparent; + this.bnL2.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnL2.Cursor = System.Windows.Forms.Cursors.Default; + this.bnL2.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnL2.FlatAppearance.BorderSize = 0; + this.bnL2.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnL2.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnL2.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnL2.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnL2.Location = new System.Drawing.Point(76, 66); + this.bnL2.Name = "bnL2"; + this.bnL2.Size = new System.Drawing.Size(43, 20); + this.bnL2.TabIndex = 53; + this.bnL2.Text = "Left Trigger"; + this.bnL2.UseVisualStyleBackColor = false; + // + // bnUp + // + this.bnUp.BackColor = System.Drawing.Color.Transparent; + this.bnUp.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnUp.Cursor = System.Windows.Forms.Cursors.Default; + this.bnUp.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnUp.FlatAppearance.BorderSize = 0; + this.bnUp.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnUp.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnUp.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnUp.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnUp.Location = new System.Drawing.Point(84, 142); + this.bnUp.Name = "bnUp"; + this.bnUp.Size = new System.Drawing.Size(19, 22); + this.bnUp.TabIndex = 53; + this.bnUp.Text = "Up Button"; + this.bnUp.UseVisualStyleBackColor = false; + // + // bnDown + // + this.bnDown.BackColor = System.Drawing.Color.Transparent; + this.bnDown.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnDown.Cursor = System.Windows.Forms.Cursors.Default; + this.bnDown.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnDown.FlatAppearance.BorderSize = 0; + this.bnDown.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnDown.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnDown.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnDown.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnDown.Location = new System.Drawing.Point(85, 184); + this.bnDown.Name = "bnDown"; + this.bnDown.Size = new System.Drawing.Size(19, 22); + this.bnDown.TabIndex = 53; + this.bnDown.Text = "Down Button"; + this.bnDown.UseVisualStyleBackColor = false; + // + // bnRight + // + this.bnRight.BackColor = System.Drawing.Color.Transparent; + this.bnRight.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnRight.Cursor = System.Windows.Forms.Cursors.Default; + this.bnRight.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnRight.FlatAppearance.BorderSize = 0; + this.bnRight.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnRight.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnRight.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnRight.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnRight.Location = new System.Drawing.Point(106, 164); + this.bnRight.Name = "bnRight"; + this.bnRight.Size = new System.Drawing.Size(21, 18); + this.bnRight.TabIndex = 53; + this.bnRight.Text = "Right Button"; + this.bnRight.UseVisualStyleBackColor = false; + // + // bnLeft + // + this.bnLeft.BackColor = System.Drawing.Color.Transparent; + this.bnLeft.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnLeft.Cursor = System.Windows.Forms.Cursors.Default; + this.bnLeft.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnLeft.FlatAppearance.BorderSize = 0; + this.bnLeft.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnLeft.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnLeft.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnLeft.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnLeft.Location = new System.Drawing.Point(57, 163); + this.bnLeft.Name = "bnLeft"; + this.bnLeft.Size = new System.Drawing.Size(26, 20); + this.bnLeft.TabIndex = 53; + this.bnLeft.Text = "Left Button"; + this.bnLeft.UseVisualStyleBackColor = false; + // + // bnOptions + // + this.bnOptions.BackColor = System.Drawing.Color.Transparent; + this.bnOptions.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnOptions.Cursor = System.Windows.Forms.Cursors.Default; + this.bnOptions.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnOptions.FlatAppearance.BorderSize = 0; + this.bnOptions.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnOptions.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnOptions.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnOptions.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnOptions.Location = new System.Drawing.Point(283, 125); + this.bnOptions.Name = "bnOptions"; + this.bnOptions.Size = new System.Drawing.Size(13, 22); + this.bnOptions.TabIndex = 53; + this.bnOptions.Text = "Start"; + this.bnOptions.UseVisualStyleBackColor = false; + // + // bnShare + // + this.bnShare.BackColor = System.Drawing.Color.Transparent; + this.bnShare.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnShare.Cursor = System.Windows.Forms.Cursors.Default; + this.bnShare.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnShare.FlatAppearance.BorderSize = 0; + this.bnShare.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnShare.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnShare.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnShare.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnShare.Location = new System.Drawing.Point(131, 127); + this.bnShare.Name = "bnShare"; + this.bnShare.Size = new System.Drawing.Size(12, 23); + this.bnShare.TabIndex = 53; + this.bnShare.Text = "Back"; + this.bnShare.UseVisualStyleBackColor = false; + // + // bnTouchpad + // + this.bnTouchpad.BackColor = System.Drawing.Color.Transparent; + this.bnTouchpad.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnTouchpad.Cursor = System.Windows.Forms.Cursors.Default; + this.bnTouchpad.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnTouchpad.FlatAppearance.BorderSize = 0; + this.bnTouchpad.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnTouchpad.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnTouchpad.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnTouchpad.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnTouchpad.Location = new System.Drawing.Point(151, 131); + this.bnTouchpad.Name = "bnTouchpad"; + this.bnTouchpad.Size = new System.Drawing.Size(64, 56); + this.bnTouchpad.TabIndex = 53; + this.bnTouchpad.Text = "Click"; + this.bnTouchpad.UseVisualStyleBackColor = false; + // + // bnPS + // + this.bnPS.BackColor = System.Drawing.Color.Transparent; + this.bnPS.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnPS.Cursor = System.Windows.Forms.Cursors.Default; + this.bnPS.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnPS.FlatAppearance.BorderSize = 0; + this.bnPS.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnPS.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnPS.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnPS.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnPS.Location = new System.Drawing.Point(205, 208); + this.bnPS.Name = "bnPS"; + this.bnPS.Size = new System.Drawing.Size(18, 18); + this.bnPS.TabIndex = 53; + this.bnPS.Text = "Guide"; + this.bnPS.UseVisualStyleBackColor = false; + // + // bnTouchUpper + // + this.bnTouchUpper.BackColor = System.Drawing.Color.Transparent; + this.bnTouchUpper.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnTouchUpper.Cursor = System.Windows.Forms.Cursors.Default; + this.bnTouchUpper.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnTouchUpper.FlatAppearance.BorderSize = 0; + this.bnTouchUpper.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnTouchUpper.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnTouchUpper.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnTouchUpper.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnTouchUpper.Location = new System.Drawing.Point(150, 104); + this.bnTouchUpper.Name = "bnTouchUpper"; + this.bnTouchUpper.Size = new System.Drawing.Size(125, 26); + this.bnTouchUpper.TabIndex = 53; + this.bnTouchUpper.Text = "Middle Click"; + this.bnTouchUpper.UseVisualStyleBackColor = false; + // + // bnTouchMulti + // + this.bnTouchMulti.BackColor = System.Drawing.Color.Transparent; + this.bnTouchMulti.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnTouchMulti.Cursor = System.Windows.Forms.Cursors.Default; + this.bnTouchMulti.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnTouchMulti.FlatAppearance.BorderSize = 0; + this.bnTouchMulti.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnTouchMulti.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnTouchMulti.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnTouchMulti.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnTouchMulti.Location = new System.Drawing.Point(215, 131); + this.bnTouchMulti.Name = "bnTouchMulti"; + this.bnTouchMulti.Size = new System.Drawing.Size(64, 56); + this.bnTouchMulti.TabIndex = 53; + this.bnTouchMulti.Text = "Right Click"; + this.bnTouchMulti.UseVisualStyleBackColor = false; + // + // bnLY + // + this.bnLY.BackColor = System.Drawing.Color.Transparent; + this.bnLY.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnLY.Cursor = System.Windows.Forms.Cursors.Default; + this.bnLY.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnLY.FlatAppearance.BorderSize = 0; + this.bnLY.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnLY.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnLY.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnLY.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnLY.Location = new System.Drawing.Point(144, 213); + this.bnLY.Name = "bnLY"; + this.bnLY.Size = new System.Drawing.Size(21, 10); + this.bnLY.TabIndex = 53; + this.bnLY.Text = "Left Y-Axis-"; + this.bnLY.UseVisualStyleBackColor = false; + // + // lbControls + // + this.lbControls.FormattingEnabled = true; + this.lbControls.Items.AddRange(new object[] { + ""}); + this.lbControls.Location = new System.Drawing.Point(418, 67); + this.lbControls.Name = "lbControls"; + this.lbControls.Size = new System.Drawing.Size(248, 212); + this.lbControls.TabIndex = 54; + this.lbControls.SelectedIndexChanged += new System.EventHandler(this.listBox1_SelectedIndexChanged); + // + // bnLY2 + // + this.bnLY2.BackColor = System.Drawing.Color.Transparent; + this.bnLY2.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnLY2.Cursor = System.Windows.Forms.Cursors.Default; + this.bnLY2.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnLY2.FlatAppearance.BorderSize = 0; + this.bnLY2.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnLY2.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnLY2.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnLY2.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnLY2.Location = new System.Drawing.Point(144, 241); + this.bnLY2.Name = "bnLY2"; + this.bnLY2.Size = new System.Drawing.Size(21, 10); + this.bnLY2.TabIndex = 53; + this.bnLY2.Text = "Left Y-Axis+"; + this.bnLY2.UseVisualStyleBackColor = false; + // + // bnRY + // + this.bnRY.BackColor = System.Drawing.Color.Transparent; + this.bnRY.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnRY.Cursor = System.Windows.Forms.Cursors.Default; + this.bnRY.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnRY.FlatAppearance.BorderSize = 0; + this.bnRY.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnRY.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnRY.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnRY.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnRY.Location = new System.Drawing.Point(265, 213); + this.bnRY.Name = "bnRY"; + this.bnRY.Size = new System.Drawing.Size(21, 10); + this.bnRY.TabIndex = 53; + this.bnRY.Text = "Right Y-Axis-"; + this.bnRY.UseVisualStyleBackColor = false; + // + // bnRY2 + // + this.bnRY2.BackColor = System.Drawing.Color.Transparent; + this.bnRY2.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnRY2.Cursor = System.Windows.Forms.Cursors.Default; + this.bnRY2.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnRY2.FlatAppearance.BorderSize = 0; + this.bnRY2.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnRY2.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnRY2.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnRY2.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnRY2.Location = new System.Drawing.Point(265, 241); + this.bnRY2.Name = "bnRY2"; + this.bnRY2.Size = new System.Drawing.Size(21, 10); + this.bnRY2.TabIndex = 53; + this.bnRY2.Text = "Right Y-Axis+"; + this.bnRY2.UseVisualStyleBackColor = false; + // + // bnLX + // + this.bnLX.BackColor = System.Drawing.Color.Transparent; + this.bnLX.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnLX.Cursor = System.Windows.Forms.Cursors.Default; + this.bnLX.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnLX.FlatAppearance.BorderSize = 0; + this.bnLX.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnLX.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnLX.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnLX.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnLX.Location = new System.Drawing.Point(131, 222); + this.bnLX.Name = "bnLX"; + this.bnLX.Size = new System.Drawing.Size(10, 20); + this.bnLX.TabIndex = 53; + this.bnLX.Text = "Left X-Axis-"; + this.bnLX.UseVisualStyleBackColor = false; + // + // bnLX2 + // + this.bnLX2.BackColor = System.Drawing.Color.Transparent; + this.bnLX2.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnLX2.Cursor = System.Windows.Forms.Cursors.Default; + this.bnLX2.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnLX2.FlatAppearance.BorderSize = 0; + this.bnLX2.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnLX2.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnLX2.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnLX2.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnLX2.Location = new System.Drawing.Point(167, 222); + this.bnLX2.Name = "bnLX2"; + this.bnLX2.Size = new System.Drawing.Size(10, 20); + this.bnLX2.TabIndex = 53; + this.bnLX2.Text = "Left X-Axis+"; + this.bnLX2.UseVisualStyleBackColor = false; + // + // bnRX + // + this.bnRX.BackColor = System.Drawing.Color.Transparent; + this.bnRX.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnRX.Cursor = System.Windows.Forms.Cursors.Default; + this.bnRX.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnRX.FlatAppearance.BorderSize = 0; + this.bnRX.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnRX.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnRX.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnRX.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnRX.Location = new System.Drawing.Point(253, 222); + this.bnRX.Name = "bnRX"; + this.bnRX.Size = new System.Drawing.Size(10, 20); + this.bnRX.TabIndex = 53; + this.bnRX.Text = "Right X-Axis-"; + this.bnRX.UseVisualStyleBackColor = false; + // + // bnRX2 + // + this.bnRX2.BackColor = System.Drawing.Color.Transparent; + this.bnRX2.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnRX2.Cursor = System.Windows.Forms.Cursors.Default; + this.bnRX2.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnRX2.FlatAppearance.BorderSize = 0; + this.bnRX2.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnRX2.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnRX2.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnRX2.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnRX2.Location = new System.Drawing.Point(289, 222); + this.bnRX2.Name = "bnRX2"; + this.bnRX2.Size = new System.Drawing.Size(10, 20); + this.bnRX2.TabIndex = 53; + this.bnRX2.Text = "Right X-Axis+"; + this.bnRX2.UseVisualStyleBackColor = false; + // + // bnL3 + // + this.bnL3.BackColor = System.Drawing.Color.Transparent; + this.bnL3.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnL3.Cursor = System.Windows.Forms.Cursors.Default; + this.bnL3.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnL3.FlatAppearance.BorderSize = 0; + this.bnL3.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnL3.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnL3.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnL3.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnL3.Location = new System.Drawing.Point(147, 223); + this.bnL3.Name = "bnL3"; + this.bnL3.Size = new System.Drawing.Size(16, 17); + this.bnL3.TabIndex = 53; + this.bnL3.Text = "Left Stick"; + this.bnL3.UseVisualStyleBackColor = false; + // + // bnR3 + // + this.bnR3.BackColor = System.Drawing.Color.Transparent; + this.bnR3.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.bnR3.Cursor = System.Windows.Forms.Cursors.Default; + this.bnR3.FlatAppearance.BorderColor = System.Drawing.Color.Red; + this.bnR3.FlatAppearance.BorderSize = 0; + this.bnR3.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.Control; + this.bnR3.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control; + this.bnR3.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.bnR3.ForeColor = System.Drawing.SystemColors.WindowText; + this.bnR3.Location = new System.Drawing.Point(267, 224); + this.bnR3.Name = "bnR3"; + this.bnR3.Size = new System.Drawing.Size(16, 17); + this.bnR3.TabIndex = 53; + this.bnR3.Text = "Right Stick"; + this.bnR3.UseVisualStyleBackColor = false; + // + // CustomMapping + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(244)))), ((int)(((byte)(244)))), ((int)(((byte)(244))))); + this.ClientSize = new System.Drawing.Size(684, 310); + this.Controls.Add(this.pictureBox); + this.Controls.Add(this.lbControls); + this.Controls.Add(this.cbScanCode); + this.Controls.Add(this.cbRepeat); + this.Controls.Add(this.btnSave); + this.Controls.Add(this.btnLoad); + this.Controls.Add(this.bnL2); + this.Controls.Add(this.bnR2); + this.Controls.Add(this.bnL1); + this.Controls.Add(this.bnR1); + this.Controls.Add(this.bnLeft); + this.Controls.Add(this.bnRY2); + this.Controls.Add(this.bnRY); + this.Controls.Add(this.bnLY2); + this.Controls.Add(this.bnRX2); + this.Controls.Add(this.bnLX2); + this.Controls.Add(this.bnRX); + this.Controls.Add(this.bnLX); + this.Controls.Add(this.bnLY); + this.Controls.Add(this.bnRight); + this.Controls.Add(this.bnDown); + this.Controls.Add(this.bnR3); + this.Controls.Add(this.bnL3); + this.Controls.Add(this.bnPS); + this.Controls.Add(this.bnShare); + this.Controls.Add(this.bnTouchUpper); + this.Controls.Add(this.bnTouchMulti); + this.Controls.Add(this.bnTouchpad); + this.Controls.Add(this.bnOptions); + this.Controls.Add(this.bnUp); + this.Controls.Add(this.bnTriangle); + this.Controls.Add(this.bnSquare); + this.Controls.Add(this.bnCircle); + this.Controls.Add(this.bnCross); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.MaximumSize = new System.Drawing.Size(700, 349); + this.MinimumSize = new System.Drawing.Size(700, 349); + this.Name = "CustomMapping"; + this.Text = "Custom Mapping"; + ((System.ComponentModel.ISupportInitialize)(this.pictureBox)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.PictureBox pictureBox; + private System.Windows.Forms.CheckBox cbRepeat; + private System.Windows.Forms.Button btnLoad; + private System.Windows.Forms.Button btnSave; + private System.Windows.Forms.CheckBox cbScanCode; + private System.Windows.Forms.Button bnCross; + private System.Windows.Forms.Button bnCircle; + private System.Windows.Forms.Button bnSquare; + private System.Windows.Forms.Button bnTriangle; + private System.Windows.Forms.Button bnR1; + private System.Windows.Forms.Button bnR2; + private System.Windows.Forms.Button bnL1; + private System.Windows.Forms.Button bnL2; + private System.Windows.Forms.Button bnUp; + private System.Windows.Forms.Button bnDown; + private System.Windows.Forms.Button bnRight; + private System.Windows.Forms.Button bnLeft; + private System.Windows.Forms.Button bnOptions; + private System.Windows.Forms.Button bnShare; + private System.Windows.Forms.Button bnTouchpad; + private System.Windows.Forms.Button bnPS; + private System.Windows.Forms.Button bnTouchUpper; + private System.Windows.Forms.Button bnTouchMulti; + private System.Windows.Forms.Button bnLY; + private System.Windows.Forms.ListBox lbControls; + private System.Windows.Forms.Button bnLY2; + private System.Windows.Forms.Button bnRY; + private System.Windows.Forms.Button bnRY2; + private System.Windows.Forms.Button bnLX; + private System.Windows.Forms.Button bnLX2; + private System.Windows.Forms.Button bnRX; + private System.Windows.Forms.Button bnRX2; + private System.Windows.Forms.Button bnL3; + private System.Windows.Forms.Button bnR3; + } +} \ No newline at end of file diff --git a/DS4Tool/CustomMapping.cs b/DS4Tool/CustomMapping.cs new file mode 100644 index 0000000..45e6493 --- /dev/null +++ b/DS4Tool/CustomMapping.cs @@ -0,0 +1,332 @@ +using DS4Control; +using DS4Library; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace ScpServer +{ + public partial class CustomMapping : Form + { + private int device; + private bool handleNextKeyPress = false; + private bool MouseMoveAdded = false; + private List comboBoxes = new List(); + private List