├── .gitattributes ├── .gitignore ├── README.md ├── XOutputPlugin.sln └── XOutputPlugin ├── DS3Device.cs ├── Globals └── GlobalIndexer.cs ├── Properties └── AssemblyInfo.cs ├── ScpDevice.cs ├── Scripts └── Halo.py ├── XOutputPlugin.cs ├── XOutputPlugin.csproj └── bin └── Release └── XOutputPlugin.dll /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | #[Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | #[Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opensdf 80 | *.sdf 81 | *.cachefile 82 | 83 | # Visual Studio profiler 84 | *.psess 85 | *.vsp 86 | *.vspx 87 | *.sap 88 | 89 | # TFS 2012 Local Workspace 90 | $tf/ 91 | 92 | # Guidance Automation Toolkit 93 | *.gpState 94 | 95 | # ReSharper is a .NET coding add-in 96 | _ReSharper*/ 97 | *.[Rr]e[Ss]harper 98 | *.DotSettings.user 99 | 100 | # JustCode is a .NET coding add-in 101 | .JustCode 102 | 103 | # TeamCity is a build add-in 104 | _TeamCity* 105 | 106 | # DotCover is a Code Coverage Tool 107 | *.dotCover 108 | 109 | # NCrunch 110 | _NCrunch_* 111 | .*crunch*.local.xml 112 | nCrunchTemp_* 113 | 114 | # MightyMoose 115 | *.mm.* 116 | AutoTest.Net/ 117 | 118 | # Web workbench (sass) 119 | .sass-cache/ 120 | 121 | # Installshield output folder 122 | [Ee]xpress/ 123 | 124 | # DocProject is a documentation generator add-in 125 | DocProject/buildhelp/ 126 | DocProject/Help/*.HxT 127 | DocProject/Help/*.HxC 128 | DocProject/Help/*.hhc 129 | DocProject/Help/*.hhk 130 | DocProject/Help/*.hhp 131 | DocProject/Help/Html2 132 | DocProject/Help/html 133 | 134 | # Click-Once directory 135 | publish/ 136 | 137 | # Publish Web Output 138 | *.[Pp]ublish.xml 139 | *.azurePubxml 140 | # TODO: Comment the next line if you want to checkin your web deploy settings 141 | # but database connection strings (with potential passwords) will be unencrypted 142 | *.pubxml 143 | *.publishproj 144 | 145 | # NuGet Packages 146 | *.nupkg 147 | # The packages folder can be ignored because of Package Restore 148 | **/packages/* 149 | # except build/, which is used as an MSBuild target. 150 | !**/packages/build/ 151 | # Uncomment if necessary however generally it will be regenerated when needed 152 | #!**/packages/repositories.config 153 | 154 | # Windows Azure Build Output 155 | csx/ 156 | *.build.csdef 157 | 158 | # Windows Azure Emulator 159 | efc/ 160 | rfc/ 161 | 162 | # Windows Store app package directory 163 | AppPackages/ 164 | 165 | # Visual Studio cache files 166 | # files ending in .cache can be ignored 167 | *.[Cc]ache 168 | # but keep track of directories ending in .cache 169 | !*.[Cc]ache/ 170 | 171 | # Others 172 | ClientBin/ 173 | [Ss]tyle[Cc]op.* 174 | ~$* 175 | *~ 176 | *.dbmdl 177 | *.dbproj.schemaview 178 | *.pfx 179 | *.publishsettings 180 | node_modules/ 181 | orleans.codegen.cs 182 | 183 | # RIA/Silverlight projects 184 | Generated_Code/ 185 | 186 | # Backup & report files from converting an old project file 187 | # to a newer Visual Studio version. Backup files are not needed, 188 | # because we have git ;-) 189 | _UpgradeReport_Files/ 190 | Backup*/ 191 | UpgradeLog*.XML 192 | UpgradeLog*.htm 193 | 194 | # SQL Server files 195 | *.mdf 196 | *.ldf 197 | 198 | # Business Intelligence projects 199 | *.rdl.data 200 | *.bim.layout 201 | *.bim_*.settings 202 | 203 | # Microsoft Fakes 204 | FakesAssemblies/ 205 | 206 | # GhostDoc plugin setting file 207 | *.GhostDoc.xml 208 | 209 | # Node.js Tools for Visual Studio 210 | .ntvs_analysis.dat 211 | 212 | # Visual Studio 6 build log 213 | *.plg 214 | 215 | # Visual Studio 6 workspace options file 216 | *.opt 217 | 218 | # Visual Studio LightSwitch build output 219 | **/*.HTMLClient/GeneratedArtifacts 220 | **/*.DesktopClient/GeneratedArtifacts 221 | **/*.DesktopClient/ModelManifest.xml 222 | **/*.Server/GeneratedArtifacts 223 | **/*.Server/ModelManifest.xml 224 | _Pvt_Extensions 225 | 226 | # Paket dependency manager 227 | .paket/paket.exe 228 | 229 | # FAKE - F# Make 230 | .fake/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #XOutputPlugin 2 | Plugin for FreePIE based off [XOutput](https://github.com/Stents-/XOutput) 3 | 4 | #How to Set Up 5 | 6 | 1. Download and install the official Xbox 360 Controller driver [here](http://www.microsoft.com/hardware/en-us/d/xbox-360-controller-for-windows) 7 | 2. Run [ScpDriver.exe](http://forums.pcsx2.net/Thread-XInput-Wrapper-for-DS3-and-Play-com-USB-Dual-DS2-Controller) 8 | 3. Click install, wait until it finishes to close it 9 | 4. Copy built [XOutputPlugin.dll](https://github.com/dschu012/XOutputPlugin/blob/master/XOutputPlugin/bin/Release/XOutputPlugin.dll?raw=true) plugin to the FreePIE plugins directory 10 | 5. Write a [script](https://github.com/dschu012/XOutputPlugin/blob/master/XOutputPlugin/Scripts/Halo.py) and run it. 11 | -------------------------------------------------------------------------------- /XOutputPlugin.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.23107.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XOutputPlugin", "XOutputPlugin\XOutputPlugin.csproj", "{BC4F5FD0-7223-424A-9DAB-CA60097163EC}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {BC4F5FD0-7223-424A-9DAB-CA60097163EC}.Debug|Any CPU.ActiveCfg = Release|Any CPU 15 | {BC4F5FD0-7223-424A-9DAB-CA60097163EC}.Debug|Any CPU.Build.0 = Release|Any CPU 16 | {BC4F5FD0-7223-424A-9DAB-CA60097163EC}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {BC4F5FD0-7223-424A-9DAB-CA60097163EC}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /XOutputPlugin/DS3Device.cs: -------------------------------------------------------------------------------- 1 | using FreePIE.Core.Contracts; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace XOutputPlugin 9 | { 10 | [GlobalEnum] 11 | public enum XOutputButton 12 | { 13 | A, B, X, Y, 14 | Up, Down, Left, Right, 15 | L3, R3, L1, R1, 16 | Guide, Start, Back 17 | } 18 | 19 | [GlobalEnum] 20 | public enum XOutputTrigger 21 | { 22 | L2, R2 23 | } 24 | 25 | [GlobalEnum] 26 | public enum XOutputAxis 27 | { 28 | LX, LY, RX, RY 29 | } 30 | 31 | class DeviceState 32 | { 33 | // 0x1 or 0x0 34 | public Boolean[] ButtonState { get; set; } 35 | public Byte[] TriggerState { get; set; } 36 | public Int16[] AxisState { get; set; } 37 | } 38 | 39 | class DS3Device : ScpDevice 40 | { 41 | public const String DS3_BUS_CLASS_GUID = "{F679F562-3164-42CE-A4DB-E7DDBE723909}"; 42 | public uint Index { get; private set; } 43 | public Boolean ResetAxisOnExecute { get; set; } 44 | private DeviceState m_state; 45 | 46 | public DS3Device(uint index) : base(DS3_BUS_CLASS_GUID) 47 | { 48 | Index = index; 49 | ResetAxisOnExecute = true; 50 | m_state = new DeviceState(); 51 | ResetState(); 52 | } 53 | 54 | private void ResetState() 55 | { 56 | m_state.ButtonState = new Boolean[Enum.GetNames(typeof(XOutputButton)).Length]; 57 | m_state.TriggerState = new Byte[Enum.GetNames(typeof(XOutputTrigger)).Length]; 58 | if(ResetAxisOnExecute) 59 | m_state.AxisState = new Int16[Enum.GetNames(typeof(XOutputAxis)).Length]; 60 | } 61 | 62 | private Int32 Scale(Int32 Value, Boolean Flip) 63 | { 64 | Value -= 0x80; 65 | 66 | if (Value == -128) Value = -127; 67 | if (Flip) Value *= -1; 68 | 69 | return (Int32)((float)Value * 258.00787401574803149606299212599f); 70 | } 71 | 72 | public override Boolean Open(int Instance = 0) 73 | { 74 | return base.Open(Instance); 75 | } 76 | 77 | public override Boolean Open(String DevicePath) 78 | { 79 | m_Path = DevicePath; 80 | m_WinUsbHandle = (IntPtr)INVALID_HANDLE_VALUE; 81 | 82 | if (GetDeviceHandle(m_Path)) 83 | { 84 | 85 | m_IsActive = true; 86 | 87 | } 88 | return true; 89 | } 90 | 91 | public Boolean Plugin() 92 | { 93 | if (IsActive) 94 | { 95 | Int32 Transfered = 0; 96 | Byte[] Buffer = new Byte[16]; 97 | 98 | Buffer[0] = 0x10; 99 | Buffer[1] = 0x00; 100 | Buffer[2] = 0x00; 101 | Buffer[3] = 0x00; 102 | 103 | Buffer[4] = (Byte)((Index >> 0) & 0xFF); 104 | Buffer[5] = (Byte)((Index >> 8) & 0xFF); 105 | Buffer[6] = (Byte)((Index >> 16) & 0xFF); 106 | Buffer[7] = (Byte)((Index >> 24) & 0xFF); 107 | 108 | return DeviceIoControl(m_FileHandle, 0x2A4000, Buffer, Buffer.Length, null, 0, ref Transfered, IntPtr.Zero); 109 | } 110 | 111 | return false; 112 | } 113 | 114 | public Boolean Unplug() 115 | { 116 | if (IsActive) 117 | { 118 | Int32 Transfered = 0; 119 | Byte[] Buffer = new Byte[16]; 120 | 121 | Buffer[0] = 0x10; 122 | Buffer[1] = 0x00; 123 | Buffer[2] = 0x00; 124 | Buffer[3] = 0x00; 125 | 126 | Buffer[4] = (Byte)((Index >> 0) & 0xFF); 127 | Buffer[5] = (Byte)((Index >> 8) & 0xFF); 128 | Buffer[6] = (Byte)((Index >> 16) & 0xFF); 129 | Buffer[7] = (Byte)((Index >> 24) & 0xFF); 130 | 131 | return DeviceIoControl(m_FileHandle, 0x2A4004, Buffer, Buffer.Length, null, 0, ref Transfered, IntPtr.Zero); 132 | } 133 | return false; 134 | } 135 | 136 | public void SetButton(XOutputButton button, Boolean pressed) 137 | { 138 | m_state.ButtonState[(int)button] = pressed; 139 | } 140 | 141 | public void SetTrigger(XOutputTrigger trigger, Int32 value) 142 | { 143 | m_state.TriggerState[(int)trigger] = Convert.ToByte(InRange(value, Byte.MinValue, Byte.MaxValue)); 144 | } 145 | 146 | public void SetAxis(XOutputAxis axis, Int32 value) 147 | { 148 | m_state.AxisState[(int)axis] = Convert.ToInt16(InRange(value, Int16.MinValue, Int16.MaxValue)); 149 | } 150 | 151 | public Boolean GetButton(XOutputButton button) 152 | { 153 | return m_state.ButtonState[(int)button]; 154 | } 155 | 156 | public Byte GetTrigger(XOutputTrigger trigger) 157 | { 158 | return m_state.TriggerState[(int)trigger]; 159 | } 160 | 161 | public Int16 GetAxis(XOutputAxis axis) 162 | { 163 | return m_state.AxisState[(int)axis] ; 164 | } 165 | 166 | public Int32 InRange(Int32 value, Int32 min, Int32 max) 167 | { 168 | value = value > max ? max : value; 169 | value = value < min ? min : value; 170 | return value; 171 | } 172 | 173 | private int IntValue(XOutputButton button) 174 | { 175 | return m_state.ButtonState[(int)button] ? 1 : 0; 176 | } 177 | 178 | private Int32 Scale(XOutputAxis trigger) 179 | { 180 | Int32 Value = m_state.AxisState[(int)trigger]; 181 | return Value; 182 | } 183 | 184 | private byte[] BuildInput() 185 | { 186 | byte[] Input = new byte[28]; 187 | Input[0] = 0x1c; 188 | Input[4] = (Byte)(Index); 189 | Input[9] = 0x14; 190 | 191 | Input[10] |= (Byte)(IntValue(XOutputButton.Up) << 0); // Up 192 | Input[10] |= (Byte)(IntValue(XOutputButton.Down) << 1); // Down 193 | Input[10] |= (Byte)(IntValue(XOutputButton.Left) << 2); // Left 194 | Input[10] |= (Byte)(IntValue(XOutputButton.Right) << 3); // Right 195 | Input[10] |= (Byte)(IntValue(XOutputButton.Start) << 4); // Start 196 | Input[10] |= (Byte)(IntValue(XOutputButton.Back) << 5); // Back 197 | Input[10] |= (Byte)(IntValue(XOutputButton.L3) << 6); // Left Thumb 198 | Input[10] |= (Byte)(IntValue(XOutputButton.R3) << 7); // Right Thumb 199 | 200 | Input[11] |= (Byte)(IntValue(XOutputButton.L1) << 0); // Left Shoulder 201 | Input[11] |= (Byte)(IntValue(XOutputButton.R1) << 1); // Right Shoulder 202 | Input[11] |= (Byte)(IntValue(XOutputButton.Guide) << 2); // Guide 203 | 204 | Input[11] |= (Byte)(IntValue(XOutputButton.Y) << 7); // Y 205 | Input[11] |= (Byte)(IntValue(XOutputButton.B) << 5); // B 206 | Input[11] |= (Byte)(IntValue(XOutputButton.A) << 4); // A 207 | Input[11] |= (Byte)(IntValue(XOutputButton.X) << 6); // X 208 | 209 | Input[12] = m_state.TriggerState[(int)XOutputTrigger.L2]; // Left Trigger 210 | Input[13] = m_state.TriggerState[(int)XOutputTrigger.R2]; // Right Trigger 211 | 212 | Int32 LX = Scale(XOutputAxis.LX); 213 | Int32 LY = Scale(XOutputAxis.LY); 214 | Int32 RX = Scale(XOutputAxis.RX); 215 | Int32 RY = Scale(XOutputAxis.RY); 216 | 217 | Input[14] = (Byte)((LX >> 0) & 0xFF); // LX 218 | Input[15] = (Byte)((LX >> 8) & 0xFF); 219 | 220 | Input[16] = (Byte)((LY >> 0) & 0xFF); // LY 221 | Input[17] = (Byte)((LY >> 8) & 0xFF); 222 | 223 | Input[18] = (Byte)((RX >> 0) & 0xFF); // RX 224 | Input[19] = (Byte)((RX >> 8) & 0xFF); 225 | 226 | Input[20] = (Byte)((RY >> 0) & 0xFF); // RY 227 | Input[21] = (Byte)((RY >> 8) & 0xFF); 228 | 229 | return Input; 230 | } 231 | 232 | public Boolean SendPressed() 233 | { 234 | if(IsActive) 235 | { 236 | Int32 Transfered = 0; 237 | byte[] Input = BuildInput(); 238 | byte[] Output = new byte[8]; 239 | bool value = DeviceIoControl(m_FileHandle, 0x2A400C, Input, Input.Length, Output, Output.Length, ref Transfered, IntPtr.Zero) && Transfered > 0; 240 | ResetState(); 241 | return value; 242 | } 243 | return false; 244 | } 245 | 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /XOutputPlugin/Globals/GlobalIndexer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace XOutputPlugin.Globals 8 | { 9 | public class GlobalIndexer : GlobalIndexer 10 | { 11 | public GlobalIndexer(Func initilizer) : base(initilizer) 12 | { 13 | } 14 | } 15 | 16 | public class GlobalIndexer 17 | { 18 | private readonly Func initilizer; 19 | private readonly Dictionary globals; 20 | 21 | public GlobalIndexer(Func initilizer) 22 | { 23 | this.initilizer = initilizer; 24 | globals = new Dictionary(); 25 | } 26 | 27 | public T this[TIndex index] 28 | { 29 | get 30 | { 31 | if (!globals.ContainsKey(index)) 32 | { 33 | globals[index] = initilizer(index); 34 | } 35 | 36 | return globals[index]; 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /XOutputPlugin/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("XOutputPlugin")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("XOutputPlugin")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("bc4f5fd0-7223-424a-9dab-ca60097163ec")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /XOutputPlugin/ScpDevice.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32.SafeHandles; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace XOutputPlugin 10 | { 11 | public partial class ScpDevice 12 | { 13 | public virtual Boolean IsActive 14 | { 15 | get { return m_IsActive; } 16 | } 17 | 18 | public virtual String Path 19 | { 20 | get { return m_Path; } 21 | } 22 | 23 | public ScpDevice(String Class) 24 | { 25 | this.m_Class = new Guid(Class); 26 | } 27 | 28 | 29 | public virtual Boolean Open(Int32 Instance = 0) 30 | { 31 | String DevicePath = String.Empty; 32 | m_WinUsbHandle = (IntPtr)INVALID_HANDLE_VALUE; 33 | 34 | if (Find(m_Class, ref DevicePath, Instance)) 35 | { 36 | Open(DevicePath); 37 | } 38 | 39 | return m_IsActive; 40 | } 41 | 42 | public virtual Boolean Open(String DevicePath) 43 | { 44 | m_Path = DevicePath.ToUpper(); 45 | m_WinUsbHandle = (IntPtr)INVALID_HANDLE_VALUE; 46 | 47 | if (GetDeviceHandle(m_Path)) 48 | { 49 | if (WinUsb_Initialize(m_FileHandle, ref m_WinUsbHandle)) 50 | { 51 | if (InitializeDevice()) 52 | { 53 | 54 | m_IsActive = true; 55 | } 56 | else 57 | { 58 | WinUsb_Free(m_WinUsbHandle); 59 | m_WinUsbHandle = (IntPtr)INVALID_HANDLE_VALUE; 60 | } 61 | } 62 | else 63 | { 64 | m_FileHandle.Close(); 65 | } 66 | } 67 | 68 | return m_IsActive; 69 | } 70 | 71 | public virtual Boolean Start() 72 | { 73 | return m_IsActive; 74 | } 75 | 76 | public virtual Boolean Stop() 77 | { 78 | m_IsActive = false; 79 | 80 | if (!(m_WinUsbHandle == (IntPtr)INVALID_HANDLE_VALUE)) 81 | { 82 | WinUsb_AbortPipe(m_WinUsbHandle, m_IntIn); 83 | WinUsb_AbortPipe(m_WinUsbHandle, m_BulkIn); 84 | WinUsb_AbortPipe(m_WinUsbHandle, m_BulkOut); 85 | 86 | WinUsb_Free(m_WinUsbHandle); 87 | m_WinUsbHandle = (IntPtr)INVALID_HANDLE_VALUE; 88 | } 89 | 90 | if (m_FileHandle != null && !m_FileHandle.IsInvalid && !m_FileHandle.IsClosed) 91 | { 92 | m_FileHandle.Close(); 93 | m_FileHandle = null; 94 | } 95 | 96 | return true; 97 | } 98 | 99 | public virtual Boolean Close() 100 | { 101 | return Stop(); 102 | } 103 | 104 | 105 | 106 | 107 | #region Constant and Structure Definitions 108 | public const Int32 SERVICE_CONTROL_STOP = 0x00000001; 109 | public const Int32 SERVICE_CONTROL_SHUTDOWN = 0x00000005; 110 | public const Int32 SERVICE_CONTROL_DEVICEEVENT = 0x0000000B; 111 | public const Int32 SERVICE_CONTROL_POWEREVENT = 0x0000000D; 112 | 113 | public const Int32 DBT_DEVICEARRIVAL = 0x8000; 114 | public const Int32 DBT_DEVICEQUERYREMOVE = 0x8001; 115 | public const Int32 DBT_DEVICEREMOVECOMPLETE = 0x8004; 116 | public const Int32 DBT_DEVTYP_DEVICEINTERFACE = 0x0005; 117 | public const Int32 DBT_DEVTYP_HANDLE = 0x0006; 118 | 119 | public const Int32 PBT_APMRESUMEAUTOMATIC = 0x0012; 120 | public const Int32 PBT_APMSUSPEND = 0x0004; 121 | 122 | public const Int32 DEVICE_NOTIFY_WINDOW_HANDLE = 0x0000; 123 | public const Int32 DEVICE_NOTIFY_SERVICE_HANDLE = 0x0001; 124 | public const Int32 DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = 0x0004; 125 | 126 | public const Int32 WM_DEVICECHANGE = 0x0219; 127 | 128 | public const Int32 DIGCF_PRESENT = 0x0002; 129 | public const Int32 DIGCF_DEVICEINTERFACE = 0x0010; 130 | 131 | public delegate Int32 ServiceControlHandlerEx(Int32 Control, Int32 Type, IntPtr Data, IntPtr Context); 132 | 133 | [StructLayout(LayoutKind.Sequential)] 134 | public class DEV_BROADCAST_DEVICEINTERFACE 135 | { 136 | internal Int32 dbcc_size; 137 | internal Int32 dbcc_devicetype; 138 | internal Int32 dbcc_reserved; 139 | internal Guid dbcc_classguid; 140 | internal Int16 dbcc_name; 141 | } 142 | 143 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 144 | public class DEV_BROADCAST_DEVICEINTERFACE_M 145 | { 146 | public Int32 dbcc_size; 147 | public Int32 dbcc_devicetype; 148 | public Int32 dbcc_reserved; 149 | 150 | [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 16)] 151 | public Byte[] dbcc_classguid; 152 | 153 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)] 154 | public Char[] dbcc_name; 155 | } 156 | 157 | [StructLayout(LayoutKind.Sequential)] 158 | public class DEV_BROADCAST_HDR 159 | { 160 | public Int32 dbch_size; 161 | public Int32 dbch_devicetype; 162 | public Int32 dbch_reserved; 163 | } 164 | 165 | [StructLayout(LayoutKind.Sequential)] 166 | protected struct SP_DEVICE_INTERFACE_DATA 167 | { 168 | internal Int32 cbSize; 169 | internal Guid InterfaceClassGuid; 170 | internal Int32 Flags; 171 | internal IntPtr Reserved; 172 | } 173 | 174 | protected const UInt32 FILE_ATTRIBUTE_NORMAL = 0x80; 175 | protected const UInt32 FILE_FLAG_OVERLAPPED = 0x40000000; 176 | protected const UInt32 FILE_SHARE_READ = 1; 177 | protected const UInt32 FILE_SHARE_WRITE = 2; 178 | protected const UInt32 GENERIC_READ = 0x80000000; 179 | protected const UInt32 GENERIC_WRITE = 0x40000000; 180 | protected const Int32 INVALID_HANDLE_VALUE = -1; 181 | protected const UInt32 OPEN_EXISTING = 3; 182 | protected const UInt32 DEVICE_SPEED = 1; 183 | protected const Byte USB_ENDPOINT_DIRECTION_MASK = 0x80; 184 | 185 | protected enum POLICY_TYPE 186 | { 187 | SHORT_PACKET_TERMINATE = 1, 188 | AUTO_CLEAR_STALL = 2, 189 | PIPE_TRANSFER_TIMEOUT = 3, 190 | IGNORE_SHORT_PACKETS = 4, 191 | ALLOW_PARTIAL_READS = 5, 192 | AUTO_FLUSH = 6, 193 | RAW_IO = 7, 194 | } 195 | 196 | protected enum USBD_PIPE_TYPE 197 | { 198 | UsbdPipeTypeControl = 0, 199 | UsbdPipeTypeIsochronous = 1, 200 | UsbdPipeTypeBulk = 2, 201 | UsbdPipeTypeInterrupt = 3, 202 | } 203 | 204 | protected enum USB_DEVICE_SPEED 205 | { 206 | UsbLowSpeed = 1, 207 | UsbFullSpeed = 2, 208 | UsbHighSpeed = 3, 209 | } 210 | 211 | [StructLayout(LayoutKind.Sequential)] 212 | protected struct USB_CONFIGURATION_DESCRIPTOR 213 | { 214 | internal Byte bLength; 215 | internal Byte bDescriptorType; 216 | internal UInt16 wTotalLength; 217 | internal Byte bNumInterfaces; 218 | internal Byte bConfigurationValue; 219 | internal Byte iConfiguration; 220 | internal Byte bmAttributes; 221 | internal Byte MaxPower; 222 | } 223 | 224 | [StructLayout(LayoutKind.Sequential)] 225 | protected struct USB_INTERFACE_DESCRIPTOR 226 | { 227 | internal Byte bLength; 228 | internal Byte bDescriptorType; 229 | internal Byte bInterfaceNumber; 230 | internal Byte bAlternateSetting; 231 | internal Byte bNumEndpoints; 232 | internal Byte bInterfaceClass; 233 | internal Byte bInterfaceSubClass; 234 | internal Byte bInterfaceProtocol; 235 | internal Byte iInterface; 236 | } 237 | 238 | [StructLayout(LayoutKind.Sequential)] 239 | protected struct WINUSB_PIPE_INFORMATION 240 | { 241 | internal USBD_PIPE_TYPE PipeType; 242 | internal Byte PipeId; 243 | internal UInt16 MaximumPacketSize; 244 | internal Byte Interval; 245 | } 246 | 247 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 248 | protected struct WINUSB_SETUP_PACKET 249 | { 250 | internal Byte RequestType; 251 | internal Byte Request; 252 | internal UInt16 Value; 253 | internal UInt16 Index; 254 | internal UInt16 Length; 255 | } 256 | 257 | protected const Int32 DIF_PROPERTYCHANGE = 0x12; 258 | protected const Int32 DICS_ENABLE = 1; 259 | protected const Int32 DICS_DISABLE = 2; 260 | protected const Int32 DICS_PROPCHANGE = 3; 261 | protected const Int32 DICS_FLAG_GLOBAL = 1; 262 | 263 | [StructLayout(LayoutKind.Sequential)] 264 | protected struct SP_CLASSINSTALL_HEADER 265 | { 266 | internal Int32 cbSize; 267 | internal Int32 InstallFunction; 268 | } 269 | 270 | [StructLayout(LayoutKind.Sequential)] 271 | protected struct SP_PROPCHANGE_PARAMS 272 | { 273 | internal SP_CLASSINSTALL_HEADER ClassInstallHeader; 274 | internal Int32 StateChange; 275 | internal Int32 Scope; 276 | internal Int32 HwProfile; 277 | } 278 | #endregion 279 | 280 | #region Protected Data Members 281 | protected Guid m_Class = Guid.Empty; 282 | protected String m_Path = String.Empty; 283 | 284 | protected SafeFileHandle m_FileHandle = null; 285 | protected IntPtr m_WinUsbHandle = IntPtr.Zero; 286 | 287 | protected Byte m_IntIn = 0xFF; 288 | protected Byte m_IntOut = 0xFF; 289 | protected Byte m_BulkIn = 0xFF; 290 | protected Byte m_BulkOut = 0xFF; 291 | 292 | protected Boolean m_IsActive = false; 293 | #endregion 294 | 295 | #region Static Helper Methods 296 | public enum Notified { Ignore = 0x0000, Arrival = 0x8000, QueryRemove = 0x8001, Removal = 0x8004 }; 297 | 298 | public static Boolean RegisterNotify(IntPtr Form, Guid Class, ref IntPtr Handle, Boolean Window = true) 299 | { 300 | IntPtr devBroadcastDeviceInterfaceBuffer = IntPtr.Zero; 301 | 302 | try 303 | { 304 | DEV_BROADCAST_DEVICEINTERFACE devBroadcastDeviceInterface = new DEV_BROADCAST_DEVICEINTERFACE(); 305 | Int32 Size = Marshal.SizeOf(devBroadcastDeviceInterface); 306 | 307 | devBroadcastDeviceInterface.dbcc_size = Size; 308 | devBroadcastDeviceInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; 309 | devBroadcastDeviceInterface.dbcc_reserved = 0; 310 | devBroadcastDeviceInterface.dbcc_classguid = Class; 311 | 312 | devBroadcastDeviceInterfaceBuffer = Marshal.AllocHGlobal(Size); 313 | Marshal.StructureToPtr(devBroadcastDeviceInterface, devBroadcastDeviceInterfaceBuffer, true); 314 | 315 | Handle = RegisterDeviceNotification(Form, devBroadcastDeviceInterfaceBuffer, Window ? DEVICE_NOTIFY_WINDOW_HANDLE : DEVICE_NOTIFY_SERVICE_HANDLE); 316 | 317 | Marshal.PtrToStructure(devBroadcastDeviceInterfaceBuffer, devBroadcastDeviceInterface); 318 | 319 | return Handle != IntPtr.Zero; 320 | } 321 | catch (Exception ex) 322 | { 323 | Console.WriteLine("{0} {1}", ex.HelpLink, ex.Message); 324 | throw; 325 | } 326 | finally 327 | { 328 | if (devBroadcastDeviceInterfaceBuffer != IntPtr.Zero) 329 | { 330 | Marshal.FreeHGlobal(devBroadcastDeviceInterfaceBuffer); 331 | } 332 | } 333 | } 334 | 335 | public static Boolean UnregisterNotify(IntPtr Handle) 336 | { 337 | try 338 | { 339 | return UnregisterDeviceNotification(Handle); 340 | } 341 | catch (Exception ex) 342 | { 343 | Console.WriteLine("{0} {1}", ex.HelpLink, ex.Message); 344 | throw; 345 | } 346 | } 347 | #endregion 348 | 349 | #region Protected Methods 350 | protected virtual Boolean Find(Guid Target, ref String Path, Int32 Instance = 0) 351 | { 352 | IntPtr detailDataBuffer = IntPtr.Zero; 353 | IntPtr deviceInfoSet = IntPtr.Zero; 354 | 355 | try 356 | { 357 | SP_DEVICE_INTERFACE_DATA DeviceInterfaceData = new SP_DEVICE_INTERFACE_DATA(), da = new SP_DEVICE_INTERFACE_DATA(); 358 | Int32 bufferSize = 0, memberIndex = 0; 359 | 360 | deviceInfoSet = SetupDiGetClassDevs(ref Target, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); 361 | 362 | DeviceInterfaceData.cbSize = da.cbSize = Marshal.SizeOf(DeviceInterfaceData); 363 | 364 | while (SetupDiEnumDeviceInterfaces(deviceInfoSet, IntPtr.Zero, ref Target, memberIndex, ref DeviceInterfaceData)) 365 | { 366 | SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref DeviceInterfaceData, IntPtr.Zero, 0, ref bufferSize, ref da); 367 | { 368 | detailDataBuffer = Marshal.AllocHGlobal(bufferSize); 369 | 370 | Marshal.WriteInt32(detailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8); 371 | 372 | if (SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref DeviceInterfaceData, detailDataBuffer, bufferSize, ref bufferSize, ref da)) 373 | { 374 | IntPtr pDevicePathName = new IntPtr(IntPtr.Size == 4 ? detailDataBuffer.ToInt32() + 4 : detailDataBuffer.ToInt64() + 4); 375 | 376 | Path = Marshal.PtrToStringAuto(pDevicePathName).ToUpper(); 377 | Marshal.FreeHGlobal(detailDataBuffer); 378 | 379 | if (memberIndex == Instance) return true; 380 | } 381 | else Marshal.FreeHGlobal(detailDataBuffer); 382 | } 383 | 384 | memberIndex++; 385 | } 386 | } 387 | catch (Exception ex) 388 | { 389 | Console.WriteLine("{0} {1}", ex.HelpLink, ex.Message); 390 | throw; 391 | } 392 | finally 393 | { 394 | if (deviceInfoSet != IntPtr.Zero) 395 | { 396 | SetupDiDestroyDeviceInfoList(deviceInfoSet); 397 | } 398 | } 399 | 400 | return false; 401 | } 402 | 403 | 404 | protected virtual Boolean GetDeviceHandle(String Path) 405 | { 406 | 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); 407 | 408 | return !m_FileHandle.IsInvalid; 409 | } 410 | 411 | protected virtual Boolean UsbEndpointDirectionIn(Int32 addr) 412 | { 413 | return (addr & 0x80) == 0x80; 414 | } 415 | 416 | protected virtual Boolean UsbEndpointDirectionOut(Int32 addr) 417 | { 418 | return (addr & 0x80) == 0x00; 419 | } 420 | 421 | protected virtual Boolean InitializeDevice() 422 | { 423 | try 424 | { 425 | USB_INTERFACE_DESCRIPTOR ifaceDescriptor = new USB_INTERFACE_DESCRIPTOR(); 426 | WINUSB_PIPE_INFORMATION pipeInfo = new WINUSB_PIPE_INFORMATION(); 427 | 428 | if (WinUsb_QueryInterfaceSettings(m_WinUsbHandle, 0, ref ifaceDescriptor)) 429 | { 430 | for (Int32 i = 0; i < ifaceDescriptor.bNumEndpoints; i++) 431 | { 432 | WinUsb_QueryPipe(m_WinUsbHandle, 0, System.Convert.ToByte(i), ref pipeInfo); 433 | 434 | if (((pipeInfo.PipeType == USBD_PIPE_TYPE.UsbdPipeTypeBulk) & UsbEndpointDirectionIn(pipeInfo.PipeId))) 435 | { 436 | m_BulkIn = pipeInfo.PipeId; 437 | WinUsb_FlushPipe(m_WinUsbHandle, m_BulkIn); 438 | } 439 | else if (((pipeInfo.PipeType == USBD_PIPE_TYPE.UsbdPipeTypeBulk) & UsbEndpointDirectionOut(pipeInfo.PipeId))) 440 | { 441 | m_BulkOut = pipeInfo.PipeId; 442 | WinUsb_FlushPipe(m_WinUsbHandle, m_BulkOut); 443 | } 444 | else if ((pipeInfo.PipeType == USBD_PIPE_TYPE.UsbdPipeTypeInterrupt) & UsbEndpointDirectionIn(pipeInfo.PipeId)) 445 | { 446 | m_IntIn = pipeInfo.PipeId; 447 | WinUsb_FlushPipe(m_WinUsbHandle, m_IntIn); 448 | } 449 | else if ((pipeInfo.PipeType == USBD_PIPE_TYPE.UsbdPipeTypeInterrupt) & UsbEndpointDirectionOut(pipeInfo.PipeId)) 450 | { 451 | m_IntOut = pipeInfo.PipeId; 452 | WinUsb_FlushPipe(m_WinUsbHandle, m_IntOut); 453 | } 454 | } 455 | 456 | return true; 457 | } 458 | 459 | return false; 460 | } 461 | catch (Exception ex) 462 | { 463 | Console.WriteLine("{0} {1}", ex.HelpLink, ex.Message); 464 | throw; 465 | } 466 | } 467 | 468 | #endregion 469 | 470 | #region Interop Definitions 471 | [DllImport("setupapi.dll", SetLastError = true)] 472 | protected static extern Int32 SetupDiCreateDeviceInfoList(ref System.Guid ClassGuid, Int32 hwndParent); 473 | 474 | [DllImport("setupapi.dll", SetLastError = true)] 475 | protected static extern Int32 SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet); 476 | 477 | [DllImport("setupapi.dll", SetLastError = true)] 478 | protected static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr DeviceInfoSet, IntPtr DeviceInfoData, ref System.Guid InterfaceClassGuid, Int32 MemberIndex, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData); 479 | 480 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] 481 | protected static extern IntPtr SetupDiGetClassDevs(ref System.Guid ClassGuid, IntPtr Enumerator, IntPtr hwndParent, Int32 Flags); 482 | 483 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] 484 | protected static extern Boolean SetupDiGetDeviceInterfaceDetail(IntPtr DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, IntPtr DeviceInterfaceDetailData, Int32 DeviceInterfaceDetailDataSize, ref Int32 RequiredSize, IntPtr DeviceInfoData); 485 | 486 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] 487 | 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); 488 | 489 | [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 490 | protected static extern IntPtr RegisterDeviceNotification(IntPtr hRecipient, IntPtr NotificationFilter, Int32 Flags); 491 | 492 | [DllImport("user32.dll", SetLastError = true)] 493 | protected static extern Boolean UnregisterDeviceNotification(IntPtr Handle); 494 | 495 | [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] 496 | protected static extern SafeFileHandle CreateFile(String lpFileName, UInt32 dwDesiredAccess, UInt32 dwShareMode, IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition, UInt32 dwFlagsAndAttributes, UInt32 hTemplateFile); 497 | 498 | [DllImport("winusb.dll", SetLastError = true)] 499 | protected static extern Boolean WinUsb_Initialize(SafeFileHandle DeviceHandle, ref IntPtr InterfaceHandle); 500 | 501 | [DllImport("winusb.dll", SetLastError = true)] 502 | protected static extern Boolean WinUsb_QueryInterfaceSettings(IntPtr InterfaceHandle, Byte AlternateInterfaceNumber, ref USB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor); 503 | 504 | [DllImport("winusb.dll", SetLastError = true)] 505 | protected static extern Boolean WinUsb_QueryPipe(IntPtr InterfaceHandle, Byte AlternateInterfaceNumber, Byte PipeIndex, ref WINUSB_PIPE_INFORMATION PipeInformation); 506 | 507 | [DllImport("winusb.dll", SetLastError = true)] 508 | protected static extern Boolean WinUsb_AbortPipe(IntPtr InterfaceHandle, Byte PipeID); 509 | 510 | [DllImport("winusb.dll", SetLastError = true)] 511 | protected static extern Boolean WinUsb_FlushPipe(IntPtr InterfaceHandle, Byte PipeID); 512 | 513 | [DllImport("winusb.dll", SetLastError = true)] 514 | protected static extern Boolean WinUsb_ControlTransfer(IntPtr InterfaceHandle, WINUSB_SETUP_PACKET SetupPacket, Byte[] Buffer, Int32 BufferLength, ref Int32 LengthTransferred, IntPtr Overlapped); 515 | 516 | [DllImport("winusb.dll", SetLastError = true)] 517 | protected static extern Boolean WinUsb_ReadPipe(IntPtr InterfaceHandle, Byte PipeID, Byte[] Buffer, Int32 BufferLength, ref Int32 LengthTransferred, IntPtr Overlapped); 518 | 519 | [DllImport("winusb.dll", SetLastError = true)] 520 | protected static extern Boolean WinUsb_WritePipe(IntPtr InterfaceHandle, Byte PipeID, Byte[] Buffer, Int32 BufferLength, ref Int32 LengthTransferred, IntPtr Overlapped); 521 | 522 | [DllImport("winusb.dll", SetLastError = true)] 523 | protected static extern Boolean WinUsb_Free(IntPtr InterfaceHandle); 524 | 525 | [DllImport("advapi32.dll", SetLastError = true)] 526 | public static extern IntPtr RegisterServiceCtrlHandlerEx(String ServiceName, ServiceControlHandlerEx Callback, IntPtr Context); 527 | 528 | [DllImport("kernel32.dll", SetLastError = true)] 529 | protected static extern Boolean DeviceIoControl(SafeFileHandle DeviceHandle, Int32 IoControlCode, Byte[] InBuffer, Int32 InBufferSize, Byte[] OutBuffer, Int32 OutBufferSize, ref Int32 BytesReturned, IntPtr Overlapped); 530 | 531 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] 532 | protected static extern Int32 CM_Get_Device_ID(Int32 dnDevInst, IntPtr Buffer, Int32 BufferLen, Int32 ulFlags); 533 | 534 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] 535 | protected static extern Boolean SetupDiOpenDeviceInfo(IntPtr DeviceInfoSet, String DeviceInstanceId, IntPtr hwndParent, Int32 Flags, ref SP_DEVICE_INTERFACE_DATA DeviceInfoData); 536 | 537 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] 538 | protected static extern Boolean SetupDiChangeState(IntPtr DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData); 539 | 540 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] 541 | protected static extern Boolean SetupDiSetClassInstallParams(IntPtr DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, ref SP_PROPCHANGE_PARAMS ClassInstallParams, Int32 ClassInstallParamsSize); 542 | #endregion 543 | } 544 | } 545 | -------------------------------------------------------------------------------- /XOutputPlugin/Scripts/Halo.py: -------------------------------------------------------------------------------- 1 | 2 | #left joy 3 | if keyboard.getKeyDown(Key.A): 4 | xoutput[0].lx = xoutput[0].AxisMin 5 | if keyboard.getKeyDown(Key.S): 6 | xoutput[0].ly = xoutput[0].AxisMin 7 | if keyboard.getKeyDown(Key.D): 8 | xoutput[0].lx = xoutput[0].AxisMax 9 | if keyboard.getKeyDown(Key.W): 10 | xoutput[0].ly = xoutput[0].AxisMax 11 | 12 | xoutput[0].rx = mouse.deltaX * 50000 13 | xoutput[0].ry = -(mouse.deltaY * 50000) 14 | 15 | xoutput[0].L1 = keyboard.getKeyDown(Key.Space) 16 | #xoutput[0].L2 17 | if mouse.rightButton: 18 | xoutput[0].R1 = xoutput[0].TriggerMax 19 | if mouse.leftButton: 20 | xoutput[0].R2 = xoutput[0].TriggerMax 21 | xoutput[0].R3 = keyboard.getKeyDown(Key.E) 22 | xoutput[0].L3 = keyboard.getKeyDown(Key.LeftControl) 23 | 24 | xoutput[0].Back = keyboard.getKeyDown(Key.LeftBracket) 25 | xoutput[0].Start = keyboard.getKeyDown(Key.RightBracket) 26 | xoutput[0].Guide = keyboard.getKeyDown(Key.Return) 27 | 28 | xoutput[0].A = keyboard.getKeyDown(Key.Q) 29 | xoutput[0].B = keyboard.getKeyDown(Key.R) 30 | xoutput[0].X = keyboard.getKeyDown(Key.F) 31 | xoutput[0].Y = mouse.middleButton 32 | 33 | xoutput[0].Up = keyboard.getKeyDown(Key.UpArrow) 34 | xoutput[0].Down = keyboard.getKeyDown(Key.DownArrow) 35 | xoutput[0].Left = keyboard.getKeyDown(Key.LeftArrow) 36 | xoutput[0].Right = keyboard.getKeyDown(Key.RightArrow) -------------------------------------------------------------------------------- /XOutputPlugin/XOutputPlugin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using FreePIE.Core.Contracts; 7 | using XOutputPlugin.Globals; 8 | using SlimDX.XInput; 9 | 10 | namespace XOutputPlugin 11 | { 12 | 13 | [GlobalType(Type = typeof(XOutputGlobal), IsIndexed = true)] 14 | public class XOutputPlugin : IPlugin 15 | { 16 | private List holders = new List(); 17 | 18 | public event EventHandler Started; 19 | 20 | public object CreateGlobal() 21 | { 22 | holders = new List(); 23 | return new GlobalIndexer(Create); 24 | } 25 | 26 | private XOutputGlobal Create(uint index) 27 | { 28 | var holder = new XOutputGlobalHolder(index + 1); 29 | holders.Add(holder); 30 | return holder.Global; 31 | } 32 | 33 | public void Stop() 34 | { 35 | holders.ForEach(h => h.Dispose()); 36 | } 37 | 38 | public void DoBeforeNextExecute() 39 | { 40 | holders.ForEach(h => h.SendPressed()); 41 | } 42 | 43 | public Action Start() 44 | { 45 | return null; 46 | } 47 | 48 | public bool GetProperty(int index, IPluginProperty property) 49 | { 50 | return false; 51 | } 52 | 53 | public bool SetProperties(Dictionary properties) 54 | { 55 | return false; 56 | } 57 | 58 | public string FriendlyName 59 | { 60 | get { return "xOutput"; } 61 | } 62 | } 63 | 64 | public class XOutputGlobalHolder : IDisposable 65 | { 66 | private DS3Device device; 67 | 68 | public XOutputGlobalHolder(uint index) 69 | { 70 | Global = new XOutputGlobal(this); 71 | device = new DS3Device(index); 72 | device.Open(); 73 | device.Plugin(); 74 | } 75 | 76 | public void SetTrigger(XOutputTrigger trigger, int value) 77 | { 78 | device.SetTrigger(trigger, (Byte)value); 79 | } 80 | 81 | public void SetButton(XOutputButton button, bool pressed) 82 | { 83 | device.SetButton(button, pressed); 84 | } 85 | 86 | public void SetPressed(XOutputButton button) 87 | { 88 | device.SetButton(button, true); 89 | } 90 | 91 | public void SendPressed() 92 | { 93 | device.SendPressed(); 94 | } 95 | 96 | public void SetAxis(XOutputAxis axis, int value) 97 | { 98 | device.SetAxis(axis, value); 99 | } 100 | 101 | public int GetAxis(XOutputAxis axis) 102 | { 103 | return device.GetAxis(axis); 104 | } 105 | 106 | public int GetTrigger(XOutputTrigger trigger) 107 | { 108 | return device.GetTrigger(trigger); 109 | } 110 | 111 | public bool GetButton(XOutputButton button) 112 | { 113 | return device.GetButton(button); 114 | } 115 | 116 | public void SetReset(bool value) 117 | { 118 | device.ResetAxisOnExecute = value; 119 | } 120 | 121 | public bool GetReset() 122 | { 123 | return device.ResetAxisOnExecute; 124 | } 125 | 126 | public void Dispose() 127 | { 128 | device.Unplug(); 129 | } 130 | 131 | public XOutputGlobal Global { get; private set; } 132 | } 133 | 134 | [Global(Name = "xoutput")] 135 | public class XOutputGlobal 136 | { 137 | private readonly XOutputGlobalHolder holder; 138 | 139 | public XOutputGlobal(XOutputGlobalHolder holder) 140 | { 141 | this.holder = holder; 142 | } 143 | 144 | #region Axis 145 | public int lx 146 | { 147 | get { return holder.GetAxis(XOutputAxis.LX); } 148 | set { holder.SetAxis(XOutputAxis.LX, value); } 149 | } 150 | 151 | public int ly 152 | { 153 | get { return holder.GetAxis(XOutputAxis.LY); } 154 | set { holder.SetAxis(XOutputAxis.LY, value); } 155 | } 156 | 157 | public int rx 158 | { 159 | get { return holder.GetAxis(XOutputAxis.RX); } 160 | set { holder.SetAxis(XOutputAxis.RX, value); } 161 | } 162 | 163 | public int ry 164 | { 165 | get { return holder.GetAxis(XOutputAxis.RY); } 166 | set { holder.SetAxis(XOutputAxis.RY, value); } 167 | } 168 | #endregion 169 | 170 | #region Triggers 171 | public int R2 172 | { 173 | get { return holder.GetTrigger(XOutputTrigger.R2); } 174 | set { holder.SetTrigger(XOutputTrigger.R2, value); } 175 | } 176 | 177 | public int L2 178 | { 179 | get { return holder.GetTrigger(XOutputTrigger.L2); } 180 | set { holder.SetTrigger(XOutputTrigger.L2, value); } 181 | } 182 | #endregion 183 | 184 | #region Buttons 185 | public bool Up 186 | { 187 | get { return holder.GetButton(XOutputButton.Up); } 188 | set { holder.SetButton(XOutputButton.Up, value); } 189 | } 190 | 191 | public bool Down 192 | { 193 | get { return holder.GetButton(XOutputButton.Down); } 194 | set { holder.SetButton(XOutputButton.Down, value); } 195 | } 196 | 197 | public bool Left 198 | { 199 | get { return holder.GetButton(XOutputButton.Left); } 200 | set { holder.SetButton(XOutputButton.Left, value); } 201 | } 202 | 203 | public bool Right 204 | { 205 | get { return holder.GetButton(XOutputButton.Right); } 206 | set { holder.SetButton(XOutputButton.Right, value); } 207 | } 208 | 209 | public bool Start 210 | { 211 | get { return holder.GetButton(XOutputButton.Start); } 212 | set { holder.SetButton(XOutputButton.Start, value); } 213 | } 214 | 215 | public bool Back 216 | { 217 | get { return holder.GetButton(XOutputButton.Back); } 218 | set { holder.SetButton(XOutputButton.Back, value); } 219 | } 220 | 221 | public bool L3 222 | { 223 | get { return holder.GetButton(XOutputButton.L3); } 224 | set { holder.SetButton(XOutputButton.L3, value); } 225 | } 226 | 227 | public bool R3 228 | { 229 | get { return holder.GetButton(XOutputButton.R3); } 230 | set { holder.SetButton(XOutputButton.R3, value); } 231 | } 232 | 233 | public bool L1 234 | { 235 | get { return holder.GetButton(XOutputButton.L1); } 236 | set { holder.SetButton(XOutputButton.L1, value); } 237 | } 238 | 239 | public bool R1 240 | { 241 | get { return holder.GetButton(XOutputButton.R1); } 242 | set { holder.SetButton(XOutputButton.R1, value); } 243 | } 244 | 245 | public bool Guide 246 | { 247 | get { return holder.GetButton(XOutputButton.Guide); } 248 | set { holder.SetButton(XOutputButton.Guide, value); } 249 | } 250 | 251 | public bool Y 252 | { 253 | get { return holder.GetButton(XOutputButton.Y); } 254 | set { holder.SetButton(XOutputButton.Y, value); } 255 | } 256 | 257 | public bool B 258 | { 259 | get { return holder.GetButton(XOutputButton.B); } 260 | set { holder.SetButton(XOutputButton.B, value); } 261 | } 262 | 263 | public bool A 264 | { 265 | get { return holder.GetButton(XOutputButton.A); } 266 | set { holder.SetButton(XOutputButton.A, value); } 267 | } 268 | 269 | public bool X 270 | { 271 | get { return holder.GetButton(XOutputButton.X); } 272 | set { holder.SetButton(XOutputButton.X, value); } 273 | } 274 | #endregion 275 | 276 | public bool ResetAxisOnExecute { 277 | get { return holder.GetReset(); } 278 | set { holder.SetReset(value); } 279 | } 280 | public int AxisMax { get { return Int16.MaxValue; } } 281 | public int AxisMin { get { return Int16.MinValue; } } 282 | public int TriggerMax { get { return Byte.MaxValue; } } 283 | public int TriggerMin { get { return Byte.MaxValue; } } 284 | 285 | public void setButton(XOutputButton button, bool pressed) 286 | { 287 | holder.SetButton(button, pressed); 288 | } 289 | 290 | } 291 | 292 | } 293 | -------------------------------------------------------------------------------- /XOutputPlugin/XOutputPlugin.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | {BC4F5FD0-7223-424A-9DAB-CA60097163EC} 7 | Library 8 | Properties 9 | XOutputPlugin 10 | XOutputPlugin 11 | v4.5 12 | 512 13 | 14 | 15 | 16 | true 17 | full 18 | true 19 | ..\..\..\..\..\..\..\..\Program Files %28x86%29\FreePIE\plugins\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | false 24 | true 25 | 26 | 27 | full 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | false 34 | true 35 | true 36 | 37 | 38 | 39 | ..\..\..\..\..\..\..\..\Program Files (x86)\FreePIE\FreePIE.Core.Contracts.dll 40 | False 41 | 42 | 43 | ..\..\..\..\..\..\..\..\Program Files (x86)\FreePIE\SlimDX.dll 44 | False 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 76 | -------------------------------------------------------------------------------- /XOutputPlugin/bin/Release/XOutputPlugin.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dschu012/XOutputPlugin/f534107c5e5a837b6ce649ac4f3039b6ea50c85c/XOutputPlugin/bin/Release/XOutputPlugin.dll --------------------------------------------------------------------------------