Repository: jloehr/HID-Wiimote Branch: master Commit: 9161c0922b25 Files: 122 Total size: 515.3 KB Directory structure: gitextract_3ar40yv7/ ├── .gitignore ├── BuildAndZip/ │ ├── BuildAndZip.vcxproj │ └── BuildAndZip.vcxproj.filters ├── BuildTools/ │ └── 7za/ │ ├── 7-zip.chm │ ├── license.txt │ └── readme.txt ├── HID Miniport/ │ ├── HID Miniport.rc │ ├── HID Miniport.vcxproj │ ├── HID Miniport.vcxproj.backup │ ├── HID Miniport.vcxproj.filters │ ├── Hidminiport.c │ ├── Hidminiport.h │ ├── Trace.c │ ├── Trace.h │ └── resource.h ├── HID Wiimote/ │ ├── Bluetooth.c │ ├── Bluetooth.h │ ├── Device.c │ ├── Device.h │ ├── DeviceInterface.c │ ├── DeviceInterface.h │ ├── DeviceInterfacePublic.h │ ├── Driver.c │ ├── Driver.h │ ├── HID Wiimote.rc │ ├── HID Wiimote.vcxproj │ ├── HID Wiimote.vcxproj.backup │ ├── HID Wiimote.vcxproj.filters │ ├── HID.c │ ├── HID.h │ ├── HIDDescriptors.c │ ├── HIDDescriptors.h │ ├── HIDWiimote.h │ ├── HIDWiimote.inf │ ├── ReadIoControlBuffer.c │ ├── ReadIoControlBuffer.h │ ├── Trace.c │ ├── Trace.h │ ├── Wiimote.c │ ├── Wiimote.h │ ├── WiimoteSettings.c │ ├── WiimoteSettings.h │ ├── WiimoteState.c │ ├── WiimoteState.h │ ├── WiimoteToHIDParser.c │ ├── WiimoteToHIDParser.h │ └── resource.h ├── HID Wiimote Control Center/ │ ├── App.config │ ├── App.xaml │ ├── App.xaml.cs │ ├── Control Center/ │ │ ├── DummyDeviceInterface.cs │ │ └── WiimoteDevice.cs │ ├── HID Wiimote Control Center.csproj │ ├── Main Windows/ │ │ ├── ControlCenterWindow.xaml │ │ ├── ControlCenterWindow.xaml.cs │ │ ├── InstallerWindow.xaml │ │ ├── InstallerWindow.xaml.cs │ │ ├── UpdaterWindow.xaml │ │ └── UpdaterWindow.xaml.cs │ ├── Properties/ │ │ ├── App.Designer.cs │ │ ├── App.resx │ │ ├── AssemblyInfo.cs │ │ ├── ControlCenter.Designer.cs │ │ ├── ControlCenter.resx │ │ ├── Installer.Designer.cs │ │ ├── Installer.resx │ │ ├── Settings.Designer.cs │ │ ├── Settings.settings │ │ └── app.manifest │ ├── Resources/ │ │ ├── JulianLoehrCA.cer │ │ └── UninstallerContent.txt │ ├── Secondary Windows/ │ │ ├── About.xaml │ │ └── About.xaml.cs │ ├── Setup/ │ │ ├── DeviceDriver.cs │ │ ├── DeviceDriverUninstallerRegistry.cs │ │ ├── InstallStepAction/ │ │ │ ├── CopyFile.cs │ │ │ ├── CreateRegistryUninstallKey.cs │ │ │ ├── IInstallAction.cs │ │ │ ├── RunDPInstall.cs │ │ │ └── TextResourceToFile.cs │ │ └── SetupAction/ │ │ ├── Certificate.cs │ │ ├── DeviceDriver.cs │ │ ├── ISetupAction.cs │ │ └── TestMode.cs │ ├── UserControls/ │ │ ├── LEDDisplay.xaml │ │ ├── LEDDisplay.xaml.cs │ │ ├── TaskList.xaml │ │ └── TaskList.xaml.cs │ └── Utility/ │ └── SingleInstanceProtector.cs ├── HID Wiimote Package/ │ ├── DPInst.xml │ ├── EULA.txt │ ├── HID Wiimote Package.vcxproj │ ├── HID Wiimote Package.vcxproj.backup │ ├── HID Wiimote Package.vcxproj.filters │ └── Readme.txt ├── HID Wiimote User Mode/ │ ├── AssemblyInfo.cpp │ ├── HID Wiimote User Mode.rc │ ├── HID Wiimote User Mode.vcxproj │ ├── HID Wiimote User Mode.vcxproj.filters │ ├── IWiimoteDeviceInterface.h │ ├── Log.cpp │ ├── Log.h │ ├── State.cpp │ ├── State.h │ ├── Status.cpp │ ├── Status.h │ ├── Stdafx.cpp │ ├── Stdafx.h │ ├── WiimoteDeviceInterface.cpp │ ├── WiimoteDeviceInterface.h │ ├── WiimoteDeviceInterfaceDiscoverer.cpp │ ├── WiimoteDeviceInterfaceDiscoverer.h │ ├── WiimoteDeviceInterfaceEnumerator.cpp │ ├── WiimoteDeviceInterfaceEnumerator.h │ └── resource.h ├── HID Wiimote.sln ├── LICENSE.md ├── README.md └── ReleaseVersioning/ ├── ReleaseVersioning.vcxproj ├── ReleaseVersioning.vcxproj.filters ├── Version.js └── Version.wsf ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific folders Certificates/ Zip/ # Autogenerated files ReleaseVersioning/Version.props ReleaseVersioning/VersionStrings.h ReleaseVersioning/VersionStrings.cs HID Wiimote Control Center/Properties/VersionStrings.cs # User-specific files *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ # Visual Studio 2015 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUNIT *.VisualState.xml TestResult.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # Benchmark Results BenchmarkDotNet.Artifacts/ # .NET Core project.lock.json project.fragment.lock.json artifacts/ **/Properties/launchSettings.json *_i.c *_p.c *_i.h *.ilk *.meta *.obj *.pch *.pdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc *.snk # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opendb *.opensdf *.sdf *.cachefile *.VC.db *.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx *.sap # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # JustCode is a .NET coding add-in .JustCode # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # Visual Studio code coverage results *.coverage *.coveragexml # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # 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 *.[Pp]ublish.xml *.azurePubxml # TODO: Comment the next line if you want to checkin your web deploy settings # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to # checkin your Azure Web App publish settings, but sensitive information contained # in these scripts will be unencrypted PublishScripts/ # NuGet Packages *.nupkg # The packages folder can be ignored because of Package Restore **/packages/* # except build/, which is used as an MSBuild target. !**/packages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/packages/repositories.config # NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets # Microsoft Azure Build Output csx/ *.build.csdef # Microsoft Azure Emulator ecf/ rcf/ # Windows Store app package directories and files AppPackages/ BundleArtifacts/ Package.StoreAssociation.xml _pkginfo.txt *.appx # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !*.[Cc]ache/ # Others ClientBin/ ~$* *~ *.dbmdl *.dbproj.schemaview *.jfm *.pfx *.publishsettings orleans.codegen.cs # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ # 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 *.mdf *.ldf *.ndf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings # Microsoft Fakes FakesAssemblies/ # GhostDoc plugin setting file *.GhostDoc.xml # Node.js Tools for Visual Studio .ntvs_analysis.dat node_modules/ # Typescript v1 declaration files typings/ # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions # Paket dependency manager .paket/paket.exe paket-files/ # FAKE - F# Make .fake/ # JetBrains Rider .idea/ *.sln.iml # CodeRush .cr/ # Python Tools for Visual Studio (PTVS) __pycache__/ *.pyc # Cake - Uncomment if you are using it # tools/** # !tools/packages.config # Tabs Studio *.tss # Telerik's JustMock configuration file *.jmconfig # BizTalk build output *.btp.cs *.btm.cs *.odx.cs *.xsd.cs ================================================ FILE: BuildAndZip/BuildAndZip.vcxproj ================================================ Windows 10 Universal Release Win32 Windows 10 Universal Release x64 Windows 10 Release Win32 Windows 10 Release x64 {0C56BAEE-4F6C-4590-9E48-EFBF80099FEB} BuildAndZip 10.0 v143 Utility v143 Utility v143 Utility v143 Utility $(SolutionDir)BuildTools\7za\7za.exe $(SolutionDir)Zip $(SolutionName.replace(' ','-'))-$(ControlCenterVersion)_$(PlatformArchitecture)Bit.zip $(ZipDir)\$(ZipName) $(SolutionDir)$(PlatformShortName)\$(Configuration.replace(" ",""))\HID Wiimote Package $(PlatformShortName)\$(Configuration)\ $(PlatformShortName)\$(Configuration)\ $(PlatformShortName)\$(Configuration)\ $(PlatformShortName)\$(Configuration)\ $(PlatformShortName)\$(Configuration)\ $(PlatformShortName)\$(Configuration)\ $(PlatformShortName)\$(Configuration)\ $(PlatformShortName)\$(Configuration)\ if not exist "$(ZipDir)" mkdir "$(ZipDir)" "$(ZipTool)" d "$(ZipPath)" "$(ZipTool)" a "$(ZipPath)" "$(PackageDir)\*" if not exist "$(ZipDir)" mkdir "$(ZipDir)" "$(ZipTool)" d "$(ZipPath)" "$(ZipTool)" a "$(ZipPath)" "$(PackageDir)\*" if not exist "$(ZipDir)" mkdir "$(ZipDir)" "$(ZipTool)" d "$(ZipPath)" "$(ZipTool)" a "$(ZipPath)" "$(PackageDir)\*" if not exist "$(ZipDir)" mkdir "$(ZipDir)" "$(ZipTool)" d "$(ZipPath)" "$(ZipTool)" a "$(ZipPath)" "$(PackageDir)\*" ================================================ FILE: BuildAndZip/BuildAndZip.vcxproj.filters ================================================  ================================================ FILE: BuildTools/7za/license.txt ================================================ 7-Zip Command line version ~~~~~~~~~~~~~~~~~~~~~~~~~~ License for use and distribution ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7-Zip Copyright (C) 1999-2010 Igor Pavlov. 7za.exe is distributed under the GNU LGPL license Notes: You can use 7-Zip on any computer, including a computer in a commercial organization. You don't need to register or pay for 7-Zip. GNU LGPL information -------------------- This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You can receive a copy of the GNU Lesser General Public License from http://www.gnu.org/ ================================================ FILE: BuildTools/7za/readme.txt ================================================ 7-Zip Command line version 9.20 ------------------------------- 7-Zip is a file archiver with high compression ratio. 7za.exe is a standalone command line version of 7-Zip. 7-Zip Copyright (C) 1999-2010 Igor Pavlov. Features of 7za.exe: - High compression ratio in new 7z format - Supported formats: - Packing / unpacking: 7z, xz, ZIP, GZIP, BZIP2 and TAR - Unpacking only: Z, lzma - Highest compression ratio for ZIP and GZIP formats. - Fast compression and decompression - Strong AES-256 encryption in 7z and ZIP formats. 7za.exe is a free software distributed under the GNU LGPL. Read license.txt for more information. Source code of 7za.exe and 7-Zip can be found at http://www.7-zip.org/ 7za.exe can work in Windows 95/98/ME/NT/2000/2003/2008/XP/Vista/7. There is also port of 7za.exe for POSIX systems like Unix (Linux, Solaris, OpenBSD, FreeBSD, Cygwin, AIX, ...), MacOS X and BeOS: http://p7zip.sourceforge.net/ This distributive packet contains the following files: 7za.exe - 7-Zip standalone command line version. readme.txt - This file. license.txt - License information. 7-zip.chm - User's Manual in HTML Help format. --- End of document ================================================ FILE: HID Miniport/HID Miniport.vcxproj ================================================  Windows 10 Universal Debug Win32 Windows 10 Universal Debug x64 Windows 10 Universal Release Win32 Windows 10 Universal Release x64 Windows 10 Debug Win32 Windows 10 Release Win32 Windows 10 Debug x64 Windows 10 Release x64 {3BAFF0EB-1B25-4E8E-8189-267B6686D7BC} {dd38f7fc-d7bd-488b-9242-7d8754cde80d} Win8 Debug Win32 HID_Miniport Driver WDM Windows10 true WindowsKernelModeDriver10.0 false true WindowsKernelModeDriver10.0 false Universal Windows10 false WindowsKernelModeDriver10.0 false false WindowsKernelModeDriver10.0 false Universal Windows10 true WindowsKernelModeDriver10.0 false true WindowsKernelModeDriver10.0 false Universal Windows10 false WindowsKernelModeDriver10.0 false false WindowsKernelModeDriver10.0 false Universal DbgengKernelDebugger $(SolutionDir)$(PlatformShortName)\$(ConfigurationName)\ $(PlatformShortName)\$(ConfigurationName)\ $(SolutionDir)$(PlatformShortName)\$(ConfigurationName)\ $(PlatformShortName)\$(ConfigurationName)\ $(SolutionDir)$(PlatformShortName)\$(ConfigurationName)\ $(PlatformShortName)\$(ConfigurationName)\ $(SolutionDir)$(PlatformShortName)\$(ConfigurationName)\ $(PlatformShortName)\$(ConfigurationName)\ $(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) SHA256 $(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) $(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) SHA256 $(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) $(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) SHA256 $(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) $(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) SHA256 $(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) ================================================ FILE: HID Miniport/HID Miniport.vcxproj.backup ================================================  Win8 Debug Win32 Win8 Release Win32 Win7 Debug Win32 Win7 Release Win32 Vista Debug Win32 Vista Release Win32 Win8 Debug x64 Win8 Release x64 Win7 Debug x64 Win7 Release x64 Vista Debug x64 Vista Release x64 {3BAFF0EB-1B25-4E8E-8189-267B6686D7BC} {dd38f7fc-d7bd-488b-9242-7d8754cde80d} v4.5 11.0 Win8 Debug Win32 HID_Miniport $(VCTargetsPath11) WindowsKernelModeDriver8.0 Driver WDM Windows8 true Windows8 false Windows7 true Windows7 false Vista true Vista false Windows8 true Windows8 false Windows7 true Windows7 false Vista true Vista false $(SolutionDir)$(PlatformShortName)\$(ConfigurationName)\ $(PlatformShortName)\$(ConfigurationName)\ DbgengKernelDebugger $(SolutionDir)$(PlatformShortName)\$(ConfigurationName)\ $(PlatformShortName)\$(ConfigurationName)\ $(SolutionDir)$(PlatformShortName)\$(ConfigurationName)\ $(PlatformShortName)\$(ConfigurationName)\ $(SolutionDir)$(PlatformShortName)\$(ConfigurationName)\ $(PlatformShortName)\$(ConfigurationName)\ $(SolutionDir)$(PlatformShortName)\$(ConfigurationName)\ $(PlatformShortName)\$(ConfigurationName)\ $(SolutionDir)$(PlatformShortName)\$(ConfigurationName)\ $(PlatformShortName)\$(ConfigurationName)\ $(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) $(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) $(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) $(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) $(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) $(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) $(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) $(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) $(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) $(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) $(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) $(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;%(AdditionalDependencies) ================================================ FILE: HID Miniport/HID Miniport.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms {8E41214B-6785-4CFE-B992-037D68949A14} inf;inv;inx;mof;mc; Source Files Source Files Header Files Header Files Header Files Resource Files ================================================ FILE: HID Miniport/Hidminiport.c ================================================ /* Copyright (C) 2014 Julian Lhr All rights reserved. Filename: hidminiport.c Abstract: Actual miniport driver for HIDClass. Passes through all IRPs. Additonally sends down a custiom IOCTL, with the actual FDO and HidNotifyPrcense address. */ #include "hidminiport.h" NTSTATUS DriverEntry ( _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ) { NTSTATUS Status; HID_MINIDRIVER_REGISTRATION HIDMinidriverRegistration; ULONG i; //Trace("Driver Entry"); //Set Function Pointers for IRPs for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) { DriverObject->MajorFunction[i] = PassThrough; } //Special for PnP DriverObject->MajorFunction[IRP_MJ_PNP] = PnPPassThrough; DriverObject->DriverExtension->AddDevice = AddDevice; DriverObject->DriverUnload = Unload; //Register as HID Minidriver RtlZeroMemory(&HIDMinidriverRegistration, sizeof(HIDMinidriverRegistration)); HIDMinidriverRegistration.Revision = HID_REVISION; HIDMinidriverRegistration.DriverObject = DriverObject; HIDMinidriverRegistration.RegistryPath = RegistryPath; HIDMinidriverRegistration.DeviceExtensionSize = 0; HIDMinidriverRegistration.DevicesArePolled = FALSE; Status = HidRegisterMinidriver(&HIDMinidriverRegistration); if (!NT_SUCCESS(Status) ){ return Status; } return Status; } NTSTATUS AddDevice( _In_ PDRIVER_OBJECT DriverObject, _In_ PDEVICE_OBJECT FunctionalDeviceObject ) { UNREFERENCED_PARAMETER(DriverObject); //Trace("Add Device"); FunctionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; return STATUS_SUCCESS; } NTSTATUS PassThrough( _In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp ) { //Trace("Pass Through"); IoCopyCurrentIrpStackLocationToNext(Irp); return IoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp); } /* NTSTATUS SendAddressesCompeted( _In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_opt_ PVOID Context ) { UNREFERENCED_PARAMETER(DeviceObject); Trace("Send Addresses Completed"); if(Context != NULL) { ExFreePoolWithTag(Context, IOCTL_POOL_TAG); } IoFreeIrp(Irp); return STATUS_SUCCESS; } */ NTSTATUS SendAddresses( _In_ PDEVICE_OBJECT DeviceObject ) { NTSTATUS Status = STATUS_SUCCESS; PIRP NewIrp; IO_STATUS_BLOCK StatusBlock; HID_MINIPORT_ADDRESSES AddressesBuffer; UNREFERENCED_PARAMETER(DeviceObject); Trace("Sending Addresses!"); /*AddressesBuffer = (PHID_MINIPORT_ADDRESSES)ExAllocatePoolWithTag(NonPagedPool, sizeof(HID_MINIPORT_ADDRESSES), IOCTL_POOL_TAG); if(AddressesBuffer == NULL) { Trace("Couldn't allocate Addresses Buffer"); return STATUS_SUCCESS; } RtlSecureZeroMemory(AddressesBuffer, sizeof(HID_MINIPORT_ADDRESSES)); */ AddressesBuffer.FDO = DeviceObject; AddressesBuffer.HidNotifyPresence = HidNotifyPresence; NewIrp = IoBuildDeviceIoControlRequest(IOCTL_WIIMOTE_ADDRESSES, GET_NEXT_DEVICE_OBJECT(DeviceObject), &AddressesBuffer, sizeof(HID_MINIPORT_ADDRESSES), NULL, 0, TRUE, NULL, &StatusBlock); if(NewIrp == NULL) { Trace("Couldn't Build IRP"); return Status; } //IoSetCompletionRoutine(NewIrp, SendAddressesCompeted, AddressesBuffer, TRUE, TRUE, TRUE); Status = IoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), NewIrp); if(!NT_SUCCESS(Status)) { if(Status == STATUS_PENDING) { Trace("SendAddress IoCallDriver is Pending!"); } else { Trace("SendAddress IoCallDriver: 0x%x", Status); } return Status; } Trace("Sending Addresses returned!"); return Status; } NTSTATUS PnPPassThrough( _In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp ) { NTSTATUS Status = STATUS_SUCCESS; PIO_STACK_LOCATION StackLocation = IoGetCurrentIrpStackLocation(Irp); UCHAR MinorFunction = StackLocation->MinorFunction; //Trace("MinorFunction: %x", MinorFunction); IoCopyCurrentIrpStackLocationToNext(Irp); Status = IoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp); if(!NT_SUCCESS(Status)) { return Status; } if(MinorFunction == IRP_MN_START_DEVICE) { Trace("Device Start"); Status = SendAddresses(DeviceObject); if(!NT_SUCCESS(Status)) { return Status; } } return Status; } VOID Unload( _In_ PDRIVER_OBJECT DriverObject ) { UNREFERENCED_PARAMETER(DriverObject); return; } ================================================ FILE: HID Miniport/Hidminiport.h ================================================ /* Copyright (C) 2014 Julian Lhr All rights reserved. Filename: hidminiport.c Abstract: Header file for hidminiport.c */ #ifndef _HIDMINIPORT_H_ #define _HIDMINIPORT_H_ #include #include #include "Trace.h" DRIVER_INITIALIZE DriverEntry; DRIVER_ADD_DEVICE AddDevice; _Dispatch_type_(IRP_MJ_OTHER) DRIVER_DISPATCH PassThrough; //IO_COMPLETION_ROUTINE SendAddressesCompeted; _Dispatch_type_(IRP_MJ_POWER) DRIVER_DISPATCH PowerPassThrough; _Dispatch_type_(IRP_MJ_PNP) DRIVER_DISPATCH PnPPassThrough; DRIVER_UNLOAD Unload; #define GET_NEXT_DEVICE_OBJECT(DO) (((PHID_DEVICE_EXTENSION)(DO)->DeviceExtension)->NextDeviceObject) #define IOCTL_WIIMOTE_ADDRESSES CTL_CODE(FILE_DEVICE_KEYBOARD, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_POOL_TAG '_WOI' typedef NTSTATUS (*PNOTIFY_PRESENCE)(PDEVICE_OBJECT, BOOLEAN); typedef struct _HID_MINIPORT_ADDRESSES { PDEVICE_OBJECT FDO; PNOTIFY_PRESENCE HidNotifyPresence; } HID_MINIPORT_ADDRESSES, * PHID_MINIPORT_ADDRESSES; #endif ================================================ FILE: HID Miniport/Trace.c ================================================ /* Copyright (C) 2013 Julian Lhr All rights reserved. Filename: Trace.c Abstract: Contains the code for Tracing. */ #include "Trace.h" VOID Trace( _In_ PCCHAR DebugMessage, ... ) { #ifndef DBG UNREFERENCED_PARAMETER(DebugMessage); #else NTSTATUS Status; va_list ParameterList; CHAR DebugMessageBuffer[512]; va_start(ParameterList, DebugMessage); if(DebugMessage != NULL) { Status = RtlStringCbVPrintfA(DebugMessageBuffer, sizeof(DebugMessageBuffer), DebugMessage, ParameterList); if(NT_SUCCESS(Status)) { DbgPrint("Trace Miniport: %s\n", DebugMessageBuffer); } } va_end(ParameterList); #endif } ================================================ FILE: HID Miniport/Trace.h ================================================ /* Copyright (C) 2013 Julian Lhr All rights reserved. Filename: Trace.h Abstract: Header file for Trace.c Contains declarations and configuration for Tracing. */ #ifndef _TRACE_H_ #define _TRACE_H_ #include #define NTSTRSAFE_LIB #include VOID Trace( _In_ PCCHAR DebugMessage, ... ); #endif ================================================ FILE: HID Miniport/resource.h ================================================ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by HID Miniport.rc // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 101 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif ================================================ FILE: HID Wiimote/Bluetooth.c ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: Bluetooth.c Abstract: Contains all Bluetooth relevant functions. Like establishing the connection, reading and writing, closing the connection to the device and Bluetooth error handling. */ #include "Bluetooth.h" #include "Device.h" EVT_WDF_REQUEST_COMPLETION_ROUTINE ControlChannelCompletion; EVT_WDF_REQUEST_COMPLETION_ROUTINE InterruptChannelCompletion; VOID L2CAPCallback(_In_ PVOID Context, _In_ INDICATION_CODE Indication, _In_ PINDICATION_PARAMETERS Parameters); EVT_WDF_REQUEST_COMPLETION_ROUTINE TransferToDeviceCompletion; EVT_WDF_REQUEST_COMPLETION_ROUTINE ReadFromDeviceCompletion; NTSTATUS GetVendorAndProductID( _In_ WDFIOTARGET IoTarget, _Out_ USHORT * VendorID, _Out_ USHORT * ProductID ) { NTSTATUS Status = STATUS_SUCCESS; WDF_MEMORY_DESCRIPTOR EnumInfoMemDescriptor; BTH_ENUMERATOR_INFO EnumInfo; RtlZeroMemory(&EnumInfo, sizeof(EnumInfo)); WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&EnumInfoMemDescriptor, &EnumInfo, sizeof(EnumInfo)); Status = WdfIoTargetSendInternalIoctlSynchronously( IoTarget, NULL, IOCTL_INTERNAL_BTHENUM_GET_ENUMINFO, NULL, &EnumInfoMemDescriptor, NULL, NULL); if (!NT_SUCCESS(Status)) { return Status; } (*ProductID) = EnumInfo.Pid; (*VendorID) = EnumInfo.Vid; return Status; } NTSTATUS BluetoothPrepare( _In_ PDEVICE_CONTEXT DeviceContext ) { NTSTATUS Status = STATUS_SUCCESS; PBLUETOOTH_DEVICE_CONTEXT BluetoothContext = &(DeviceContext->BluetoothContext); WDF_MEMORY_DESCRIPTOR DeviceInfoMemDescriptor; BTH_DEVICE_INFO DeviceInfo; BluetoothContext->ControlChannelHandle = NULL; BluetoothContext->InterruptChannelHandle = NULL; // Get Interfaces Status = WdfFdoQueryForInterface( DeviceContext->Device, &GUID_BTHDDI_PROFILE_DRIVER_INTERFACE, (PINTERFACE)(&(BluetoothContext->ProfileDriverInterface)), sizeof(BluetoothContext->ProfileDriverInterface), BTHDDI_PROFILE_DRIVER_INTERFACE_VERSION_FOR_QI, NULL); if (!NT_SUCCESS(Status)) { return Status; } // Get BluetoothAdress RtlZeroMemory(&DeviceInfo, sizeof(DeviceInfo)); WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&DeviceInfoMemDescriptor, &DeviceInfo, sizeof(DeviceInfo)); Status = WdfIoTargetSendInternalIoctlSynchronously( DeviceContext->IoTarget, NULL, IOCTL_INTERNAL_BTHENUM_GET_DEVINFO, NULL, &DeviceInfoMemDescriptor, NULL, NULL); if (!NT_SUCCESS(Status)) { return Status; } BluetoothContext->DeviceAddress = DeviceInfo.address; Status = RtlStringCchPrintfW(BluetoothContext->DeviceAddressStringBuffer, BLUETOOTH_ADDRESS_STRING_SIZE, L"%012I64x", DeviceInfo.address); if (!NT_SUCCESS(Status)) { return Status; } Status = RtlUnicodeStringInit(&BluetoothContext->DeviceAddressString, BluetoothContext->DeviceAddressStringBuffer); if (!NT_SUCCESS(Status)) { return Status; } size_t NameLength; Status = RtlStringCbLengthA(DeviceInfo.name, BTH_MAX_NAME_SIZE, &NameLength); if (!NT_SUCCESS(Status)) { return Status; } Status = RtlUTF8ToUnicodeN(BluetoothContext->DeviceNameStringBuffer, BTH_MAX_NAME_SIZE * sizeof(WCHAR), NULL, DeviceInfo.name, (ULONG)NameLength); if (!NT_SUCCESS(Status)) { return Status; } Status = RtlUnicodeStringInit(&BluetoothContext->DeviceNameString, BluetoothContext->DeviceNameStringBuffer); if (!NT_SUCCESS(Status)) { return Status; } return Status; } NTSTATUS CreateRequest( _In_ WDFDEVICE Device, _In_ WDFIOTARGET IoTarget, _Outptr_ WDFREQUEST * Request ) { NTSTATUS Status = STATUS_SUCCESS; WDF_OBJECT_ATTRIBUTES Attributes; WDF_OBJECT_ATTRIBUTES_INIT(&Attributes); Attributes.ParentObject = Device; Status = WdfRequestCreate(&Attributes, IoTarget, Request); if(!NT_SUCCESS(Status)) { return Status; } return Status; } NTSTATUS CreateBuffer( _In_ WDFREQUEST Request, _In_ SIZE_T BufferSize, _Outptr_ WDFMEMORY * Memory, _Outptr_opt_result_buffer_(BufferSize) PVOID * Buffer ) { NTSTATUS Status = STATUS_SUCCESS; WDF_OBJECT_ATTRIBUTES Attributes; WDF_OBJECT_ATTRIBUTES_INIT(&Attributes); Attributes.ParentObject = Request; Status = WdfMemoryCreate(&Attributes, NonPagedPool, BUFFER_POOL_TAG, BufferSize, Memory, Buffer); if(!NT_SUCCESS(Status)) { return Status; } return Status; } NTSTATUS BluetoothCreateRequestAndBuffer( _In_ WDFDEVICE Device, _In_ WDFIOTARGET IoTarget, _In_ SIZE_T BufferSize, _Outptr_ WDFREQUEST * Request, _Outptr_ WDFMEMORY * Memory, _Outptr_opt_result_buffer_(BufferSize) PVOID * Buffer ) { NTSTATUS Status = STATUS_SUCCESS; Status = CreateRequest(Device, IoTarget, Request); if(!NT_SUCCESS(Status)) { return Status; } Status = CreateBuffer((*Request), BufferSize, Memory, Buffer); if(!NT_SUCCESS(Status)) { WdfObjectDelete(*Request); (*Request) = NULL; return Status; } return Status; } NTSTATUS PrepareRequest( _In_ WDFIOTARGET IoTarget, _In_ PBRB BRB, _In_ WDFREQUEST Request ) { NTSTATUS Status = STATUS_SUCCESS; WDF_OBJECT_ATTRIBUTES MemoryAttributes; WDFMEMORY Memory = NULL; WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); MemoryAttributes.ParentObject = Request; Status = WdfMemoryCreatePreallocated( &MemoryAttributes, BRB, sizeof(*BRB), &Memory ); if(!NT_SUCCESS(Status)) { return Status; } Status = WdfIoTargetFormatRequestForInternalIoctlOthers( IoTarget, Request, IOCTL_INTERNAL_BTH_SUBMIT_BRB, Memory, //OtherArg1 NULL, //OtherArg1Offset NULL, //OtherArg2 NULL, //OtherArg2Offset NULL, //OtherArg4 NULL //OtherArg4Offset ); if(!NT_SUCCESS(Status)) { return Status; } return Status; } NTSTATUS SendBRB( _In_ PDEVICE_CONTEXT DeviceContext, _In_opt_ WDFREQUEST OptRequest, _In_ PBRB BRB, _In_ PFN_WDF_REQUEST_COMPLETION_ROUTINE CompletionRoutine ) { NTSTATUS Status = STATUS_SUCCESS; WDFREQUEST Request; if(OptRequest == NULL) { Status = CreateRequest(DeviceContext->Device, DeviceContext->IoTarget, &Request); if(!NT_SUCCESS(Status)) { return Status; } } else { Request = OptRequest; } Status = PrepareRequest(DeviceContext->IoTarget, BRB, Request); if(!NT_SUCCESS(Status)) { WdfObjectDelete(Request); return Status; } WdfRequestSetCompletionRoutine( Request, CompletionRoutine, BRB ); if(!WdfRequestSend( Request, DeviceContext->IoTarget, WDF_NO_SEND_OPTIONS )) { Status = WdfRequestGetStatus(Request); WdfObjectDelete(Request); return Status; } return Status; } NTSTATUS SendBRBSynchronous( _In_ PDEVICE_CONTEXT DeviceContext, _In_opt_ WDFREQUEST OptRequest, _In_ PBRB BRB ) { NTSTATUS Status = STATUS_SUCCESS; WDF_REQUEST_SEND_OPTIONS SendOptions; WDFREQUEST Request; if(OptRequest == NULL) { Status = CreateRequest(DeviceContext->Device, DeviceContext->IoTarget, &Request); if(!NT_SUCCESS(Status)) { return Status; } } else { Request = OptRequest; } Status = PrepareRequest(DeviceContext->IoTarget, BRB, Request); if(!NT_SUCCESS(Status)) { WdfObjectDelete(Request); return Status; } Status = WdfRequestAllocateTimer(Request); if(!NT_SUCCESS(Status)) { WdfObjectDelete(Request); return Status; } WDF_REQUEST_SEND_OPTIONS_INIT(&SendOptions, WDF_REQUEST_SEND_OPTION_SYNCHRONOUS | WDF_REQUEST_SEND_OPTION_TIMEOUT); WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&SendOptions, SYNCHRONOUS_CALL_TIMEOUT); WdfRequestSend( Request, DeviceContext->IoTarget, &SendOptions ); Status = WdfRequestGetStatus(Request); if(!NT_SUCCESS(Status)) { WdfObjectDelete(Request); return Status; } return Status; } VOID CleanUpCompletedRequest( _In_ WDFREQUEST Request, _In_ WDFIOTARGET IoTarget, _In_ WDFCONTEXT Context ) { PDEVICE_CONTEXT DeviceContext; PBLUETOOTH_DEVICE_CONTEXT BluetoothContext; PBRB UsedBRB; DeviceContext = GetDeviceContext(WdfIoTargetGetDevice(IoTarget)); BluetoothContext = &(DeviceContext->BluetoothContext); UsedBRB = (PBRB)Context; WdfObjectDelete(Request); BluetoothContext->ProfileDriverInterface.BthFreeBrb(UsedBRB); } VOID L2CAPCallback( _In_ PVOID Context, _In_ INDICATION_CODE Indication, _In_ PINDICATION_PARAMETERS Parameters ) { //WDF_DEVICE_STATE NewDeviceState; PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)Context; //UNREFERENCED_PARAMETER(Context); UNREFERENCED_PARAMETER(Parameters); Trace("L2CAP Channel Callback"); Trace("Indication: %u", Indication); if(Indication == IndicationRemoteDisconnect) { //Wiimote has disconnected. //Code has to be added to signal the PnP-Manager that the device is gone. Trace("Disconnect"); Trace("Parameter: %u; %u", Parameters->Parameters.Disconnect.Reason, Parameters->Parameters.Disconnect.CloseNow); WiimoteReset(DeviceContext); SignalDeviceIsGone(DeviceContext); //WDF_DEVICE_STATE_INIT (&NewDeviceState); //HidNotifyPresence(WdfDeviceWdmGetDeviceObject(DeviceContext->Device), FALSE); //WdfDeviceGetDeviceState(DeviceContext->Device, &NewDeviceState); //NewDeviceState.Removed = WdfTrue; //WdfDeviceSetDeviceState(DeviceContext->Device, &NewDeviceState); //WdfPdoMarkMissing(DeviceContext->Device); } } NTSTATUS OpenChannel( _In_ PDEVICE_CONTEXT DeviceContext, _In_opt_ PBRB PreAllocatedBRB, _In_ BYTE PSM, _In_opt_ PFNBTHPORT_INDICATION_CALLBACK ChannelCallback, _In_ PFN_WDF_REQUEST_COMPLETION_ROUTINE ChannelCompletion ) { NTSTATUS Status = STATUS_SUCCESS; PBLUETOOTH_DEVICE_CONTEXT BluetoothContext = &(DeviceContext->BluetoothContext); PBRB_L2CA_OPEN_CHANNEL BRBOpenChannel; //Create or reuse BRB if(PreAllocatedBRB == NULL) { BRBOpenChannel = (PBRB_L2CA_OPEN_CHANNEL)BluetoothContext->ProfileDriverInterface.BthAllocateBrb(BRB_L2CA_OPEN_CHANNEL, BLUETOOTH_POOL_TAG); if (BRBOpenChannel == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } } else { BluetoothContext->ProfileDriverInterface.BthReuseBrb(PreAllocatedBRB, BRB_L2CA_OPEN_CHANNEL); BRBOpenChannel = (PBRB_L2CA_OPEN_CHANNEL)PreAllocatedBRB; } //Fill BRB BRBOpenChannel->BtAddress = BluetoothContext->DeviceAddress; BRBOpenChannel->Psm = PSM; //0x13 BRBOpenChannel->ChannelFlags = 0; BRBOpenChannel->ConfigOut.Flags = 0; BRBOpenChannel->ConfigOut.Mtu.Max = L2CAP_DEFAULT_MTU; BRBOpenChannel->ConfigOut.Mtu.Min = L2CAP_MIN_MTU; BRBOpenChannel->ConfigOut.Mtu.Preferred = L2CAP_DEFAULT_MTU; BRBOpenChannel->ConfigOut.FlushTO.Max = L2CAP_DEFAULT_FLUSHTO; BRBOpenChannel->ConfigOut.FlushTO.Min = L2CAP_MIN_FLUSHTO; BRBOpenChannel->ConfigOut.FlushTO.Preferred = L2CAP_DEFAULT_FLUSHTO; BRBOpenChannel->ConfigOut.ExtraOptions = 0; BRBOpenChannel->ConfigOut.NumExtraOptions = 0; BRBOpenChannel->ConfigOut.LinkTO = 0; BRBOpenChannel->IncomingQueueDepth = 50; BRBOpenChannel->ReferenceObject = (PVOID) WdfDeviceWdmGetDeviceObject(DeviceContext->Device); if(ChannelCallback != NULL) { BRBOpenChannel->CallbackFlags = CALLBACK_DISCONNECT; BRBOpenChannel->Callback = ChannelCallback; //L2CAPCallback; BRBOpenChannel->CallbackContext = (PVOID)DeviceContext; } //SendBRB Status = SendBRB(DeviceContext, NULL, (PBRB)BRBOpenChannel, ChannelCompletion); if(!NT_SUCCESS(Status)) { BluetoothContext->ProfileDriverInterface.BthFreeBrb((PBRB)BRBOpenChannel); return Status; } return Status; } VOID ControlChannelCompletion( _In_ WDFREQUEST Request, _In_ WDFIOTARGET IoTarget, _In_ PWDF_REQUEST_COMPLETION_PARAMS Params, _In_ WDFCONTEXT Context ) { NTSTATUS Status = STATUS_SUCCESS; PDEVICE_CONTEXT DeviceContext; PBLUETOOTH_DEVICE_CONTEXT BluetoothContext; PBRB_L2CA_OPEN_CHANNEL UsedBRBOpenChannel; DeviceContext = GetDeviceContext(WdfIoTargetGetDevice(IoTarget)); BluetoothContext = &(DeviceContext->BluetoothContext); UsedBRBOpenChannel = (PBRB_L2CA_OPEN_CHANNEL)Context; Status = Params->IoStatus.Status; TraceStatus("Control Channel Result", Status); if(!NT_SUCCESS(Status)) { CleanUpCompletedRequest(Request, IoTarget, Context); if(Status == STATUS_IO_TIMEOUT) { SignalDeviceIsGone(DeviceContext); } else { WdfDeviceSetFailed(DeviceContext->Device, WdfDeviceFailedNoRestart); } return; } BluetoothContext->ControlChannelHandle = UsedBRBOpenChannel->ChannelHandle; CleanUpCompletedRequest(Request, IoTarget, Context); // Open Interrupt Channel OpenChannel(DeviceContext, NULL, 0x13, L2CAPCallback, InterruptChannelCompletion); } VOID InterruptChannelCompletion( _In_ WDFREQUEST Request, _In_ WDFIOTARGET IoTarget, _In_ PWDF_REQUEST_COMPLETION_PARAMS Params, _In_ WDFCONTEXT Context ) { NTSTATUS Status = STATUS_SUCCESS; PDEVICE_CONTEXT DeviceContext; PBLUETOOTH_DEVICE_CONTEXT BluetoothContext; PBRB_L2CA_OPEN_CHANNEL UsedBRBOpenChannel; DeviceContext = GetDeviceContext(WdfIoTargetGetDevice(IoTarget)); BluetoothContext = &(DeviceContext->BluetoothContext); UsedBRBOpenChannel = (PBRB_L2CA_OPEN_CHANNEL)Context; Status = Params->IoStatus.Status; TraceStatus("Interrupt Channel Result", Status); if(!NT_SUCCESS(Status)) { CleanUpCompletedRequest(Request, IoTarget, Context); if(Status == STATUS_IO_TIMEOUT) { SignalDeviceIsGone(DeviceContext); } else { WdfDeviceSetFailed(DeviceContext->Device, WdfDeviceFailedNoRestart); } return; } BluetoothContext->InterruptChannelHandle = UsedBRBOpenChannel->ChannelHandle; CleanUpCompletedRequest(Request, IoTarget, Context); // Start Wiimote functionality WiimoteStart(DeviceContext); } NTSTATUS BluetoothOpenChannels( _In_ PDEVICE_CONTEXT DeviceContext ) { return OpenChannel(DeviceContext, NULL, 0x11, NULL, ControlChannelCompletion); } NTSTATUS CloseChannel( _In_ PDEVICE_CONTEXT DeviceContext, _In_ L2CAP_CHANNEL_HANDLE ChannelHandle ) { NTSTATUS Status = STATUS_SUCCESS; PBLUETOOTH_DEVICE_CONTEXT BluetoothContext = &(DeviceContext->BluetoothContext); PBRB_L2CA_CLOSE_CHANNEL BRBCloseChannel; if(ChannelHandle == NULL) { Trace("Close Channel: Handle is NULL"); return Status; } BRBCloseChannel = (PBRB_L2CA_CLOSE_CHANNEL)BluetoothContext->ProfileDriverInterface.BthAllocateBrb(BRB_L2CA_CLOSE_CHANNEL, BLUETOOTH_POOL_TAG); if (BRBCloseChannel == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } BRBCloseChannel->BtAddress = BluetoothContext->DeviceAddress; BRBCloseChannel->ChannelHandle = ChannelHandle; Status = SendBRBSynchronous(DeviceContext, NULL, (PBRB)BRBCloseChannel); BluetoothContext->ProfileDriverInterface.BthFreeBrb((PBRB)BRBCloseChannel); return Status; } NTSTATUS BluetoothCloseChannels( _In_ PDEVICE_CONTEXT DeviceContext ) { PBLUETOOTH_DEVICE_CONTEXT BluetoothContext = &(DeviceContext->BluetoothContext); CloseChannel(DeviceContext, BluetoothContext->InterruptChannelHandle); BluetoothContext->InterruptChannelHandle = NULL; CloseChannel(DeviceContext, BluetoothContext->ControlChannelHandle); BluetoothContext->ControlChannelHandle = NULL; return STATUS_SUCCESS; } NTSTATUS BluetoothTransferToDevice( _In_ PDEVICE_CONTEXT DeviceContext, _In_ WDFREQUEST Request, _In_ WDFMEMORY Memory, _In_ BOOLEAN Synchronous ) { NTSTATUS Status = STATUS_SUCCESS; PBLUETOOTH_DEVICE_CONTEXT BluetoothContext = &(DeviceContext->BluetoothContext); PBRB_L2CA_ACL_TRANSFER BRBTransfer; size_t BufferSize; if(BluetoothContext->InterruptChannelHandle == NULL) { return STATUS_INVALID_HANDLE; } // Now get an BRB and fill it BRBTransfer = (PBRB_L2CA_ACL_TRANSFER)BluetoothContext->ProfileDriverInterface.BthAllocateBrb(BRB_L2CA_ACL_TRANSFER, BLUETOOTH_POOL_TAG); if (BRBTransfer == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } BRBTransfer->BtAddress = BluetoothContext->DeviceAddress; BRBTransfer->ChannelHandle = BluetoothContext->InterruptChannelHandle; BRBTransfer->TransferFlags = ACL_TRANSFER_DIRECTION_OUT; BRBTransfer->BufferMDL = NULL; BRBTransfer->Buffer = WdfMemoryGetBuffer(Memory, &BufferSize); BRBTransfer->BufferSize = (ULONG)BufferSize; //Send if(Synchronous) { Status = SendBRBSynchronous(DeviceContext, Request, (PBRB)BRBTransfer); BluetoothContext->ProfileDriverInterface.BthFreeBrb((PBRB)BRBTransfer); if(!NT_SUCCESS(Status)) { return Status; } } else { Status = SendBRB(DeviceContext, Request, (PBRB)BRBTransfer, TransferToDeviceCompletion); if(!NT_SUCCESS(Status)) { BluetoothContext->ProfileDriverInterface.BthFreeBrb((PBRB)BRBTransfer); return Status; } } return Status; } VOID TransferToDeviceCompletion( _In_ WDFREQUEST Request, _In_ WDFIOTARGET IoTarget, _In_ PWDF_REQUEST_COMPLETION_PARAMS Params, _In_ WDFCONTEXT Context ) { UNREFERENCED_PARAMETER(Params); CleanUpCompletedRequest(Request, IoTarget, Context); } NTSTATUS ReadFromDevice( _In_ PDEVICE_CONTEXT DeviceContext, _In_ WDFREQUEST Request, _In_ PBRB_L2CA_ACL_TRANSFER BRB, _In_reads_(ReadBufferSize) PVOID ReadBuffer, _In_ SIZE_T ReadBufferSize ) { NTSTATUS Status = STATUS_SUCCESS; PBLUETOOTH_DEVICE_CONTEXT BluetoothContext = &(DeviceContext->BluetoothContext); if(BluetoothContext->InterruptChannelHandle == NULL) { return STATUS_INVALID_HANDLE; } BRB->BtAddress = BluetoothContext->DeviceAddress; BRB->ChannelHandle = BluetoothContext->InterruptChannelHandle; BRB->TransferFlags = ACL_TRANSFER_DIRECTION_IN | ACL_SHORT_TRANSFER_OK; BRB->BufferMDL = NULL; BRB->Buffer = ReadBuffer; BRB->BufferSize = (ULONG)ReadBufferSize; Status = SendBRB(DeviceContext, Request, (PBRB)BRB, ReadFromDeviceCompletion); if(!NT_SUCCESS(Status)) { TraceStatus("SendBRB Failed", Status); return Status; } return Status; } VOID ReadFromDeviceCompletion( _In_ WDFREQUEST Request, _In_ WDFIOTARGET IoTarget, _In_ PWDF_REQUEST_COMPLETION_PARAMS Params, _In_ WDFCONTEXT Context ) { NTSTATUS Status = STATUS_SUCCESS; PDEVICE_CONTEXT DeviceContext; PBLUETOOTH_DEVICE_CONTEXT BluetoothContext; PVOID ReadBuffer; size_t ReadBufferSize; PBRB_L2CA_ACL_TRANSFER BRB; WDF_REQUEST_REUSE_PARAMS RequestReuseParams; DeviceContext = GetDeviceContext(WdfIoTargetGetDevice(IoTarget)); BluetoothContext = &(DeviceContext->BluetoothContext); BRB = (PBRB_L2CA_ACL_TRANSFER)Context; Status = Params->IoStatus.Status; //TraceStatus("ReadFromDeviceCompletion Result", Status); if(!NT_SUCCESS(Status)) { WdfObjectDelete(Request); return; } ReadBuffer = BRB->Buffer; ReadBufferSize = BRB->BufferSize; //Trace("RawBuffer: %08x", (*(UINT64 * )ReadBuffer)); //Trace("BufferSize: %d - RemainingBufferSize: %d", BRB->BufferSize, BRB->RemainingBufferSize); //Call Wiimote Read Callback Status = WiimoteProcessReport(DeviceContext, ReadBuffer, (ReadBufferSize - BRB->RemainingBufferSize)); if(!NT_SUCCESS(Status)) { WdfObjectDelete(Request); return; } //Reset all Object for reuse BluetoothContext->ProfileDriverInterface.BthReuseBrb((PBRB)BRB, BRB_L2CA_ACL_TRANSFER); WDF_REQUEST_REUSE_PARAMS_INIT(&RequestReuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_SUCCESS); Status = WdfRequestReuse(Request, &RequestReuseParams); if(!NT_SUCCESS(Status)) { WdfObjectDelete(Request); return; } RtlSecureZeroMemory(ReadBuffer, ReadBufferSize); //Send out new Read Status = ReadFromDevice(DeviceContext, Request, BRB, ReadBuffer, BluetoothContext->ReadBufferSize); if(!NT_SUCCESS(Status)) { return; } } NTSTATUS BluetoothStartContiniousReader( _In_ PDEVICE_CONTEXT DeviceContext ) { CONST size_t ReadBufferSize = 50; NTSTATUS Status = STATUS_SUCCESS; WDFREQUEST Request; WDFMEMORY Memory; PBRB BRB; PBLUETOOTH_DEVICE_CONTEXT BluetoothContext = &(DeviceContext->BluetoothContext); PVOID ReadBuffer = NULL; Trace("StartContiniousReader"); //Create Report And Buffer Status = BluetoothCreateRequestAndBuffer(DeviceContext->Device, DeviceContext->IoTarget, ReadBufferSize, &Request, &Memory, &ReadBuffer); if(!NT_SUCCESS(Status)) { TraceStatus("CreateRequestAndBuffer Failed", Status); return Status; } // Safe the Buffer Size BluetoothContext->ReadBufferSize = ReadBufferSize; // Create BRB BRB = BluetoothContext->ProfileDriverInterface.BthAllocateBrb(BRB_L2CA_ACL_TRANSFER, BLUETOOTH_POOL_TAG); if (BRB == NULL) { WdfObjectDelete(Request); return STATUS_INSUFFICIENT_RESOURCES; } //Start the Reader Status = ReadFromDevice(DeviceContext, Request, (PBRB_L2CA_ACL_TRANSFER)BRB, ReadBuffer, ReadBufferSize); if(!NT_SUCCESS(Status)) { return Status; } return Status; } ================================================ FILE: HID Wiimote/Bluetooth.h ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: Bluetooth.h Abstract: Header file for Bluetooth.c */ #pragma once #include "HIDWiimote.h" #include #include #include #include #include #include #include #define BLUETOOTH_POOL_TAG '_htB' #define BUFFER_POOL_TAG '_fuB' #define SYNCHRONOUS_CALL_TIMEOUT (-1000000000) // 1 Second #define BLUETOOTH_ADDRESS_STRING_SIZE 17 typedef struct _BLUETOOTH_DEVICE_CONTEXT { BTH_PROFILE_DRIVER_INTERFACE ProfileDriverInterface; BTH_ADDR DeviceAddress; UNICODE_STRING DeviceAddressString; WCHAR DeviceAddressStringBuffer[BLUETOOTH_ADDRESS_STRING_SIZE]; UNICODE_STRING DeviceNameString; WCHAR DeviceNameStringBuffer[BTH_MAX_NAME_SIZE]; L2CAP_CHANNEL_HANDLE ControlChannelHandle; L2CAP_CHANNEL_HANDLE InterruptChannelHandle; size_t ReadBufferSize; } BLUETOOTH_DEVICE_CONTEXT, * PBLUETOOTH_DEVICE_CONTEXT; typedef struct _BRB_L2CA_OPEN_CHANNEL * PBRB_L2CA_OPEN_CHANNEL; typedef struct _BRB_L2CA_CLOSE_CHANNEL * PBRB_L2CA_CLOSE_CHANNEL; typedef struct _BRB_L2CA_ACL_TRANSFER * PBRB_L2CA_ACL_TRANSFER; NTSTATUS GetVendorAndProductID(_In_ WDFIOTARGET IoTarget, _Out_ USHORT * VendorID, _Out_ USHORT * ProductID); NTSTATUS BluetoothPrepare(_In_ PDEVICE_CONTEXT DeviceContext); NTSTATUS BluetoothOpenChannels(_In_ PDEVICE_CONTEXT DeviceContext); NTSTATUS BluetoothCloseChannels(_In_ PDEVICE_CONTEXT DeviceContext); NTSTATUS BluetoothCreateRequestAndBuffer(_In_ WDFDEVICE Device, _In_ WDFIOTARGET IoTarget, _In_ SIZE_T BufferSize, _Outptr_ WDFREQUEST * Request, _Outptr_ WDFMEMORY * Memory, _Outptr_opt_result_buffer_(BufferSize) PVOID * Buffer); NTSTATUS BluetoothTransferToDevice(_In_ PDEVICE_CONTEXT DeviceContext, _In_ WDFREQUEST Request, _In_ WDFMEMORY Memory, _In_ BOOLEAN Synchronous); NTSTATUS BluetoothStartContiniousReader(_In_ PDEVICE_CONTEXT DeviceContext); ================================================ FILE: HID Wiimote/Device.c ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: Device.c Abstract: Contains all system callbacks regarding a devices pnp and power states. */ #include "Device.h" NTSTATUS DeviceAdd( _In_ WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit ) { NTSTATUS Status = STATUS_SUCCESS; WDF_OBJECT_ATTRIBUTES Attributes; WDF_PNPPOWER_EVENT_CALLBACKS PnpPowerCallbacks; WDFDEVICE Device; PDEVICE_CONTEXT DevContext; UNREFERENCED_PARAMETER(Driver); Trace("Device Added"); // Driver is filter WdfFdoInitSetFilter(DeviceInit); // Configure PnP Functions WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&PnpPowerCallbacks); PnpPowerCallbacks.EvtDevicePrepareHardware = PrepareHardware; PnpPowerCallbacks.EvtDeviceReleaseHardware = ReleaseHardware; PnpPowerCallbacks.EvtDeviceD0Entry = DeviceD0Entry; PnpPowerCallbacks.EvtDeviceD0Exit = DeviceD0Exit; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &PnpPowerCallbacks); // Configure Device Context WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, DEVICE_CONTEXT); //Create Device Object Status = WdfDeviceCreate(&DeviceInit, &Attributes, &Device); if(!NT_SUCCESS(Status)) { return Status; } //Initialize DeviceContext DevContext = GetDeviceContext(Device); DevContext->Device = Device; // Create IO Queue Status = HIDCreateQueues(Device, DevContext); if(!NT_SUCCESS(Status)) { Trace("Device Added Error On CreateQueues Result: 0x%x", Status); return Status; } // Create Settings Device Interface Status = DeviceInterfaceCreate(DevContext); if (!NT_SUCCESS(Status)) { TraceStatus("Error Creating Device Interface", Status); return Status; } TraceStatus("Device Added Result", Status); return Status; } NTSTATUS PrepareHardware( _In_ WDFDEVICE Device, _In_ WDFCMRESLIST ResourcesRaw, _In_ WDFCMRESLIST ResourcesTranslated ) { NTSTATUS Status = STATUS_SUCCESS; PDEVICE_CONTEXT DeviceContext; UNREFERENCED_PARAMETER(ResourcesRaw); UNREFERENCED_PARAMETER(ResourcesTranslated); Trace("PrepareHardware"); DeviceContext = GetDeviceContext(Device); DeviceContext->IoTarget = WdfDeviceGetIoTarget(Device); //Initialize Bluetooth Status = BluetoothPrepare(DeviceContext); if(!NT_SUCCESS(Status)) { return Status; } //Initialize HID Status = HIDPrepare(DeviceContext); if(!NT_SUCCESS(Status)) { return Status; } //Initialize Wiimote Status = WiimotePrepare(DeviceContext); if(!NT_SUCCESS(Status)) { return Status; } TraceStatus("PrepareHardware Result", Status); return Status; } NTSTATUS DeviceD0Entry( _In_ WDFDEVICE Device, _In_ WDF_POWER_DEVICE_STATE PreviousState ) { NTSTATUS Status = STATUS_SUCCESS; PDEVICE_CONTEXT DeviceContext; UNREFERENCED_PARAMETER(PreviousState); Trace("Device D0 Entry"); DeviceContext = GetDeviceContext(Device); RtlSecureZeroMemory(&(DeviceContext->HIDMiniportAddresses), sizeof(HID_MINIPORT_ADDRESSES)); Status = BluetoothOpenChannels(DeviceContext); if(!NT_SUCCESS(Status)) { return Status; } TraceStatus("Device D0 Entry Result", Status); return Status; } NTSTATUS DeviceD0Exit( _In_ WDFDEVICE Device, _In_ WDF_POWER_DEVICE_STATE TargetState ) { NTSTATUS Status = STATUS_SUCCESS; PDEVICE_CONTEXT DeviceContext; UNREFERENCED_PARAMETER(TargetState); Trace("Exit D0; Target: %x", TargetState); DeviceContext = GetDeviceContext(Device); //Suspend Wiimote Status = WiimoteStop(DeviceContext); if (!NT_SUCCESS(Status)) { TraceStatus("Error Stopping Wiimote", Status); } //Close BluetoothConnection Status = BluetoothCloseChannels(DeviceContext); if (!NT_SUCCESS(Status)) { TraceStatus("Error Closing Bluetooth Connections", Status); } TraceStatus("Exit D0 Result", Status); return Status; } NTSTATUS ReleaseHardware( _In_ WDFDEVICE Device, _In_ WDFCMRESLIST ResourcesTranslated ) { NTSTATUS Status = STATUS_SUCCESS; PDEVICE_CONTEXT DeviceContext; UNREFERENCED_PARAMETER(ResourcesTranslated); Trace("Releasee Hardware"); DeviceContext = GetDeviceContext(Device); Status = DeviceInterfaceRelease(DeviceContext->SettingsInterfaceContext); if (!NT_SUCCESS(Status)) { TraceStatus("Error Releaseing Device Interface", Status); } Status = HIDRelease(DeviceContext); if (!NT_SUCCESS(Status)) { TraceStatus("Error Releaseing HID", Status); } TraceStatus("Releasee Hardware Result", Status); return Status; } VOID SetHIDMiniportAddresses( _In_ PDEVICE_CONTEXT DeviceContext, _In_ PHID_MINIPORT_ADDRESSES Addresses ) { DeviceContext->HIDMiniportAddresses.FDO = Addresses->FDO; DeviceContext->HIDMiniportAddresses.HidNotifyPresence = Addresses->HidNotifyPresence; } NTSTATUS SignalDeviceIsGone( _In_ PDEVICE_CONTEXT DeviceContext ) { NTSTATUS Status = STATUS_SUCCESS; if((DeviceContext->HIDMiniportAddresses.FDO != NULL) && (DeviceContext->HIDMiniportAddresses.HidNotifyPresence != NULL)) { Status = (DeviceContext->HIDMiniportAddresses.HidNotifyPresence)((DeviceContext->HIDMiniportAddresses.FDO), FALSE); TraceStatus("Signaling Device is Gone", Status); } return Status; } ================================================ FILE: HID Wiimote/Device.h ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: Device.h Abstract: Header file for Device.c */ #pragma once #include "HIDWiimote.h" #include "DeviceInterface.h" #include "Wiimote.h" #include "Bluetooth.h" #include "HID.h" typedef struct _DEVICE_CONTEXT { WDFDEVICE Device; WDFIOTARGET IoTarget; PDEVICE_INTERFACE_CONTEXT SettingsInterfaceContext; BLUETOOTH_DEVICE_CONTEXT BluetoothContext; HID_DEVICE_CONTEXT HIDContext; WIIMOTE_DEVICE_CONTEXT WiimoteContext; HID_MINIPORT_ADDRESSES HIDMiniportAddresses; } DEVICE_CONTEXT, * PDEVICE_CONTEXT; WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, GetDeviceContext) EVT_WDF_DRIVER_DEVICE_ADD DeviceAdd; EVT_WDF_DEVICE_PREPARE_HARDWARE PrepareHardware; EVT_WDF_DEVICE_D0_ENTRY DeviceD0Entry; EVT_WDF_DEVICE_D0_EXIT DeviceD0Exit; EVT_WDF_DEVICE_RELEASE_HARDWARE ReleaseHardware; VOID SetHIDMiniportAddresses(_In_ PDEVICE_CONTEXT DeviceContext, _In_ PHID_MINIPORT_ADDRESSES Addresses); NTSTATUS SignalDeviceIsGone(_In_ PDEVICE_CONTEXT DeviceContext); ================================================ FILE: HID Wiimote/DeviceInterface.c ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: DeviceInterface.c Abstract: Contains code for the RawPDO used as Device Interface. Handles all incomming IOCTLs. */ #include "DeviceInterface.h" #include "Device.h" #include "DeviceInterfacePublic.h" typedef VOID DRIVER_MODE_SETTING_SETTER(_In_ PDEVICE_CONTEXT DeviceContext, _In_ WIIMOTE_DRIVER_MODE Value); typedef VOID BOOLEAN_SETTING_SETTER(_In_ PDEVICE_CONTEXT DeviceContext, _In_ BOOLEAN Value); // {7D180E63-2CAC-4112-B3D4-C42275CA497E} DEFINE_GUID(GUID_DEVCLASS_HIDWIIMOTE, 0x7d180e63, 0x2cac, 0x4112, 0xb3, 0xd4, 0xc4, 0x22, 0x75, 0xca, 0x49, 0x7e); WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_INTERFACE_CONTEXT, GetDeviceInterfaceContext); NTSTATUS CreateSettingsInterfaceQueues(_In_ PDEVICE_INTERFACE_CONTEXT DeviceInterfaceContext); EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL DeviceInterfaceDeviceControlCallback; EVT_READ_IO_CONTROL_BUFFER_FILL_BUFFER DeviceInterfaceFillReadBufferCallback; VOID ProcessGetState(_In_ WDFREQUEST Request, _In_ PDEVICE_INTERFACE_CONTEXT DeviceInterfaceContext); VOID ForwardReadStatusRequest(_In_ WDFREQUEST Request, _In_ PDEVICE_INTERFACE_CONTEXT DeviceInterfaceContext); VOID ProcessSetDriverModeSetting(_In_ WDFREQUEST Request, _In_ PDEVICE_INTERFACE_CONTEXT DeviceInterfaceContext, _In_ DRIVER_MODE_SETTING_SETTER DriverModeSettingSetter); VOID ProcessSetBooleanSetting(_In_ WDFREQUEST Request, _In_ PDEVICE_INTERFACE_CONTEXT DeviceInterfaceContext, _In_ BOOLEAN_SETTING_SETTER BooleanSettingSetter); VOID FillStateIoControlData(_In_ PWIIMOTE_STATE_IOCTL_DATA StateData, _In_ PWIIMOTE_DEVICE_CONTEXT WiimoteContext); VOID FillStatusIoControlData(_In_ PWIIMOTE_STATUS_IOCTL_DATA StatusData, _In_ PWIIMOTE_DEVICE_CONTEXT WiimoteContext); NTSTATUS DeviceInterfaceCreate(_In_ PDEVICE_CONTEXT ParentDeviceContext) { NTSTATUS Status = STATUS_SUCCESS; PWDFDEVICE_INIT DeviceInit; WDF_OBJECT_ATTRIBUTES Attributes; WDFDEVICE InterfaceDevice; PDEVICE_INTERFACE_CONTEXT DeviceInterfaceContext; WDF_DEVICE_PNP_CAPABILITIES PnpCapabilities; WDF_DEVICE_STATE DeviceState; DECLARE_CONST_UNICODE_STRING(DeviceID, L"{398128C0-7830-4B53-BA84-1E02F05EFFB0}\\HIDWiimoteInterface"); DECLARE_CONST_UNICODE_STRING(InstanceID, L"0"); DECLARE_CONST_UNICODE_STRING(DeviceText, L"HID Wiimote Settings Interface"); DECLARE_CONST_UNICODE_STRING(DeviceLocation, L"Somewhere in Kernel Space"); // Allocate and setup DeviceInit DeviceInit = WdfPdoInitAllocate(ParentDeviceContext->Device); if (DeviceInit == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } // Assing custom Device Class Status = WdfPdoInitAssignRawDevice(DeviceInit, &GUID_DEVCLASS_HIDWIIMOTE); if (!NT_SUCCESS(Status)) { WdfDeviceInitFree(DeviceInit); return Status; } // Device ID Status = WdfPdoInitAssignDeviceID(DeviceInit, &DeviceID); if (!NT_SUCCESS(Status)) { WdfDeviceInitFree(DeviceInit); return Status; } // Instance ID (unique to its parent) Status = WdfPdoInitAssignInstanceID(DeviceInit, &InstanceID); if (!NT_SUCCESS(Status)) { WdfDeviceInitFree(DeviceInit); return Status; } // Default Device Name and Location shown in Device Manager Status = WdfPdoInitAddDeviceText(DeviceInit, &DeviceText, &DeviceLocation, 0x409); if (!NT_SUCCESS(Status)) { WdfDeviceInitFree(DeviceInit); return Status; } WdfPdoInitSetDefaultLocale(DeviceInit, 0x409); // Set our Device Interface Context WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, DEVICE_INTERFACE_CONTEXT); // Create the raw PDO Status = WdfDeviceCreate(&DeviceInit, &Attributes, &InterfaceDevice); if (!NT_SUCCESS(Status)) { TraceStatus("Error creating raw PDO for Settings Interface", Status); WdfDeviceInitFree(DeviceInit); return Status; } // Initialize Raw Context DeviceInterfaceContext = GetDeviceInterfaceContext(InterfaceDevice); DeviceInterfaceContext->InterfaceDevice = InterfaceDevice; DeviceInterfaceContext->Parent = ParentDeviceContext; // Plug'n'Play Settings WDF_DEVICE_PNP_CAPABILITIES_INIT(&PnpCapabilities); PnpCapabilities.Removable = WdfTrue; PnpCapabilities.SurpriseRemovalOK = WdfTrue; PnpCapabilities.NoDisplayInUI = WdfTrue; WdfDeviceSetPnpCapabilities(InterfaceDevice, &PnpCapabilities); //Hide it in Device Manager WDF_DEVICE_STATE_INIT(&DeviceState); DeviceState.DontDisplayInUI = WdfTrue; WdfDeviceSetDeviceState(InterfaceDevice, &DeviceState); // Create Device Interface Status = WdfDeviceCreateDeviceInterface(InterfaceDevice, &GUID_DEVINTERFACE_HIDWIIMOTE, NULL); if (!NT_SUCCESS(Status)) { TraceStatus("Error creating raw PDO for Settings Interface", Status); WdfObjectDelete(InterfaceDevice); return Status; } // Make Static Child Status = WdfFdoAddStaticChild(ParentDeviceContext->Device, InterfaceDevice); if (!NT_SUCCESS(Status)) { WdfObjectDelete(InterfaceDevice); return Status; } // Everything is fine, so save the Interface Context in our parent/main context ParentDeviceContext->SettingsInterfaceContext = DeviceInterfaceContext; // Create Queues Status = CreateSettingsInterfaceQueues(DeviceInterfaceContext); if (!NT_SUCCESS(Status)) { TraceStatus("Error Creating Settings Interface Queues", Status); return Status; } return STATUS_SUCCESS; } NTSTATUS CreateSettingsInterfaceQueues(_In_ PDEVICE_INTERFACE_CONTEXT DeviceInterfaceContext) { NTSTATUS Status = STATUS_SUCCESS; WDF_IO_QUEUE_CONFIG DefaultQueueConfig; // Default IO Queue WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&DefaultQueueConfig, WdfIoQueueDispatchSequential); DefaultQueueConfig.EvtIoDeviceControl = DeviceInterfaceDeviceControlCallback; Status = WdfIoQueueCreate(DeviceInterfaceContext->InterfaceDevice, &DefaultQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &DeviceInterfaceContext->DefaultIOQueue); if (!NT_SUCCESS(Status)) { TraceStatus("Failed to create Default IO Queue for Settings Interface Device", Status); return Status; } // Read Buffer Queue Status = ReadIoControlBufferCreate( &DeviceInterfaceContext->ReadBuffer, DeviceInterfaceContext->InterfaceDevice, DeviceInterfaceContext->Parent, DeviceInterfaceFillReadBufferCallback, sizeof(WIIMOTE_STATUS_IOCTL_DATA)); if (!NT_SUCCESS(Status)) { TraceStatus("Creating Device Interface Read Buffer failed", Status); return Status; } return STATUS_SUCCESS; } NTSTATUS DeviceInterfaceRelease( _In_ PDEVICE_INTERFACE_CONTEXT DeviceInterfaceContext ) { NTSTATUS Status = STATUS_SUCCESS; ReadIoControlBufferFlush(&DeviceInterfaceContext->ReadBuffer); return Status; } VOID DeviceInterfaceWiimoteStateUpdated(_In_ PDEVICE_CONTEXT DeviceContext) { ReadIoControlBufferDispatchRequest(&DeviceContext->SettingsInterfaceContext->ReadBuffer); } VOID DeviceInterfaceDeviceControlCallback( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode ) { UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); PDEVICE_INTERFACE_CONTEXT DeviceInterfaceContext = GetDeviceInterfaceContext(WdfIoQueueGetDevice(Queue)); switch (IoControlCode) { case IOCTL_WIIMOTE_GET_STATE: ProcessGetState(Request, DeviceInterfaceContext); break; case IOCTL_WIIMOTE_READ_STATUS: ForwardReadStatusRequest(Request, DeviceInterfaceContext); break; case IOCTL_WIIMOTE_SET_MODE: ProcessSetDriverModeSetting(Request, DeviceInterfaceContext, WiimoteSettingsSetDriverMode); break; case IOCTL_WIIMOTE_SET_ENABLE_WIIMOTE_XAXIS_ACCELEROMETER: ProcessSetBooleanSetting(Request, DeviceInterfaceContext, WiimoteSettingsSetEnableWiimoteXAxisAccelerometer); break; case IOCTL_WIIMOTE_SET_ENABLE_WIIMOTE_YAXIS_ACCELEROMETER: ProcessSetBooleanSetting(Request, DeviceInterfaceContext, WiimoteSettingsSetEnableWiimoteYAxisAccelerometer); break; case IOCTL_WIIMOTE_SET_SWITCH_MOUSEBUTTONS: ProcessSetBooleanSetting(Request, DeviceInterfaceContext, WiimoteSettingsSetSwapMouseButtons); break; case IOCTL_WIIMOTE_SET_SWITCH_TRIGGERANDSHOULDER: ProcessSetBooleanSetting(Request, DeviceInterfaceContext, WiimoteSettingsSetSwapTriggerAndShoulder); break; case IOCTL_WIIMOTE_SET_SPLIT_TRIGGERAXIS: ProcessSetBooleanSetting(Request, DeviceInterfaceContext, WiimoteSettingsSetSplitTriggerAxis); break; case IOCTL_WIIMOTE_SET_MAP_TRIGGER_AS_AXIS: ProcessSetBooleanSetting(Request, DeviceInterfaceContext, WiimoteSettingsSetMapTriggerAsAxis); break; case IOCTL_WIIMOTE_SET_MAP_TRIGGER_AS_BUTTONS: ProcessSetBooleanSetting(Request, DeviceInterfaceContext, WiimoteSettingsSetMapTriggerAsButtons); break; default: Trace("Devcice Interface recieved unknown IOCTL: %#010x", IoControlCode); WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED); } } VOID ProcessGetState( _In_ WDFREQUEST Request, _In_ PDEVICE_INTERFACE_CONTEXT DeviceInterfaceContext ) { NTSTATUS Status = STATUS_SUCCESS; PWIIMOTE_STATE_IOCTL_DATA StateData = NULL; PWIIMOTE_DEVICE_CONTEXT WiimoteContext = &(DeviceInterfaceContext->Parent->WiimoteContext); Trace("Processing IOCTL_WIIMOTE_GET_STATE"); Status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WIIMOTE_STATE_IOCTL_DATA), &StateData, NULL); if (!NT_SUCCESS(Status)) { TraceStatus("Error retrieving State Buffer", Status); WdfRequestComplete(Request, Status); return; } FillStateIoControlData(StateData, WiimoteContext); WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, sizeof(WIIMOTE_STATE_IOCTL_DATA)); } VOID ForwardReadStatusRequest( _In_ WDFREQUEST Request, _In_ PDEVICE_INTERFACE_CONTEXT DeviceInterfaceContext ) { ReadIoControlBufferForwardRequest(&DeviceInterfaceContext->ReadBuffer, Request); } VOID DeviceInterfaceFillReadBufferCallback( _In_ PDEVICE_CONTEXT DeviceContext, _Inout_updates_all_(BufferSize) PVOID Buffer, _In_ size_t BufferSize, _Out_ PSIZE_T BytesWritten) { UNREFERENCED_PARAMETER(BufferSize); FillStatusIoControlData((PWIIMOTE_STATUS_IOCTL_DATA)Buffer, &DeviceContext->WiimoteContext); (*BytesWritten) = sizeof(WIIMOTE_STATUS_IOCTL_DATA); } VOID FillStateIoControlData( _In_ PWIIMOTE_STATE_IOCTL_DATA StateData, _In_ PWIIMOTE_DEVICE_CONTEXT WiimoteContext ) { RtlZeroMemory(StateData, sizeof(WIIMOTE_STATE_IOCTL_DATA)); StateData->Settings = WiimoteContext->Settings; FillStatusIoControlData(&(StateData->Status), WiimoteContext); } VOID FillStatusIoControlData( _In_ PWIIMOTE_STATUS_IOCTL_DATA StatusData, _In_ PWIIMOTE_DEVICE_CONTEXT WiimoteContext ) { RtlZeroMemory(StatusData, sizeof(WIIMOTE_STATUS_IOCTL_DATA)); StatusData->Extension = WiimoteContext->Extension; StatusData->BatteryLevel = WiimoteContext->BatteryLevel; StatusData->LEDs = WiimoteContext->LEDState; } VOID ProcessSetDriverModeSetting( _In_ WDFREQUEST Request, _In_ PDEVICE_INTERFACE_CONTEXT DeviceInterfaceContext, _In_ DRIVER_MODE_SETTING_SETTER DriverModeSettingSetter ) { NTSTATUS Status; PWIIMOTE_DRIVER_MODE RequestedMode; Status = WdfRequestRetrieveInputBuffer(Request, sizeof(WIIMOTE_DRIVER_MODE), &RequestedMode, NULL); if (!NT_SUCCESS(Status)) { TraceStatus("Error retrieving Driver Mode Io Control Mode Input Buffer", Status); WdfRequestComplete(Request, Status); return; } DriverModeSettingSetter(DeviceInterfaceContext->Parent, *RequestedMode); WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, sizeof(WIIMOTE_DRIVER_MODE)); } VOID ProcessSetBooleanSetting( _In_ WDFREQUEST Request, _In_ PDEVICE_INTERFACE_CONTEXT DeviceInterfaceContext, _In_ BOOLEAN_SETTING_SETTER BooleanSettingSetter ) { NTSTATUS Status; PBOOLEAN RequestedValue; Status = WdfRequestRetrieveInputBuffer(Request, sizeof(BOOLEAN), &RequestedValue, NULL); if (!NT_SUCCESS(Status)) { TraceStatus("Error retrieving Driver Mode Io Control Mode Input Buffer", Status); WdfRequestComplete(Request, Status); return; } BooleanSettingSetter(DeviceInterfaceContext->Parent, *RequestedValue); WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, sizeof(BOOLEAN)); } ================================================ FILE: HID Wiimote/DeviceInterface.h ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: DeviceInterface.h Abstract: Header file for DeviceInterface.c */ #pragma once #include "HIDWiimote.h" #include "ReadIoControlBuffer.h" typedef struct _DEVICE_INTERFACE_CONTEXT { WDFDEVICE InterfaceDevice; PDEVICE_CONTEXT Parent; WDFQUEUE DefaultIOQueue; READ_IO_CONTROL_BUFFER ReadBuffer; } DEVICE_INTERFACE_CONTEXT, * PDEVICE_INTERFACE_CONTEXT; NTSTATUS DeviceInterfaceCreate(_In_ PDEVICE_CONTEXT ParentDeviceContext); NTSTATUS DeviceInterfaceRelease(_In_ PDEVICE_INTERFACE_CONTEXT DeviceInterfaceContext); VOID DeviceInterfaceWiimoteStateUpdated(_In_ PDEVICE_CONTEXT DeviceContext); ================================================ FILE: HID Wiimote/DeviceInterfacePublic.h ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: DeviceInterfacePublic.h Abstract: Shared types and values for the Device Interface, provided by the driver and used by the user mode dll. */ #pragma once #include // {8259315A-7B87-4D02-83A3-20CBCDAD7647} DEFINE_GUID(GUID_DEVINTERFACE_HIDWIIMOTE, 0x8259315a, 0x7b87, 0x4d02, 0x83, 0xa3, 0x20, 0xcb, 0xcd, 0xad, 0x76, 0x47); // IOCTLs // 0x00-0x7FF (0-2047) reserved, 0x800-0xFFF (2048-4095) for custom use #define FUNCTION_CODE(base, id) (0x800 | base | id) #define HID_WIIMOTE_CTL_CODE(base, id) CTL_CODE(FILE_DEVICE_KEYBOARD, FUNCTION_CODE(base, id), METHOD_NEITHER, FILE_ANY_ACCESS) #define HID_WIIMOTE_BUFFERED_CTL_CODE(base, id) CTL_CODE(FILE_DEVICE_KEYBOARD, FUNCTION_CODE(base, id), METHOD_BUFFERED, FILE_ANY_ACCESS) // Device #define DEVICE_IOCTL_BASE 0x000 #define IOCTL_WIIMOTE_GET_STATE HID_WIIMOTE_BUFFERED_CTL_CODE(DEVICE_IOCTL_BASE, 0x01) #define IOCTL_WIIMOTE_READ_STATUS HID_WIIMOTE_BUFFERED_CTL_CODE(DEVICE_IOCTL_BASE, 0x02) // Settings #define SETTINGS_IOCTL_BASE 0x100 #define IOCTL_WIIMOTE_SET_MODE HID_WIIMOTE_BUFFERED_CTL_CODE(SETTINGS_IOCTL_BASE, 0x01) #define IOCTL_WIIMOTE_SET_ENABLE_WIIMOTE_XAXIS_ACCELEROMETER HID_WIIMOTE_BUFFERED_CTL_CODE(SETTINGS_IOCTL_BASE, 0x02) #define IOCTL_WIIMOTE_SET_ENABLE_WIIMOTE_YAXIS_ACCELEROMETER HID_WIIMOTE_BUFFERED_CTL_CODE(SETTINGS_IOCTL_BASE, 0x03) #define IOCTL_WIIMOTE_SET_SWITCH_MOUSEBUTTONS HID_WIIMOTE_BUFFERED_CTL_CODE(SETTINGS_IOCTL_BASE, 0x04) #define IOCTL_WIIMOTE_SET_SWITCH_TRIGGERANDSHOULDER HID_WIIMOTE_BUFFERED_CTL_CODE(SETTINGS_IOCTL_BASE, 0x10) #define IOCTL_WIIMOTE_SET_SPLIT_TRIGGERAXIS HID_WIIMOTE_BUFFERED_CTL_CODE(SETTINGS_IOCTL_BASE, 0x11) #define IOCTL_WIIMOTE_SET_MAP_TRIGGER_AS_AXIS HID_WIIMOTE_BUFFERED_CTL_CODE(SETTINGS_IOCTL_BASE, 0x12) #define IOCTL_WIIMOTE_SET_MAP_TRIGGER_AS_BUTTONS HID_WIIMOTE_BUFFERED_CTL_CODE(SETTINGS_IOCTL_BASE, 0x13) // LEDs #define WIIMOTE_LEDS_ONE (0x10) #define WIIMOTE_LEDS_TWO (0x20) #define WIIMOTE_LEDS_THREE (0x40) #define WIIMOTE_LEDS_FOUR (0x80) #define WIIMOTE_LEDS_ALL (WIIMOTE_LEDS_FOUR | WIIMOTE_LEDS_THREE | WIIMOTE_LEDS_TWO | WIIMOTE_LEDS_ONE) // Enumerations typedef enum _WIIMOTE_EXTENSION { None, Nunchuck, BalanceBoard, ClassicController, ClassicControllerPro, WiiUProController, Guitar } WIIMOTE_EXTENSION, *PWIIMOTE_EXTENSION; typedef enum _WIIMOTE_DRIVER_MODE { Gamepad, PassThrough, IRMouse, DPadMouse, GamepadAndIRMouse } WIIMOTE_DRIVER_MODE, *PWIIMOTE_DRIVER_MODE; // IOCTL data structs typedef struct _WIIMOTE_SETTINGS { WIIMOTE_DRIVER_MODE Mode; BOOLEAN EnableWiimoteXAxisAccelerometer; BOOLEAN EnableWiimoteYAxisAcceleromenter; BOOLEAN SwapMouseButtons; BOOLEAN SwapTriggerAndShoulder; BOOLEAN SplitTriggerAxis; BOOLEAN MapTriggerAsAxis; BOOLEAN MapTriggerAsButtons; } WIIMOTE_SETTINGS, *PWIIMOTE_SETTINGS; typedef struct _WIIMOTE_STATUS_IOCTL_DATA { UCHAR LEDs; UCHAR BatteryLevel; WIIMOTE_EXTENSION Extension; } WIIMOTE_STATUS_IOCTL_DATA, *PWIIMOTE_STATUS_IOCTL_DATA; typedef struct _WIIMOTE_STATE_IOCTL_DATA { WIIMOTE_SETTINGS Settings; WIIMOTE_STATUS_IOCTL_DATA Status; } WIIMOTE_STATE_IOCTL_DATA, *PWIIMOTE_STATE_IOCTL_DATA; ================================================ FILE: HID Wiimote/Driver.c ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: Driver.c Abstract: Contains the entry code for the Kernel Mode driver. */ #include "Driver.h" NTSTATUS DriverEntry ( _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ) { NTSTATUS Status = STATUS_SUCCESS; WDF_DRIVER_CONFIG Config; // Initialize Config WDF_DRIVER_CONFIG_INIT(&Config, DeviceAdd); // Create Driver Object Status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &Config, WDF_NO_HANDLE); return Status; } ================================================ FILE: HID Wiimote/Driver.h ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: Driver.h Abstract: Header file for Driver.c */ #pragma once #include "HIDWiimote.h" #include "Device.h" DRIVER_INITIALIZE DriverEntry; ================================================ FILE: HID Wiimote/HID Wiimote.vcxproj ================================================  Windows 10 Universal Debug Win32 Windows 10 Universal Debug x64 Windows 10 Universal Release Win32 Windows 10 Universal Release x64 Windows 10 Debug Win32 Windows 10 Release Win32 Windows 10 Debug x64 Windows 10 Release x64 {785D88E1-E758-4966-80FA-AEF74681FEF1} {1bc93793-694f-48fe-9372-81e2b05556fd} Win8 Debug Win32 HID_Wiimote Driver KMDF Windows10 true WindowsKernelModeDriver10.0 false true WindowsKernelModeDriver10.0 false Universal Windows10 false WindowsKernelModeDriver10.0 false false WindowsKernelModeDriver10.0 false Universal Windows10 true WindowsKernelModeDriver10.0 false true WindowsKernelModeDriver10.0 false Universal Windows10 false WindowsKernelModeDriver10.0 false false WindowsKernelModeDriver10.0 false Universal DbgengKernelDebugger $(SolutionDir)$(PlatformShortName)\$(ConfigurationName)\ $(PlatformShortName)\$(ConfigurationName)\ $(SolutionDir)$(PlatformShortName)\$(ConfigurationName)\ $(PlatformShortName)\$(ConfigurationName)\ $(SolutionDir)$(PlatformShortName)\$(ConfigurationName)\ $(PlatformShortName)\$(ConfigurationName)\ $(SolutionDir)$(PlatformShortName)\$(ConfigurationName)\ $(PlatformShortName)\$(ConfigurationName)\ %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib $(DeviceDriverVersion) $(DeviceDriverVersion) $(DeviceDriverVersion) $(DeviceDriverVersion) SHA256 SHA256 SHA256 SHA256 ================================================ FILE: HID Wiimote/HID Wiimote.vcxproj.backup ================================================  Win8 Debug Win32 Win8 Release Win32 Win7 Debug Win32 Win7 Release Win32 Vista Debug Win32 Vista Release Win32 Win8 Debug x64 Win8 Release x64 Win7 Debug x64 Win7 Release x64 Vista Debug x64 Vista Release x64 {785D88E1-E758-4966-80FA-AEF74681FEF1} {1bc93793-694f-48fe-9372-81e2b05556fd} v4.5 11.0 Win8 Debug Win32 HID_Wiimote $(VCTargetsPath11) WindowsKernelModeDriver8.0 Driver KMDF Windows8 true Windows8 false Windows7 true Windows7 false Vista true Vista false Windows8 true Windows8 false Windows7 true Windows7 false Vista true Vista false $(SolutionDir)$(PlatformShortName)\$(ConfigurationName)\ $(PlatformShortName)\$(ConfigurationName)\ DbgengKernelDebugger $(SolutionDir)$(PlatformShortName)\$(ConfigurationName)\ $(PlatformShortName)\$(ConfigurationName)\ $(SolutionDir)$(PlatformShortName)\$(ConfigurationName)\ $(PlatformShortName)\$(ConfigurationName)\ $(SolutionDir)$(PlatformShortName)\$(ConfigurationName)\ $(PlatformShortName)\$(ConfigurationName)\ $(SolutionDir)$(PlatformShortName)\$(ConfigurationName)\ $(PlatformShortName)\$(ConfigurationName)\ $(SolutionDir)$(PlatformShortName)\$(ConfigurationName)\ $(PlatformShortName)\$(ConfigurationName)\ true trace.h true %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib %(AdditionalDependencies);$(DDK_LIB_PATH)\hidclass.lib;$(DDK_LIB_PATH)\ntstrsafe.lib NotSet ================================================ FILE: HID Wiimote/HID Wiimote.vcxproj.filters ================================================  {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms {8E41214B-6785-4CFE-B992-037D68949A14} inf;inv;inx;mof;mc; {5159a567-d541-480d-953f-e3c93dffcaa2} {c20eef7d-9f93-4c18-9f99-bfb2145ed4a5} {ec536e52-2b68-45dd-a902-0321278a5e69} {90c8726a-976d-46bc-ac3c-1b98dbd789d8} {5a23eaec-7eab-4ec8-a970-9d4d31de22de} {a11a5e1a-29a3-478a-a65f-6a59c0e0acf7} Driver Files Device Bluetooth Wiimote HID HID HID Driver Utilities Device Utilities Wiimote Wiimote Device Bluetooth Wiimote HID HID HID Driver Driver Utilities Utilities Device Utilities Wiimote Wiimote Device Resource Files ================================================ FILE: HID Wiimote/HID.c ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: HID.c Abstract: Contains IOQueues and HID specific functions. Handles all HID Requests and translates the Wiimote State into HID reports. */ #include "HID.h" #include "Device.h" #include "Bluetooth.h" #include "HIDDescriptors.h" #include "WiimoteToHIDParser.h" EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL HIDInternalDeviceControlCallback; EVT_READ_IO_CONTROL_BUFFER_FILL_BUFFER HIDFillReadBufferCallback; VOID ProcessGetDeviceDescriptor(_In_ WDFREQUEST Request); VOID ProcessGetReportDescriptor(_In_ WDFREQUEST Request); VOID ProcessGetDeviceAttributes(_In_ WDFREQUEST Request,_In_ PHID_DEVICE_CONTEXT HIDContext); VOID ProcessGetString(_In_ WDFREQUEST Request, _In_ PDEVICE_CONTEXT DeviceContext); VOID ForwardReadReportRequest(_In_ WDFREQUEST Request, _In_ PDEVICE_CONTEXT DeviceContext); VOID ProcessAddresses(_In_ WDFREQUEST Request, _In_ PDEVICE_CONTEXT DeviceContext); NTSTATUS HIDPrepare( _In_ PDEVICE_CONTEXT DeviceContext ) { NTSTATUS Status = STATUS_SUCCESS; Status = GetVendorAndProductID(DeviceContext->IoTarget, &(DeviceContext->HIDContext.VendorID), &(DeviceContext->HIDContext.ProductID)); if(!NT_SUCCESS(Status)) { return Status; } return Status; } NTSTATUS HIDCreateQueues( _In_ WDFDEVICE Device, _In_ PDEVICE_CONTEXT DeviceContext ) { NTSTATUS Status; WDF_IO_QUEUE_CONFIG QueueConfig; PHID_DEVICE_CONTEXT HIDContext = &DeviceContext->HIDContext; // Create Default Queue WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&QueueConfig, WdfIoQueueDispatchParallel); QueueConfig.EvtIoInternalDeviceControl = HIDInternalDeviceControlCallback; Status = WdfIoQueueCreate(Device, &QueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &(HIDContext->DefaultIOQueue)); if(!NT_SUCCESS(Status)) { TraceStatus("Creating DefaultIOQueue failed", Status); return Status; } // Create Read Buffer Queue Status = ReadIoControlBufferCreate(&HIDContext->ReadBuffer, DeviceContext->Device, DeviceContext, HIDFillReadBufferCallback, sizeof(HID_GAMEPAD_REPORT)); if (!NT_SUCCESS(Status)) { TraceStatus("Creating HID Read Buffer failed", Status); return Status; } return Status; } PHID_DEVICE_CONTEXT GetHIDContext( _In_ WDFQUEUE Queue ) { return &(GetDeviceContext(WdfIoQueueGetDevice(Queue))->HIDContext); } VOID HIDInternalDeviceControlCallback( _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength, _In_ ULONG IoControlCode ) { UNREFERENCED_PARAMETER(Queue); UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); switch(IoControlCode) { case IOCTL_HID_GET_DEVICE_DESCRIPTOR: ProcessGetDeviceDescriptor(Request); break; case IOCTL_HID_GET_DEVICE_ATTRIBUTES: ProcessGetDeviceAttributes(Request, GetHIDContext(Queue)); break; case IOCTL_HID_GET_REPORT_DESCRIPTOR: ProcessGetReportDescriptor(Request); break; case IOCTL_HID_GET_STRING: ProcessGetString(Request, GetDeviceContext(WdfIoQueueGetDevice(Queue))); break; case IOCTL_HID_READ_REPORT: ForwardReadReportRequest(Request, GetDeviceContext(WdfIoQueueGetDevice(Queue))); break; case IOCTL_WIIMOTE_ADDRESSES: ProcessAddresses(Request, GetDeviceContext(WdfIoQueueGetDevice(Queue))); break; default: Trace("Unknown IOCTL: %x", IoControlCode); WdfRequestComplete(Request, STATUS_NOT_SUPPORTED); } } VOID ProcessGetDeviceDescriptor( _In_ WDFREQUEST Request ) { NTSTATUS Status; WDFMEMORY Memory; // Get Memory Status = WdfRequestRetrieveOutputMemory(Request, &Memory); if(!NT_SUCCESS(Status)) { WdfRequestComplete(Request, Status); return; } // Copy Status = WdfMemoryCopyFromBuffer(Memory, 0, (PVOID)&HIDDescriptor, HIDDescriptor.bLength); if(!NT_SUCCESS(Status)) { WdfRequestComplete(Request, Status); return; } // Complete Request WdfRequestCompleteWithInformation(Request, Status, HIDDescriptor.bLength); } VOID ProcessGetDeviceAttributes( _In_ WDFREQUEST Request, _In_ PHID_DEVICE_CONTEXT HIDContext ) { NTSTATUS Status; PHID_DEVICE_ATTRIBUTES DeviceAttributes = NULL; size_t DeviceAttributesSize = sizeof(HID_DEVICE_ATTRIBUTES); // Get Buffer Status = WdfRequestRetrieveOutputBuffer(Request, DeviceAttributesSize, (PVOID *)&DeviceAttributes, NULL); if(!NT_SUCCESS(Status)) { WdfRequestComplete(Request, Status); return; } // Fill out DeviceAttributes->Size = (ULONG)DeviceAttributesSize; DeviceAttributes->VendorID = HIDContext->VendorID; DeviceAttributes->ProductID = HIDContext->ProductID; DeviceAttributes->VersionNumber = 0x0000; // Complete Request WdfRequestCompleteWithInformation(Request, Status, DeviceAttributesSize); } VOID ProcessGetReportDescriptor( _In_ WDFREQUEST Request ) { NTSTATUS Status; WDFMEMORY Memory; size_t ReportDescriptorSize = HIDReportDescriptorSize; // Get Memory Status = WdfRequestRetrieveOutputMemory(Request, &Memory); if(!NT_SUCCESS(Status)) { WdfRequestComplete(Request, Status); return; } // Copy Status = WdfMemoryCopyFromBuffer(Memory, 0, (PVOID)&HIDReportDescriptor, ReportDescriptorSize); if(!NT_SUCCESS(Status)) { WdfRequestComplete(Request, Status); return; } // Complete Request WdfRequestCompleteWithInformation(Request, Status, ReportDescriptorSize); } VOID ProcessGetString( _In_ WDFREQUEST Request, _In_ PDEVICE_CONTEXT DeviceContext ) { NTSTATUS Status; WDF_REQUEST_PARAMETERS Parameters; WDFMEMORY Memory; PUNICODE_STRING String = NULL; WDF_REQUEST_PARAMETERS_INIT(&Parameters); WdfRequestGetParameters(Request, &Parameters); Status = WdfRequestRetrieveOutputMemory(Request, &Memory); if (!NT_SUCCESS(Status)) { WdfRequestComplete(Request, Status); return; } switch (((UINT_PTR)Parameters.Parameters.DeviceIoControl.Type3InputBuffer) & 0xFF) { case HID_STRING_ID_IPRODUCT: String = &DeviceContext->BluetoothContext.DeviceNameString; break; case HID_STRING_ID_IMANUFACTURER: WdfRequestComplete(Request, STATUS_NOT_SUPPORTED); return; case HID_STRING_ID_ISERIALNUMBER: String = &DeviceContext->BluetoothContext.DeviceAddressString; break; } Status = WdfMemoryCopyFromBuffer(Memory, 0, (PVOID)String->Buffer, String->MaximumLength); if (!NT_SUCCESS(Status)) { WdfRequestComplete(Request, Status); return; } // Complete Request WdfRequestCompleteWithInformation(Request, Status, String->MaximumLength); } VOID ForwardReadReportRequest( _In_ WDFREQUEST Request, _In_ PDEVICE_CONTEXT DeviceContext ) { ReadIoControlBufferForwardRequest(&DeviceContext->HIDContext.ReadBuffer, Request); } NTSTATUS HIDRelease( _In_ PDEVICE_CONTEXT DeviceContext ) { NTSTATUS Status = STATUS_SUCCESS; PHID_DEVICE_CONTEXT HIDContext = &(DeviceContext->HIDContext); ReadIoControlBufferFlush(&HIDContext->ReadBuffer); return Status; } VOID HIDFillReadBufferCallback( _In_ PDEVICE_CONTEXT DeviceContext, _Inout_updates_all_(BufferSize) PVOID Buffer, _In_ size_t BufferSize, _Out_ PSIZE_T BytesWritten) { PWIIMOTE_DEVICE_CONTEXT WiimoteContext = &(DeviceContext->WiimoteContext); (*BytesWritten) = 0; switch (WiimoteContext->Settings.Mode) { case Gamepad: ParseWiimoteStateAsGamepad(WiimoteContext, Buffer, BufferSize, BytesWritten); break; case PassThrough: break; case IRMouse: ParseWiimoteStateAsIRMouse(&(WiimoteContext->State), Buffer, BufferSize, BytesWritten); break; case DPadMouse: ParseWiimoteStateAsDPadMouse(&(WiimoteContext->State), Buffer, BufferSize, BytesWritten); break; case GamepadAndIRMouse: if (!DeviceContext->HIDContext.GamepadAndIRMouseReportToggleFlag) { ParseWiimoteStateAsIRMouse(&(WiimoteContext->State), Buffer, BufferSize, BytesWritten); DeviceContext->HIDContext.GamepadAndIRMouseReportToggleFlag = !DeviceContext->HIDContext.GamepadAndIRMouseReportToggleFlag; ReadIoControlBufferDispatchRequest(&(DeviceContext->HIDContext.ReadBuffer)); } else { ParseWiimoteStateAsGamepad(WiimoteContext, Buffer, BufferSize, BytesWritten); DeviceContext->HIDContext.GamepadAndIRMouseReportToggleFlag = !DeviceContext->HIDContext.GamepadAndIRMouseReportToggleFlag; } break; } } VOID HIDWiimoteStateUpdated( _In_ PDEVICE_CONTEXT DeviceContext ) { ReadIoControlBufferDispatchRequest(&(DeviceContext->HIDContext.ReadBuffer)); } VOID ProcessAddresses( _In_ WDFREQUEST Request, _In_ PDEVICE_CONTEXT DeviceContext ) { NTSTATUS Status = STATUS_SUCCESS; PHID_MINIPORT_ADDRESSES Addresses = NULL; Trace("Adresses recieved"); Status = WdfRequestRetrieveInputBuffer(Request, sizeof(HID_MINIPORT_ADDRESSES), (PVOID *)&Addresses, NULL); if(!NT_SUCCESS(Status)) { TraceStatus("Couldn't retrieve Input Buffer", Status); WdfRequestComplete(Request, STATUS_SUCCESS); return; } SetHIDMiniportAddresses(DeviceContext, Addresses); WdfRequestComplete(Request, STATUS_SUCCESS); } ================================================ FILE: HID Wiimote/HID.h ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: HID.h Abstract: Header file for HID.c */ #pragma once #include "HIDWiimote.h" #include #include "ReadIoControlBuffer.h" typedef struct _HID_DEVICE_CONTEXT { WDFQUEUE DefaultIOQueue; READ_IO_CONTROL_BUFFER ReadBuffer; USHORT VendorID; USHORT ProductID; BOOLEAN GamepadAndIRMouseReportToggleFlag; } HID_DEVICE_CONTEXT, * PHID_DEVICE_CONTEXT; typedef UCHAR HID_REPORT_DESCRIPTOR, *PHID_REPORT_DESCRIPTOR; NTSTATUS HIDPrepare(_In_ PDEVICE_CONTEXT DeviceContext); NTSTATUS HIDCreateQueues(_In_ WDFDEVICE Device, _In_ PDEVICE_CONTEXT DeviceContext); NTSTATUS HIDRelease(_In_ PDEVICE_CONTEXT DeviceContext); VOID HIDWiimoteStateUpdated(_In_ PDEVICE_CONTEXT DeviceContext); #define IOCTL_WIIMOTE_ADDRESSES CTL_CODE(FILE_DEVICE_KEYBOARD, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) ================================================ FILE: HID Wiimote/HIDDescriptors.c ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: HIDDescriptor.c Abstract: Contains the definition of several HID Descriptors */ #include "HIDDescriptors.h" CONST HID_REPORT_DESCRIPTOR HIDReportDescriptor[] = { 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x05, // USAGE (Game Pad) 0xa1, 0x01, // COLLECTION (Application) /* |-----------------------------| | Gamepad | |-----------------------------| |--------|-------|--------|-------|--------|-------|--------|-------| | Report ID | |--------|-------|--------|-------|--------|-------|--------|-------| | X-Axis | |--------|-------|--------|-------|--------|-------|--------|-------| | Y-Axis | |--------|-------|--------|-------|--------|-------|--------|-------| | Button 1-8 | |--------|-------|--------|-------|--------|-------|--------|-------| | Button 9-13 |xxxxxxx Padding xxxxxxxx| |--------|-------|--------|-------|--------|-------|--------|-------| | Z-Axis | |--------|-------|--------|-------|--------|-------|--------|-------| | RX-Axis | |--------|-------|--------|-------|--------|-------|--------|-------| | RY-Axis | |--------|-------|--------|-------|--------|-------|--------|-------| | RZ-Axis | |--------|-------|--------|-------|--------|-------|--------|-------| | Hat Switch | |--------|-------|--------|-------|--------|-------|--------|-------| */ 0x85, GAMEPAD_REPORT_ID, // REPORT_ID (GAMEPAD_REPORT_ID) 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x30, // USAGE (X) 0x09, 0x31, // USAGE (Y) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x26, 0xFF, 0x00, // LOGICAL_MAXIMUM (255) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x02, // REPORT_COUNT (2) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x05, 0x09, // USAGE_PAGE (Button) 0x19, 0x01, // USAGE_MINIMUM (Button 1) 0x29, 0x0D, // USAGE_MAXIMUM (Button 13) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x95, 0x0D, // REPORT_COUNT (13) 0x75, 0x01, // REPORT_SIZE (1) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x03, // REPORT_SIZE (3) 0x81, 0x03, // INPUT (Cnst,Var,Abs) 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x32, // USAGE (Z) 0x09, 0x33, // USAGE (RX) 0x09, 0x34, // USAGE (RY) 0x09, 0x35, // USAGE (RZ) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x26, 0xFF, 0x00, // LOGICAL_MAXIMUM (255) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x04, // REPORT_COUNT (4) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x39, // USAGE (Hat Swtich) 0x15, 0x01, // LOGICAL_MINIMUM (1) 0x25, 0x08, // LOGICAL_MAXIMUM (8) 0x35, 0x00, // PHYSICAL_MINIMUM (0) 0x46, 0x3b, 0x01, // PHYSICAL_MAXIMUM (315) 0x55, 0x00, // UNIT_EXPONENT (0) 0x65, 0x14, // UNIT (English Rotation: Angular Position) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x01, // REPORT_COUNT (1) 0x81, 0x4a, // INPUT (Data,Var,Abs,Wrap,Null) /* |-----------------------------| | Wiimote | |-----------------------------| */ 0xc0 // END_COLLECTION /* 0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x91, 0x00, // OUTPUT (Data,Ary,Abs) 0x85, 0x11, // REPORT_ID (11) 0x95, 0x01, // REPORT_COUNT (1) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x91, 0x00, // OUTPUT (Data,Ary,Abs) 0x85, 0x12, // REPORT_ID (12) 0x95, 0x02, // REPORT_COUNT (2) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x91, 0x00, // OUTPUT (Data,Ary,Abs) 0x85, 0x13, // REPORT_ID (13) 0x95, 0x01, // REPORT_COUNT (1) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x91, 0x00, // OUTPUT (Data,Ary,Abs) 0x85, 0x14, // REPORT_ID (14) 0x95, 0x01, // REPORT_COUNT (1) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x91, 0x00, // OUTPUT (Data,Ary,Abs) 0x85, 0x15, // REPORT_ID (15) 0x95, 0x01, // REPORT_COUNT (1) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x91, 0x00, // OUTPUT (Data,Ary,Abs) 0x85, 0x16, // REPORT_ID (16) 0x95, 0x15, // REPORT_COUNT (21) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x91, 0x00, // OUTPUT (Data,Ary,Abs) 0x85, 0x17, // REPORT_ID (17) 0x95, 0x06, // REPORT_COUNT (6) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x91, 0x00, // OUTPUT (Data,Ary,Abs) 0x85, 0x18, // REPORT_ID (18) 0x95, 0x15, // REPORT_COUNT (21) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x91, 0x00, // OUTPUT (Data,Ary,Abs) 0x85, 0x19, // REPORT_ID (19) 0x95, 0x01, // REPORT_COUNT (1) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x91, 0x00, // OUTPUT (Data,Ary,Abs) 0x85, 0x1a, // REPORT_ID (1A) 0x95, 0x01, // REPORT_COUNT (1) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x91, 0x00, // OUTPUT (Data,Ary,Abs) 0x85, 0x20, // REPORT_ID (20) 0x95, 0x06, // REPORT_COUNT (6) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0x85, 0x21, // REPORT_ID (21) 0x95, 0x15, // REPORT_COUNT (21) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0x85, 0x22, // REPORT_ID (22) 0x95, 0x04, // REPORT_COUNT (4) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0x85, 0x30, // REPORT_ID (30) 0x95, 0x02, // REPORT_COUNT (2) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0x85, 0x31, // REPORT_ID (31) 0x95, 0x05, // REPORT_COUNT (5) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0x85, 0x32, // REPORT_ID (32) 0x95, 0x0a, // REPORT_COUNT (10) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0x85, 0x33, // REPORT_ID (33) 0x95, 0x11, // REPORT_COUNT (17) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0x85, 0x34, // REPORT_ID (34) 0x95, 0x15, // REPORT_COUNT (21) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0x85, 0x35, // REPORT_ID (35) 0x95, 0x15, // REPORT_COUNT (21) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0x85, 0x36, // REPORT_ID (36) 0x95, 0x15, // REPORT_COUNT (21) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0x85, 0x37, // REPORT_ID (37) 0x95, 0x15, // REPORT_COUNT (21) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0x85, 0x3d, // REPORT_ID (3D) 0x95, 0x15, // REPORT_COUNT (21) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0x85, 0x3e, // REPORT_ID (3E) 0x95, 0x15, // REPORT_COUNT (21) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0x85, 0x3f, // REPORT_ID (3F) 0x95, 0x15, // REPORT_COUNT (21) 0x09, 0x01, // USAGE (Vendor Ussage 1) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0xc0, // END_COLLECTION /* |-----------------------------| | IR-Mouse | |-----------------------------| |--------|-------|--------|-------|--------|-------|--------|-------| | Report ID | |--------|-------|--------|-------|--------|-------|--------|-------| | Button 1-3 |xxxxxxxxxxxxxxxx Padding xxxxxxxxxxxxxxxx| |--------|-------|--------|-------|--------|-------|--------|-------| | X-Axis | |--------|-------|--------|-------|--------|-------|--------|-------| | X-Axis | |--------|-------|--------|-------|--------|-------|--------|-------| | Y-Axis | |--------|-------|--------|-------|--------|-------|--------|-------| | Y-Axis | |--------|-------|--------|-------|--------|-------|--------|-------| */ /* 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x02, // USAGE (Mouse) 0xa1, 0x01, // COLLECTION (Application) 0x09, 0x01, // USAGE (Pointer) 0x85, IRMOUSE_REPORT_ID, // REPORT_ID (IRMOUSE_REPORT_ID) 0x05, 0x09, // USAGE_PAGE (Button) 0x19, 0x01, // USAGE_MINIMUM (Button 1) 0x29, 0x03, // USAGE_MAXIMUM (Button 3) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x95, 0x03, // REPORT_COUNT (3) 0x75, 0x01, // REPORT_SIZE (1) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x05, // REPORT_SIZE (5) 0x81, 0x03, // INPUT (Cnst,Var,Abs) 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x30, // USAGE (X) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x26, 0xFF, 0x03, // LOGICAL_MAXIMUM (1023) 0x75, 0x0B, // REPORT_SIZE (11) 0x95, 0x01, // REPORT_COUNT (1) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x05, // REPORT_SIZE (5) 0x81, 0x03, // INPUT (Cnst,Var,Abs) 0x09, 0x31, // USAGE (Y) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x26, 0xFF, 0x03, // LOGICAL_MAXIMUM (1023) 0x75, 0x0B, // REPORT_SIZE (11) 0x95, 0x01, // REPORT_COUNT (1) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x05, // REPORT_SIZE (5) 0x81, 0x03, // INPUT (Cnst,Var,Abs) 0xc0, // END_COLLECTION /* |-----------------------------| | DPad-Mouse | |-----------------------------| |--------|-------|--------|-------|--------|-------|--------|-------| | Report ID | |--------|-------|--------|-------|--------|-------|--------|-------| | Button 1-3 |xxxxxxxxxxxxxxxx Padding xxxxxxxxxxxxxxxx| |--------|-------|--------|-------|--------|-------|--------|-------| | X-Axis | |--------|-------|--------|-------|--------|-------|--------|-------| | Y-Axis | |--------|-------|--------|-------|--------|-------|--------|-------| |xxxxxxxxxxxxxxxxxxxxxxxxxxxxx Padding xxxxxxxxxxxxxxxxxxxxxxxxxxxx| |--------|-------|--------|-------|--------|-------|--------|-------| */ /* 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x02, // USAGE (Mouse) 0xa1, 0x01, // COLLECTION (Application) 0x09, 0x01, // USAGE (Pointer) 0x85, DPADMOUSE_REPORT_ID, // REPORT_ID (DPADMOUSE_REPORT_ID) 0x05, 0x09, // USAGE_PAGE (Button) 0x19, 0x01, // USAGE_MINIMUM (Button 1) 0x29, 0x03, // USAGE_MAXIMUM (Button 3) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x95, 0x03, // REPORT_COUNT (3) 0x75, 0x01, // REPORT_SIZE (1) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x05, // REPORT_SIZE (5) 0x81, 0x03, // INPUT (Cnst,Var,Abs) 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x30, // USAGE (X) 0x09, 0x31, // USAGE (Y) 0x15, 0x81, // LOGICAL_MINIMUM (-127) 0x25, 0x7f, // LOGICAL_MAXIMUM (127) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x02, // REPORT_COUNT (2) 0x81, 0x06, // INPUT (Data,Var,Rel) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x08, // REPORT_SIZE (8) 0x81, 0x03, // INPUT (Cnst,Var,Abs) 0xc0 // END_COLLECTION */ }; CONST HID_DESCRIPTOR HIDDescriptor = { 0x09, // length of HID descriptor 0x21, // descriptor type == HID 0x21 0x0111, // hid spec release 0x00, // country code == Not Specified 0x01, // number of HID class descriptors { 0x22, // descriptor type sizeof(HIDReportDescriptor) // total length of report descriptor } }; CONST size_t HIDReportDescriptorSize = sizeof(HIDReportDescriptor); ================================================ FILE: HID Wiimote/HIDDescriptors.h ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: HIDDescriptor.h Abstract: Common Header file. Contains common includes and declarations. */ #pragma once #include "HID.h" #define GAMEPAD_REPORT_ID 0x01 #define IRMOUSE_REPORT_ID 0x02 #define DPADMOUSE_REPORT_ID 0x03 extern CONST HID_REPORT_DESCRIPTOR HIDReportDescriptor[]; extern CONST HID_DESCRIPTOR HIDDescriptor; extern CONST size_t HIDReportDescriptorSize; #pragma pack(push, 1) typedef struct _HID_GAMEPAD_REPORT { UCHAR ReportID; UCHAR XAxis; UCHAR YAxis; UCHAR Buttons[2]; UCHAR ZAxis; UCHAR RXAxis; UCHAR RYAxis; UCHAR RZAxis; UCHAR Hatswitch; } HID_GAMEPAD_REPORT, * PHID_GAMEPAD_REPORT; VOID FORCEINLINE HID_GAMEPAD_REPORT_INIT( _Out_ PHID_GAMEPAD_REPORT Report) { RtlZeroMemory(Report, sizeof(HID_GAMEPAD_REPORT)); Report->ReportID = GAMEPAD_REPORT_ID; Report->XAxis = 0x7F; Report->YAxis = 0x7F; Report->ZAxis = 0x7F; Report->RXAxis = 0x7F; Report->RYAxis = 0x7F; Report->RZAxis = 0x7F; } typedef struct _HID_IRMOUSE_REPORT { UCHAR ReportID; UCHAR Buttons; USHORT X; USHORT Y; } HID_IRMOUSE_REPORT, * PHID_IRMOUSE_REPORT; VOID FORCEINLINE HID_IRMOUSE_REPORT_INIT( _Out_ PHID_IRMOUSE_REPORT Report) { RtlZeroMemory(Report, sizeof(HID_IRMOUSE_REPORT)); Report->ReportID = IRMOUSE_REPORT_ID; } typedef struct _HID_DPADMOUSE_REPORT { UCHAR ReportID; UCHAR Buttons; UCHAR X; UCHAR Y; } HID_DPADMOUSE_REPORT, *PHID_DPADMOUSE_REPORT; VOID FORCEINLINE HID_DPADMOUSE_REPORT_INIT( _Out_ PHID_DPADMOUSE_REPORT Report) { RtlZeroMemory(Report, sizeof(HID_DPADMOUSE_REPORT)); Report->ReportID = DPADMOUSE_REPORT_ID; } #pragma pack(pop) ================================================ FILE: HID Wiimote/HIDWiimote.h ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: HIDWiimote.h Abstract: Common Header file. Contains common includes and declarations. */ #pragma once #include #include #include #include "Trace.h" //#define MOUSE_DPAD //#define MOUSE_IR //Forward Declarations typedef struct _DEVICE_CONTEXT DEVICE_CONTEXT, * PDEVICE_CONTEXT; typedef struct _DEVICE_INTERFACE_CONTEXT DEVICE_INTERFACE_CONTEXT, *PDEVICE_INTERFACE_CONTEXT; typedef struct _WIIMOTE_DEVICE_CONTEXT WIIMOTE_DEVICE_CONTEXT, * PWIIMOTE_DEVICE_CONTEXT; typedef struct _BLUETOOTH_DEVICE_CONTEXT BLUETOOTH_DEVICE_CONTEXT, * PBLUETOOTH_DEVICE_CONTEXT; typedef struct _HID_DEVICE_CONTEXT HID_DEVICE_CONTEXT, * PHID_DEVICE_CONTEXT; // Used by HID Layer and Device Part typedef NTSTATUS (*PNOTIFY_PRESENCE)(PDEVICE_OBJECT, BOOLEAN); typedef struct _HID_MINIPORT_ADDRESSES { PDEVICE_OBJECT FDO; PNOTIFY_PRESENCE HidNotifyPresence; } HID_MINIPORT_ADDRESSES, * PHID_MINIPORT_ADDRESSES; ================================================ FILE: HID Wiimote/ReadIoControlBuffer.c ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: ReadIoControlBuffer.c Abstract: A manual dispatch Queue to buffer read requests */ #include "ReadIoControlBuffer.h" VOID ReadIoControlBufferCompleteRequest( _In_ PREAD_IO_CONTROL_BUFFER ReadIoControlBuffer, _In_ WDFREQUEST Request ); NTSTATUS ReadIoControlBufferCreate( _Inout_ PREAD_IO_CONTROL_BUFFER ReadIoControlBuffer, _In_ WDFDEVICE ParentDevice, _In_ PDEVICE_CONTEXT DeviceContext, _In_ PFN_READ_IO_CONTROL_BUFFER_FILL_BUFFER Callback, _In_ size_t MinOutputBufferSize ) { NTSTATUS Status = STATUS_SUCCESS; WDF_IO_QUEUE_CONFIG QueueConfig; // Set up the Object ReadIoControlBuffer->DeviceContext = DeviceContext; ReadIoControlBuffer->Callback = Callback; ReadIoControlBuffer->InstantCompletion = FALSE; ReadIoControlBuffer->MinOutputBufferSize = MinOutputBufferSize; // Create the WDF Queue WDF_IO_QUEUE_CONFIG_INIT(&QueueConfig, WdfIoQueueDispatchManual); QueueConfig.PowerManaged = WdfFalse; Status = WdfIoQueueCreate(ParentDevice, &QueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &(ReadIoControlBuffer->BufferQueue)); if (!NT_SUCCESS(Status)) { TraceStatus("Failed to create Read IO Control Buffer Queue", Status); return Status; } return Status; } VOID ReadIoControlBufferFlush( _In_ PREAD_IO_CONTROL_BUFFER ReadIoControlBuffer ) { NTSTATUS Status = STATUS_SUCCESS; WDFREQUEST TmpRequest; if (ReadIoControlBuffer->BufferQueue == NULL) { return; } while (NT_SUCCESS(Status = (WdfIoQueueRetrieveNextRequest(ReadIoControlBuffer->BufferQueue, &TmpRequest)))) { WdfRequestComplete(TmpRequest, STATUS_DEVICE_REMOVED); } if (Status != STATUS_NO_MORE_ENTRIES) { TraceStatus("Something went wring while flushing a Read IO Control Buffer", Status); } } VOID ReadIoControlBufferForwardRequest( _In_ PREAD_IO_CONTROL_BUFFER ReadIoControlBuffer, _In_ WDFREQUEST Request ) { NTSTATUS Status = STATUS_SUCCESS; if (ReadIoControlBuffer->InstantCompletion) { ReadIoControlBufferCompleteRequest(ReadIoControlBuffer, Request); } else { Status = WdfRequestForwardToIoQueue(Request, ReadIoControlBuffer->BufferQueue); if (!NT_SUCCESS(Status)) { WdfRequestComplete(Request, Status); return; } } } VOID ReadIoControlBufferCompleteRequest( _In_ PREAD_IO_CONTROL_BUFFER ReadIoControlBuffer, _In_ WDFREQUEST Request ) { NTSTATUS Status = STATUS_SUCCESS; PVOID OutputBuffer; size_t OutputBufferSize; SIZE_T BytesWritten = 0; ReadIoControlBuffer->InstantCompletion = FALSE; Status = WdfRequestRetrieveOutputBuffer(Request, ReadIoControlBuffer->MinOutputBufferSize, &OutputBuffer, &OutputBufferSize); if (!NT_SUCCESS(Status)) { TraceStatus("Error retrieving Output Buffer from Read IO Control", Status); WdfRequestComplete(Request, Status); return; } ReadIoControlBuffer->Callback(ReadIoControlBuffer->DeviceContext, OutputBuffer, OutputBufferSize, &BytesWritten); WdfRequestCompleteWithInformation(Request, Status, BytesWritten); } VOID ReadIoControlBufferDispatchRequest( _In_ PREAD_IO_CONTROL_BUFFER ReadIoControlBuffer ) { NTSTATUS Status = STATUS_SUCCESS; WDFREQUEST Request; Status = WdfIoQueueRetrieveNextRequest(ReadIoControlBuffer->BufferQueue, &Request); if (NT_SUCCESS(Status)) { ReadIoControlBufferCompleteRequest(ReadIoControlBuffer, Request); } else if (Status == STATUS_NO_MORE_ENTRIES) { ReadIoControlBuffer->InstantCompletion = TRUE; } } ================================================ FILE: HID Wiimote/ReadIoControlBuffer.h ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: ReadIoControlBuffer.h Abstract: Header file for ReadIoControlBuffer.c */ #pragma once #include "HIDWiimote.h" typedef VOID EVT_READ_IO_CONTROL_BUFFER_FILL_BUFFER(_In_ PDEVICE_CONTEXT DeviceContext, _Inout_updates_all_(BufferSize) PVOID Buffer, _In_ size_t BufferSize, _Out_ PSIZE_T BytesWritten); typedef EVT_READ_IO_CONTROL_BUFFER_FILL_BUFFER *PFN_READ_IO_CONTROL_BUFFER_FILL_BUFFER; typedef struct _READ_IO_CONTROL_BUFFER { WDFQUEUE BufferQueue; PDEVICE_CONTEXT DeviceContext; PFN_READ_IO_CONTROL_BUFFER_FILL_BUFFER Callback; size_t MinOutputBufferSize; BOOLEAN InstantCompletion; } READ_IO_CONTROL_BUFFER, * PREAD_IO_CONTROL_BUFFER; NTSTATUS ReadIoControlBufferCreate( _Inout_ PREAD_IO_CONTROL_BUFFER ReadIoControlBuffer, _In_ WDFDEVICE ParentDevice, _In_ PDEVICE_CONTEXT DeviceContext, _In_ PFN_READ_IO_CONTROL_BUFFER_FILL_BUFFER Callback, _In_ size_t MinOutputBufferSize ); VOID ReadIoControlBufferFlush( _In_ PREAD_IO_CONTROL_BUFFER ReadIoControlBuffer ); VOID ReadIoControlBufferForwardRequest( _In_ PREAD_IO_CONTROL_BUFFER ReadIoControlBuffer, _In_ WDFREQUEST Request); VOID ReadIoControlBufferDispatchRequest( _In_ PREAD_IO_CONTROL_BUFFER ReadIoControlBuffer ); ================================================ FILE: HID Wiimote/Trace.c ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: Trace.c Abstract: Contains the code for Tracing. */ #include "Trace.h" VOID Trace( _In_ PCCHAR DebugMessage, ... ) { #ifndef DBG UNREFERENCED_PARAMETER(DebugMessage); #else NTSTATUS Status; va_list ParameterList; CHAR DebugMessageBuffer[512]; va_start(ParameterList, DebugMessage); if(DebugMessage != NULL) { Status = RtlStringCbVPrintfA(DebugMessageBuffer, sizeof(DebugMessageBuffer), DebugMessage, ParameterList); if(NT_SUCCESS(Status)) { DbgPrint("Trace Wiimote: %s\n", DebugMessageBuffer); } } va_end(ParameterList); #endif } VOID TraceStatus( _In_ PCCHAR DebugMessage, _In_ NTSTATUS Status ) { #ifndef DBG UNREFERENCED_PARAMETER(DebugMessage); UNREFERENCED_PARAMETER(Status); #else Trace("%s: " NTSTATUS_FORMAT_IDENTIFIER, DebugMessage, Status); #endif } VOID PrintBytes( _In_reads_(Size) PCUCHAR Data, _In_ SIZE_T Size ) { #ifndef DBG UNREFERENCED_PARAMETER(Data); UNREFERENCED_PARAMETER(Size); #else NTSTATUS Result = STATUS_SUCCESS; PCHAR Message; PCHAR WritePointer; PCUCHAR ReadPointer; const size_t BytesPerElement = 5; size_t StringBufferSize = (Size * BytesPerElement) + 1; Message = (PCHAR)ExAllocatePoolWithTag(NonPagedPool, StringBufferSize, PRINTBYTE_POOL_TAG); if (Message == NULL) { Trace("Error printing Bytes: Out of Memory"); return; } WritePointer = Message; ReadPointer = Data; for (SIZE_T i = 0; (i < Size) && (NT_SUCCESS(Result)); ++i) { Result = RtlStringCbPrintfA(WritePointer, StringBufferSize, "%#04x ", *ReadPointer); WritePointer += BytesPerElement; StringBufferSize -= BytesPerElement; ReadPointer++; } (*WritePointer) = 0; Trace("Byte Print: %s", Message); ExFreePool(Message); #endif } ================================================ FILE: HID Wiimote/Trace.h ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: Trace.h Abstract: Header file for Trace.c Contains declarations and configuration for Tracing. */ #pragma once #include #define NTSTRSAFE_LIB #include #define PRINTBYTE_POOL_TAG '_BrP' #define NTSTATUS_FORMAT_IDENTIFIER "%#010x" VOID Trace( _In_ PCCHAR DebugMessage, ... ); VOID TraceStatus( _In_ PCCHAR DebugMessage, _In_ NTSTATUS Status ); VOID PrintBytes( _In_reads_(Size) PCUCHAR Data, _In_ SIZE_T Size ); ================================================ FILE: HID Wiimote/Wiimote.c ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: Wiimote.c Abstract: Manages the Wiimote states and is the layer between HID and Bluetooth. */ #include "Wiimote.h" #include "Device.h" #include "Bluetooth.h" #include "WiimoteSettings.h" EVT_WDF_TIMER BatteryLevelLEDUpdateTimerExpired; NTSTATUS WiimotePrepare( _In_ PDEVICE_CONTEXT DeviceContext ) { NTSTATUS Status = STATUS_SUCCESS; WDF_TIMER_CONFIG TimerConfig; WDF_OBJECT_ATTRIBUTES TimerAttributes; // Reset Device WiimoteReset(DeviceContext); // Load Settings from Registry WiimoteSettingsLoad(DeviceContext); // Create Timer to request StatusInformation WDF_TIMER_CONFIG_INIT_PERIODIC(&TimerConfig, BatteryLevelLEDUpdateTimerExpired, WIIMOTE_STATUSINFORMATION_INTERVAL); WDF_OBJECT_ATTRIBUTES_INIT(&TimerAttributes); TimerAttributes.ParentObject = DeviceContext->Device; Status = WdfTimerCreate(&TimerConfig, &TimerAttributes, &(DeviceContext->WiimoteContext.BatteryLevelLEDUpdateTimer)); if(!NT_SUCCESS(Status)) { return Status; } return Status; } NTSTATUS SetLEDs( _In_ PDEVICE_CONTEXT DeviceContext, _In_ BYTE LEDFlag ) { CONST size_t BufferSize = 3; NTSTATUS Status = STATUS_SUCCESS; WDFREQUEST Request; WDFMEMORY Memory; BYTE * Data; // Save new LED State DeviceContext->WiimoteContext.LEDState = LEDFlag; // Get Resources Status = BluetoothCreateRequestAndBuffer(DeviceContext->Device, DeviceContext->IoTarget, BufferSize, &Request, &Memory, (PVOID *)&Data); if(!NT_SUCCESS(Status)) { return Status; } // Fill Buffer Data[0] = 0xA2; //HID Output Report Data[1] = 0x11; //Player LED Data[2] = LEDFlag; Status = BluetoothTransferToDevice(DeviceContext, Request, Memory, FALSE); if(!NT_SUCCESS(Status)) { return Status; } return Status; } NTSTATUS SetReportMode( _In_ PDEVICE_CONTEXT DeviceContext, _In_ BYTE ReportMode ) { CONST size_t BufferSize = 4; NTSTATUS Status = STATUS_SUCCESS; WDFREQUEST Request; WDFMEMORY Memory; BYTE * Data; // Get Resources Status = BluetoothCreateRequestAndBuffer(DeviceContext->Device, DeviceContext->IoTarget, BufferSize, &Request, &Memory, (PVOID *)&Data); if(!NT_SUCCESS(Status)) { return Status; } // Fill Buffer Data[0] = 0xA2; //HID Output Report Data[1] = 0x12; //Set ReportMode Data[2] = 0x00; //Only On Change Data[3] = ReportMode; //Mode Status = BluetoothTransferToDevice(DeviceContext, Request, Memory, FALSE); if(!NT_SUCCESS(Status)) { return Status; } DeviceContext->WiimoteContext.CurrentReportMode = ReportMode; return Status; } NTSTATUS RequestStatusInformation( _In_ PDEVICE_CONTEXT DeviceContext ) { CONST size_t BufferSize = 3; NTSTATUS Status = STATUS_SUCCESS; WDFREQUEST Request; WDFMEMORY Memory; BYTE * Data; // Get Resources Status = BluetoothCreateRequestAndBuffer(DeviceContext->Device, DeviceContext->IoTarget, BufferSize, &Request, &Memory, (PVOID *)&Data); if(!NT_SUCCESS(Status)) { return Status; } // Fill Buffer Data[0] = 0xA2; //HID Output Report Data[1] = 0x15; //Status Information Request Data[2] = 0x00; //Rumble Off Status = BluetoothTransferToDevice(DeviceContext, Request, Memory, FALSE); if(!NT_SUCCESS(Status)) { return Status; } return Status; } NTSTATUS ReadFromRegister( _In_ PDEVICE_CONTEXT DeviceContext, _In_ INT32 Address, _In_ BYTE Size ) { CONST size_t BufferSize = 8; NTSTATUS Status = STATUS_SUCCESS; WDFREQUEST Request; WDFMEMORY Memory; BYTE * Data; // Get Resources Status = BluetoothCreateRequestAndBuffer(DeviceContext->Device, DeviceContext->IoTarget, BufferSize, &Request, &Memory, (PVOID *)&Data); if (!NT_SUCCESS(Status)) { return Status; } // Fill Buffer Data[0] = 0xA2; //HID Output Report Data[1] = 0x17; //Status Information Request Data[2] = 0x04; //Rumble Off but write to Registers //Offset Data[3] = 0xFF & (Address >> 16); Data[4] = 0xFF & (Address >> 8); Data[5] = 0xFF & (Address); Data[6] = 0x00; //Size Data[7] = Size; //Size Status = BluetoothTransferToDevice(DeviceContext, Request, Memory, FALSE); if (!NT_SUCCESS(Status)) { return Status; } return Status; } NTSTATUS WriteToRegister( _In_ PDEVICE_CONTEXT DeviceContext, _In_ INT32 Address, _In_reads_(DataSize) PCUCHAR Data, _In_ BYTE DataSize ) { CONST size_t BufferSize = 23; NTSTATUS Status = STATUS_SUCCESS; WDFREQUEST Request; WDFMEMORY Memory; BYTE * Report; // Get Resources Status = BluetoothCreateRequestAndBuffer(DeviceContext->Device, DeviceContext->IoTarget, BufferSize, &Request, &Memory, (PVOID *)&Report); if (!NT_SUCCESS(Status)) { return Status; } // Fill Buffer Report[0] = 0xA2; //HID Output Report Report[1] = 0x16; //Status Information Request Report[2] = 0x04; //Rumble Off but write to Registers //Offset Report[3] = 0xFF & (Address >> 16); Report[4] = 0xFF & (Address >> 8); Report[5] = 0xFF & (Address); Report[6] = DataSize; //Size RtlSecureZeroMemory(Report + 7, 16); RtlCopyBytes(Report + 7, Data, DataSize); Status = BluetoothTransferToDevice(DeviceContext, Request, Memory, FALSE); if (!NT_SUCCESS(Status)) { return Status; } return Status; } NTSTATUS WriteSingeByteToRegister( _In_ PDEVICE_CONTEXT DeviceContext, _In_ INT32 Address, _In_ BYTE Data ) { return WriteToRegister(DeviceContext, Address, &Data, 1); } NTSTATUS SendSingleByteReport( _In_ PDEVICE_CONTEXT DeviceContext, _In_ BYTE ReportID, _In_ BYTE Byte ) { CONST size_t BufferSize = 3; NTSTATUS Status = STATUS_SUCCESS; WDFREQUEST Request; WDFMEMORY Memory; BYTE * Data; // Get Resources Status = BluetoothCreateRequestAndBuffer(DeviceContext->Device, DeviceContext->IoTarget, BufferSize, &Request, &Memory, (PVOID *)&Data); if (!NT_SUCCESS(Status)) { return Status; } // Fill Buffer Data[0] = 0xA2; //HID Output Report Data[1] = ReportID; // Enable IR Data[2] = Byte; // Get acknowledgement Status = BluetoothTransferToDevice(DeviceContext, Request, Memory, FALSE); if (!NT_SUCCESS(Status)) { return Status; } return Status; } NTSTATUS WiimoteStart( _In_ PDEVICE_CONTEXT DeviceContext ) { NTSTATUS Status = STATUS_SUCCESS; //Set LEDs Status = SetLEDs(DeviceContext, WIIMOTE_LEDS_ALL); if(!NT_SUCCESS(Status)) { return Status; } #ifdef MOUSE_IR //Enable IR Status = SendSingleByteReport(DeviceContext, 0x13, 0x06); if(!NT_SUCCESS(Status)) { TraceStatus("EnableIR Failed", Status); return Status; } #else //Set Report Mode Status = SetReportMode(DeviceContext, 0x31); if(!NT_SUCCESS(Status)) { TraceStatus("SetReportMode Failed", Status); return Status; } #endif //Start Continious Reader Status = BluetoothStartContiniousReader(DeviceContext); if(!NT_SUCCESS(Status)) { TraceStatus("StartContiniousReader Failed", Status); return Status; } //Start Timer WdfTimerStart(DeviceContext->WiimoteContext.BatteryLevelLEDUpdateTimer, WDF_REL_TIMEOUT_IN_SEC(1)); return Status; } NTSTATUS EnableIR( _In_ PDEVICE_CONTEXT DeviceContext ) { NTSTATUS Status = STATUS_SUCCESS; const BYTE SensivityBlock1[] = { 0x02, 0x00, 0x00, 0x71, 0x01, 0x00, 0xaa, 0x00, 0x64 }; const BYTE SensivityBlock2[] = { 0x63, 0x03 }; //Write 0x08 to register 0xb00030 Status = WriteSingeByteToRegister(DeviceContext, 0xb00030, 0x08); if (!NT_SUCCESS(Status)) { return Status; } //Write Sensitivity Block 1 to registers at 0xb00000 Status = WriteToRegister(DeviceContext, 0xb00000, SensivityBlock1, sizeof(SensivityBlock1)); if (!NT_SUCCESS(Status)) { return Status; } //Write Sensitivity Block 2 to registers at 0xb0001a Status = WriteToRegister(DeviceContext, 0xb0001a, SensivityBlock2, sizeof(SensivityBlock2)); if (!NT_SUCCESS(Status)) { return Status; } //Write Mode Number to register 0xb00033 //0x01 Basic Mode 10 Byte Status = WriteSingeByteToRegister(DeviceContext, 0xb00030, 0x01); if (!NT_SUCCESS(Status)) { return Status; } //Write 0x08 to register 0xb00030 (again) Status = WriteSingeByteToRegister(DeviceContext, 0xb00030, 0x08); if (!NT_SUCCESS(Status)) { return Status; } //Set Report Mode Status = SetReportMode(DeviceContext, 0x36); if (!NT_SUCCESS(Status)) { return Status; } return Status; } NTSTATUS SuspendWiimote( _In_ PDEVICE_CONTEXT DeviceContext ) { CONST size_t BufferSize = 1; NTSTATUS Status = STATUS_SUCCESS; WDFREQUEST Request; WDFMEMORY Memory; BYTE * Data; // Get Resources Status = BluetoothCreateRequestAndBuffer(DeviceContext->Device, DeviceContext->IoTarget, BufferSize, &Request, &Memory, (PVOID *)&Data); if(!NT_SUCCESS(Status)) { return Status; } // Fill Buffer Data[0] = 0x13; //HID Control with Suspend: 0x10 = HID_Control - 0x03 = SUSPEND Status = BluetoothTransferToDevice(DeviceContext, Request, Memory, TRUE); if(!NT_SUCCESS(Status)) { return Status; } WdfObjectDelete(Request); return Status; } NTSTATUS WiimoteStop( _In_ PDEVICE_CONTEXT DeviceContext ) { NTSTATUS Status = STATUS_SUCCESS; //Stop Timer WdfTimerStop(DeviceContext->WiimoteContext.BatteryLevelLEDUpdateTimer, TRUE); //Shut down Wiimote Status = SuspendWiimote(DeviceContext); if(!NT_SUCCESS(Status)) { return Status; } return Status; } VOID WiimoteReset( _In_ PDEVICE_CONTEXT DeviceContext ) { DeviceContext->WiimoteContext.Extension = None; WiimoteStateResetToNullState(DeviceContext); } NTSTATUS UpdateBatteryLEDs( _In_ PDEVICE_CONTEXT DeviceContext ) { NTSTATUS Status = STATUS_SUCCESS; PWIIMOTE_DEVICE_CONTEXT WiimoteContext = &(DeviceContext->WiimoteContext); if (WiimoteContext->Extension == BalanceBoard) { return Status; } Status = SetLEDs(DeviceContext, ((0xF0 << (3 - (DeviceContext->WiimoteContext.BatteryLevel / 64))) & 0xF0)); if (!NT_SUCCESS(Status)) { return Status; } if (DeviceContext->WiimoteContext.LEDState == WIIMOTE_LEDS_FOUR) { WdfTimerStop(WiimoteContext->BatteryLevelLEDUpdateTimer, FALSE); } return Status; } NTSTATUS InitializeExtension( _In_ PDEVICE_CONTEXT DeviceContext ) { NTSTATUS Status = STATUS_SUCCESS; Status = WriteSingeByteToRegister(DeviceContext, 0xA400F0, 0x55); if (!NT_SUCCESS(Status)) { return Status; } Status = WriteSingeByteToRegister(DeviceContext, 0xA400FB, 0x00); if (!NT_SUCCESS(Status)) { return Status; } Status = ReadFromRegister(DeviceContext, 0xA400FA, 0x06); if (!NT_SUCCESS(Status)) { return Status; } return Status; } NTSTATUS ProcessWiimoteBatteryLevel( _In_ PDEVICE_CONTEXT DeviceContext, _In_ BYTE BatteryLevel ) { NTSTATUS Status = STATUS_SUCCESS; Trace("BatteryLevel: 0x%x", BatteryLevel); DeviceContext->WiimoteContext.BatteryLevel = BatteryLevel; Status = UpdateBatteryLEDs(DeviceContext); if (!NT_SUCCESS(Status)) { return Status; } return STATUS_SUCCESS; } NTSTATUS ProcessStatusInformation( _In_ PDEVICE_CONTEXT DeviceContext, _In_reads_bytes_(ReadBufferSize) BYTE * ReadBuffer, _In_ size_t ReadBufferSize ) { NTSTATUS Status = STATUS_SUCCESS; UNREFERENCED_PARAMETER(ReadBufferSize); Trace("ProcessStatusInformation"); #ifndef MOUSE_IR BOOLEAN Extension = (ReadBuffer[3] & 0x02); Trace("Extension Flag: %d", (ReadBuffer[3] & 0x02)); if (Extension) { if (DeviceContext->WiimoteContext.Extension == None) { Status = InitializeExtension(DeviceContext); if (!NT_SUCCESS(Status)) { return Status; } } } else { DeviceContext->WiimoteContext.Extension = None; DeviceContext->WiimoteContext.CurrentReportMode = 0x31; } #endif //Process the Battery Level to set the LEDS; Wii U Pro Controller reports its Battery Level in its Input Report switch (DeviceContext->WiimoteContext.Extension) { case WiiUProController: break; default: Status = ProcessWiimoteBatteryLevel(DeviceContext, ReadBuffer[6]); if (!NT_SUCCESS(Status)) { return Status; } } //Set Report Mode, if extension changed Status = SetReportMode(DeviceContext, DeviceContext->WiimoteContext.CurrentReportMode); if(!NT_SUCCESS(Status)) { return Status; } // Notify Device Interface about Status Update DeviceInterfaceWiimoteStateUpdated(DeviceContext); return Status; } NTSTATUS ProcessExtensionRegister( _In_ PDEVICE_CONTEXT DeviceContext, _In_reads_bytes_(ReadBufferSize) BYTE * ReadBuffer, _In_ size_t ReadBufferSize, _In_ BYTE ErrorFlag, _In_ USHORT ReadAddress) { NTSTATUS Status = STATUS_SUCCESS; UNREFERENCED_PARAMETER(ReadBufferSize); UNREFERENCED_PARAMETER(ErrorFlag); UNREFERENCED_PARAMETER(ReadAddress); USHORT ExtensionType = ReadBuffer[4] << 8 | ReadBuffer[5]; USHORT SubType = ReadBuffer[0] << 8 | ReadBuffer[1]; Trace("Extension Type: %#010x", ExtensionType); Trace("Sub Type: %#010x", SubType); switch (ExtensionType) { case 0x0000: // Nunchuck Trace("Nunchuck Extension"); DeviceContext->WiimoteContext.Extension = Nunchuck; DeviceContext->WiimoteContext.CurrentReportMode = 0x35; break; case 0x0402: // Balance Board Trace("Balance Board"); DeviceContext->WiimoteContext.Extension = BalanceBoard; DeviceContext->WiimoteContext.CurrentReportMode = 0x32; SetLEDs(DeviceContext, WIIMOTE_LEDS_ALL); // Get Calibration Data ReadFromRegister(DeviceContext, 0xA40024, 24); break; case 0x0101: switch (SubType) { default: case 0x0000: // Classic Controler Trace("Classic Controller Extension"); DeviceContext->WiimoteContext.Extension = ClassicController; DeviceContext->WiimoteContext.CurrentReportMode = 0x32; break; case 0x0100: // Classic Controler Pro Trace("Classic Controller Pro Extension"); DeviceContext->WiimoteContext.Extension = ClassicControllerPro; DeviceContext->WiimoteContext.CurrentReportMode = 0x32; break; } break; case 0x0120: // Wii U Pro Controller Trace("Wii U Pro Controller"); DeviceContext->WiimoteContext.Extension = WiiUProController; DeviceContext->WiimoteContext.CurrentReportMode = 0x34; break; case 0x0103: // 0x0000: Guitar Hero Guitar // 0x0100: Guitar Hero Drum Kit // 0x0300: DJ Hero Turntables Trace("Guitar Hero Guitar"); DeviceContext->WiimoteContext.Extension = Guitar; DeviceContext->WiimoteContext.CurrentReportMode = 0x32; break; case 0xFFFF: // Error Trace("Error"); DeviceContext->WiimoteContext.Extension = None; DeviceContext->WiimoteContext.CurrentReportMode = 0x31; Status = InitializeExtension(DeviceContext); if (!NT_SUCCESS(Status)) { return Status; } break; default: Trace("Unsupported Extension!"); return Status; } Status = SetReportMode(DeviceContext, DeviceContext->WiimoteContext.CurrentReportMode); if (!NT_SUCCESS(Status)) { return Status; } // Signal Device Interface to report the new Extension Type DeviceInterfaceWiimoteStateUpdated(DeviceContext); return Status; } NTSTATUS ProcessBalanceBoardCalibrationRegister( _In_ PDEVICE_CONTEXT DeviceContext, _In_reads_bytes_(ReadBufferSize) PUCHAR ReadBuffer, _In_ size_t ReadBufferSize, _In_ BYTE ErrorFlag, _In_ USHORT ReadAddress) { NTSTATUS Status = STATUS_SUCCESS; UNREFERENCED_PARAMETER(ErrorFlag); PUSHORT Data = (PUSHORT)ReadBuffer; size_t CalibrationIndexStart = (ReadAddress == 0x0024) ? 0 : 2; size_t CalibrationIndexEnd = CalibrationIndexStart + (ReadBufferSize / 8); for (size_t CalibrationDataIndex = CalibrationIndexStart; CalibrationDataIndex < CalibrationIndexEnd; ++CalibrationDataIndex) { for (size_t SensorIndex = 0; SensorIndex < 4; ++SensorIndex) { DeviceContext->WiimoteContext.State.BalanceBoardState.Calibration[SensorIndex][CalibrationDataIndex] = RtlUshortByteSwap(Data[4 * (CalibrationDataIndex - CalibrationIndexStart) + SensorIndex]); } } return Status; } NTSTATUS ProcessRegisterReadReport( _In_ PDEVICE_CONTEXT DeviceContext, _In_reads_bytes_(ReadBufferSize) BYTE * ReadBuffer, _In_ size_t ReadBufferSize ) { NTSTATUS Status = STATUS_SUCCESS; UNREFERENCED_PARAMETER(ReadBufferSize); Trace("ProcessRegisterReadReport"); WiimoteStateUpdate(DeviceContext, ReadBuffer, ReadBufferSize); BYTE Error = 0x0F & (ReadBuffer[3]); Trace("Error Flag: %#04x", Error); BYTE Size = ((0xF0 & (ReadBuffer[3])) >> 4) + 1; Trace("Size: %#04x", Size); USHORT Address = RtlUshortByteSwap(*((USHORT *)(ReadBuffer + 4))); Trace("Address: %#06x", Address); switch(Address) { case 0x00FA: // Extension Type Status = ProcessExtensionRegister(DeviceContext, ReadBuffer + 6, Size, Error, Address); break; case 0x0024: // BalanceBoard Calibration case 0x0034: Status = ProcessBalanceBoardCalibrationRegister(DeviceContext, ReadBuffer + 6, Size, Error, Address); break; } return Status; } NTSTATUS ProcessAcknowledgementReport( _In_ PDEVICE_CONTEXT DeviceContext, _In_reads_bytes_(ReadBufferSize) BYTE * ReadBuffer, _In_ size_t ReadBufferSize ) { NTSTATUS Status = STATUS_SUCCESS; UNREFERENCED_PARAMETER(ReadBufferSize); Trace("ProcessAcknowledgementReport"); WiimoteStateUpdate(DeviceContext, ReadBuffer, ReadBufferSize); BYTE Report = ReadBuffer[3]; BYTE Result = ReadBuffer[4]; Trace("Report: %#04x", Report); Trace("Error Flag: %#04x", Result); if (Result == 0x03) { return STATUS_SUCCESS; } switch (Report) { case 0x13: Status = SendSingleByteReport(DeviceContext, 0x1A, 0x06); break; case 0x1A: Status = EnableIR(DeviceContext); break; } if (!NT_SUCCESS(Status)) { return Status; } return Status; } NTSTATUS WiimoteProcessReport( _In_ PDEVICE_CONTEXT DeviceContext, _In_reads_bytes_(ReadBufferSize) PVOID ReadBuffer, _In_ SIZE_T ReadBufferSize ) { NTSTATUS Status = STATUS_SUCCESS; BYTE ReportID = 0x00; if(ReadBufferSize >= 2) { ReportID = ((BYTE *)ReadBuffer)[1]; } //PrintBytes(ReadBuffer, ReadBufferSize); switch(ReportID) { // Status Information case 0x20: Status = ProcessStatusInformation(DeviceContext,(((BYTE *)ReadBuffer) + 1), (ReadBufferSize - 1)); break; case 0x21: Status = ProcessRegisterReadReport(DeviceContext, (((BYTE *)ReadBuffer) + 1), (ReadBufferSize - 1)); break; case 0x22: Status = ProcessAcknowledgementReport(DeviceContext, (((BYTE *)ReadBuffer) + 1), (ReadBufferSize - 1)); break; case 0x30: case 0x31: case 0x32: case 0x34: case 0x35: case 0x36: case 0x3D: Status = WiimoteStateUpdate(DeviceContext,(((PUCHAR)ReadBuffer) + 1), (ReadBufferSize - 1)); break; default: Trace("Unkown Report Recieved"); break; } if(!NT_SUCCESS(Status)) { return Status; } return Status; } VOID BatteryLevelLEDUpdateTimerExpired( WDFTIMER Timer ) { NTSTATUS Status; PDEVICE_CONTEXT DeviceContext = GetDeviceContext(WdfTimerGetParentObject(Timer)); Trace("BatteryLevelLEDUpdate Timer!"); if (DeviceContext->WiimoteContext.Extension == WiiUProController) { Status = UpdateBatteryLEDs(DeviceContext); if (!NT_SUCCESS(Status)) { return; } } else { Status = RequestStatusInformation(DeviceContext); TraceStatus("Request Status Information Result", Status); if (!NT_SUCCESS(Status)) { return; } } } ================================================ FILE: HID Wiimote/Wiimote.h ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: Wiimote.h Abstract: Header file for Wiimote.c */ #pragma once #include "HIDWiimote.h" #include "DeviceInterfacePublic.h" #include "WiimoteState.h" #include "WiimoteSettings.h" #define WIIMOTE_STATUSINFORMATION_INTERVAL (60000) // 60 Second typedef struct _WIIMOTE_DEVICE_CONTEXT { BYTE CurrentReportMode; BYTE BatteryLevel; BYTE LEDState; WIIMOTE_SETTINGS Settings; WIIMOTE_EXTENSION Extension; WIIMOTE_STATE State; WDFTIMER BatteryLevelLEDUpdateTimer; } WIIMOTE_DEVICE_CONTEXT, * PWIIMOTE_DEVICE_CONTEXT; NTSTATUS WiimotePrepare(_In_ PDEVICE_CONTEXT DeviceContext); NTSTATUS WiimoteStart(_In_ PDEVICE_CONTEXT DeviceContext); NTSTATUS WiimoteStop(_In_ PDEVICE_CONTEXT DeviceContext); VOID WiimoteReset(_In_ PDEVICE_CONTEXT DeviceContext); NTSTATUS WiimoteProcessReport(_In_ PDEVICE_CONTEXT DeviceContext, _In_reads_bytes_(ReadBufferSize) PVOID ReadBuffer, _In_ SIZE_T ReadBufferSize); ================================================ FILE: HID Wiimote/WiimoteSettings.c ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: WiimoteSettings.c Abstract: Loads and saves the Wiimote Settings from and to the Registry. */ #include "WiimoteToHIDParser.h" #include "Device.h" DECLARE_CONST_UNICODE_STRING(DriverModeValueName, L"DriverMode"); DECLARE_CONST_UNICODE_STRING(EnableWiimoteXAxisAccelerometerValueName, L"EnableWiimoteXAxisAccelerometer"); DECLARE_CONST_UNICODE_STRING(EnableWiimoteYAxisAccelerometerValueName, L"EnableWiimoteYAxisAccelerometer"); DECLARE_CONST_UNICODE_STRING(SwapMouseButtonsValueName, L"SwapMouseButtons"); DECLARE_CONST_UNICODE_STRING(SwapTriggerAndShoulderValueName, L"SwapTriggerAndShoulder"); DECLARE_CONST_UNICODE_STRING(SplitTriggerAxisValueName, L"SplitTriggerAxis"); DECLARE_CONST_UNICODE_STRING(MapTriggerAsAxisValueName, L"MapTriggerAsAxis"); DECLARE_CONST_UNICODE_STRING(MapTriggerAsButtonsValueName, L"MapTriggerAsButtons"); NTSTATUS OpenRegistryKey( _In_ PDEVICE_CONTEXT DeviceContext, _In_ ACCESS_MASK Access, _Out_ WDFKEY * DeviceKey, _Out_opt_ BOOLEAN * NewlyCreated ); VOID LoadWiimoteDriverModeValue( _In_ WDFKEY Key, _In_ PCUNICODE_STRING ValueName, _In_ WIIMOTE_DRIVER_MODE DefaultValue, _Out_ PWIIMOTE_DRIVER_MODE Value ); VOID LoadBooleanValue( _In_ WDFKEY Key, _In_ PCUNICODE_STRING ValueName, _In_ BOOLEAN DefaultValue, _Out_ PBOOLEAN Value ); VOID SaveULONGValue( _In_ PDEVICE_CONTEXT DeviceContext, _In_ PCUNICODE_STRING ValueName, _In_ ULONG Value ); VOID WiimoteSettingsLoad( _In_ PDEVICE_CONTEXT DeviceContext ) { NTSTATUS Status; WDFKEY Key; Status = OpenRegistryKey(DeviceContext, KEY_READ, &Key, NULL); if (!NT_SUCCESS(Status)) { Trace("Failed to open Reg Key to load settings."); return; } // Load each Setting DeviceContext->WiimoteContext.Settings.Mode = Gamepad; //LoadWiimoteDriverModeValue(Key, &DriverModeValueName, Gamepad, &DeviceContext->WiimoteContext.Settings.Mode); LoadBooleanValue(Key, &EnableWiimoteXAxisAccelerometerValueName, TRUE, &DeviceContext->WiimoteContext.Settings.EnableWiimoteXAxisAccelerometer); LoadBooleanValue(Key, &EnableWiimoteYAxisAccelerometerValueName, TRUE, &DeviceContext->WiimoteContext.Settings.EnableWiimoteYAxisAcceleromenter); LoadBooleanValue(Key, &SwapMouseButtonsValueName, FALSE, &DeviceContext->WiimoteContext.Settings.SwapMouseButtons); LoadBooleanValue(Key, &SwapTriggerAndShoulderValueName, FALSE, &DeviceContext->WiimoteContext.Settings.SwapTriggerAndShoulder); LoadBooleanValue(Key, &SplitTriggerAxisValueName, TRUE, &DeviceContext->WiimoteContext.Settings.SplitTriggerAxis); LoadBooleanValue(Key, &MapTriggerAsAxisValueName, TRUE, &DeviceContext->WiimoteContext.Settings.MapTriggerAsAxis); LoadBooleanValue(Key, &MapTriggerAsButtonsValueName, TRUE, &DeviceContext->WiimoteContext.Settings.MapTriggerAsButtons); // Close Key WdfRegistryClose(Key); } VOID WiimoteSettingsSetDriverMode( _In_ PDEVICE_CONTEXT DeviceContext, _In_ WIIMOTE_DRIVER_MODE DriverMode ) { //DeviceContext->WiimoteContext.Settings.Mode = DriverMode; SaveULONGValue(DeviceContext, &DriverModeValueName, (ULONG)DriverMode); // Check for IR Activation/Deactivation } VOID WiimoteSettingsSetEnableWiimoteXAxisAccelerometer( _In_ PDEVICE_CONTEXT DeviceContext, _In_ BOOLEAN Enabled ) { DeviceContext->WiimoteContext.Settings.EnableWiimoteXAxisAccelerometer = Enabled; HIDWiimoteStateUpdated(DeviceContext); SaveULONGValue(DeviceContext, &EnableWiimoteXAxisAccelerometerValueName, (ULONG)Enabled); } VOID WiimoteSettingsSetEnableWiimoteYAxisAccelerometer( _In_ PDEVICE_CONTEXT DeviceContext, _In_ BOOLEAN Enabled ) { DeviceContext->WiimoteContext.Settings.EnableWiimoteYAxisAcceleromenter = Enabled; HIDWiimoteStateUpdated(DeviceContext); SaveULONGValue(DeviceContext, &EnableWiimoteYAxisAccelerometerValueName, (ULONG)Enabled); } VOID WiimoteSettingsSetSwapMouseButtons( _In_ PDEVICE_CONTEXT DeviceContext, _In_ BOOLEAN Enabled ) { DeviceContext->WiimoteContext.Settings.SwapMouseButtons = Enabled; HIDWiimoteStateUpdated(DeviceContext); SaveULONGValue(DeviceContext, &SwapMouseButtonsValueName, (ULONG)Enabled); } VOID WiimoteSettingsSetSwapTriggerAndShoulder( _In_ PDEVICE_CONTEXT DeviceContext, _In_ BOOLEAN Enabled ) { DeviceContext->WiimoteContext.Settings.SwapTriggerAndShoulder = Enabled; HIDWiimoteStateUpdated(DeviceContext); SaveULONGValue(DeviceContext, &SwapTriggerAndShoulderValueName, (ULONG)Enabled); } VOID WiimoteSettingsSetSplitTriggerAxis( _In_ PDEVICE_CONTEXT DeviceContext, _In_ BOOLEAN Enabled ) { DeviceContext->WiimoteContext.Settings.SplitTriggerAxis = Enabled; HIDWiimoteStateUpdated(DeviceContext); SaveULONGValue(DeviceContext, &SplitTriggerAxisValueName, (ULONG)Enabled); } VOID WiimoteSettingsSetMapTriggerAsAxis( _In_ PDEVICE_CONTEXT DeviceContext, _In_ BOOLEAN Enabled ) { DeviceContext->WiimoteContext.Settings.MapTriggerAsAxis = Enabled; HIDWiimoteStateUpdated(DeviceContext); SaveULONGValue(DeviceContext, &MapTriggerAsAxisValueName, (ULONG)Enabled); } VOID WiimoteSettingsSetMapTriggerAsButtons( _In_ PDEVICE_CONTEXT DeviceContext, _In_ BOOLEAN Enabled ) { DeviceContext->WiimoteContext.Settings.MapTriggerAsButtons = Enabled; HIDWiimoteStateUpdated(DeviceContext); SaveULONGValue(DeviceContext, &MapTriggerAsButtonsValueName, (ULONG)Enabled); } /* Currently the hardware/device key as well as the driver software key is not persistent accross disconnecting Wiimotes. Therefore we need to use the driver/service parameters key, that seems to be persistent, even when the driver is uninstalled. An "DeviceSettings" subkey is used so the parameters key remains clear. For each device the Bluetooth address is used as unique identifier and device key. */ NTSTATUS OpenRegistryKey( _In_ PDEVICE_CONTEXT DeviceContext, _In_ ACCESS_MASK Access, _Out_ WDFKEY * DeviceKey, _Out_opt_ BOOLEAN * NewlyCreated ) { NTSTATUS Status; WDFKEY ServiceKey; WDFKEY DeviceSettingsSubkey; ULONG CreateDisposition; DECLARE_CONST_UNICODE_STRING(DeviceSettingsSubkeyName, L"DeviceSettings"); // Open the driver/service parameters key "../Services/HIDWiimote/Parameters" Status = WdfDriverOpenParametersRegistryKey(WdfGetDriver(), Access, WDF_NO_OBJECT_ATTRIBUTES, &ServiceKey); if (!NT_SUCCESS(Status)) { TraceStatus("Error opening Service Key", Status); return Status; } // Open/create a subkey for all devices "../Services/HIDWiimote/Parameters/DeviceSettings" Status = WdfRegistryCreateKey(ServiceKey, &DeviceSettingsSubkeyName, Access, REG_OPTION_NON_VOLATILE, &CreateDisposition, WDF_NO_OBJECT_ATTRIBUTES, &DeviceSettingsSubkey); if (!NT_SUCCESS(Status)) { TraceStatus("Error opening Device Settings Subkey", Status); WdfRegistryClose(ServiceKey); return Status; } // Open/create the device "../Services/HIDWiimote/Parameters/DeviceSettings/XXXXXXXXXXX" Status = WdfRegistryCreateKey(DeviceSettingsSubkey, &DeviceContext->BluetoothContext.DeviceAddressString, Access, REG_OPTION_NON_VOLATILE, &CreateDisposition, WDF_NO_OBJECT_ATTRIBUTES, DeviceKey); if (!NT_SUCCESS(Status)) { TraceStatus("Error opening Device Subkey", Status); WdfRegistryClose(ServiceKey); WdfRegistryClose(DeviceSettingsSubkey); return Status; } if (NewlyCreated != NULL) { (*NewlyCreated) = (CreateDisposition == REG_CREATED_NEW_KEY) ? TRUE : FALSE; } WdfRegistryClose(ServiceKey); WdfRegistryClose(DeviceSettingsSubkey); return STATUS_SUCCESS; } VOID LoadWiimoteDriverModeValue( _In_ WDFKEY Key, _In_ PCUNICODE_STRING ValueName, _In_ WIIMOTE_DRIVER_MODE DefaultValue, _Out_ PWIIMOTE_DRIVER_MODE Value ) { NTSTATUS Status; ULONG ValueBuffer; Status = WdfRegistryQueryULong(Key, ValueName, &ValueBuffer); (*Value) = NT_SUCCESS(Status) ? (WIIMOTE_DRIVER_MODE)ValueBuffer : DefaultValue; } VOID LoadBooleanValue( _In_ WDFKEY Key, _In_ PCUNICODE_STRING ValueName, _In_ BOOLEAN DefaultValue, _Out_ PBOOLEAN Value ) { NTSTATUS Status; ULONG ValueBuffer; Status = WdfRegistryQueryULong(Key, ValueName, &ValueBuffer); (*Value) = NT_SUCCESS(Status) ? (BOOLEAN)ValueBuffer : DefaultValue; } VOID SaveULONGValue( _In_ PDEVICE_CONTEXT DeviceContext, _In_ PCUNICODE_STRING ValueName, _In_ ULONG Value ) { NTSTATUS Status; WDFKEY Key; Status = OpenRegistryKey(DeviceContext, KEY_WRITE, &Key, NULL); if (!NT_SUCCESS(Status)) { TraceStatus("Error opening Subkey for writing", Status); return; } Status = WdfRegistryAssignULong(Key, ValueName, Value); if (!NT_SUCCESS(Status)) { TraceStatus("Error writing Value", Status); WdfRegistryClose(Key); return; } WdfRegistryClose(Key); } ================================================ FILE: HID Wiimote/WiimoteSettings.h ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: WiimoteSettings.h Abstract: Header file for WiimoteSettings.c */ #pragma once #include "HIDWiimote.h" #include "DeviceInterfacePublic.h" VOID WiimoteSettingsLoad( _In_ PDEVICE_CONTEXT DeviceContext ); VOID WiimoteSettingsSetDriverMode( _In_ PDEVICE_CONTEXT DeviceContext, _In_ WIIMOTE_DRIVER_MODE DriverMode ); VOID WiimoteSettingsSetEnableWiimoteXAxisAccelerometer( _In_ PDEVICE_CONTEXT DeviceContext, _In_ BOOLEAN Enabled ); VOID WiimoteSettingsSetEnableWiimoteYAxisAccelerometer( _In_ PDEVICE_CONTEXT DeviceContext, _In_ BOOLEAN Enabled ); VOID WiimoteSettingsSetSwapMouseButtons( _In_ PDEVICE_CONTEXT DeviceContext, _In_ BOOLEAN Enabled ); VOID WiimoteSettingsSetSwapTriggerAndShoulder( _In_ PDEVICE_CONTEXT DeviceContext, _In_ BOOLEAN Enabled ); VOID WiimoteSettingsSetSplitTriggerAxis( _In_ PDEVICE_CONTEXT DeviceContext, _In_ BOOLEAN Enabled ); VOID WiimoteSettingsSetMapTriggerAsAxis( _In_ PDEVICE_CONTEXT DeviceContext, _In_ BOOLEAN Enabled ); VOID WiimoteSettingsSetMapTriggerAsButtons( _In_ PDEVICE_CONTEXT DeviceContext, _In_ BOOLEAN Enabled ); ================================================ FILE: HID Wiimote/WiimoteState.c ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: WiimoteState.c Abstract: Parses Wiimote Reports into State Buffers */ #include "WiimoteState.h" #include "Device.h" NTSTATUS UpdateCoreButtons(_Inout_ PWIIMOTE_WII_REMOTE_STATE WiiRemoteState, _In_reads_bytes_(2) PUCHAR ButtonData, _In_ size_t ButtonDataSize); NTSTATUS UpdateAccelerometer(_Inout_ PWIIMOTE_WII_REMOTE_STATE WiiRemoteState, _In_reads_bytes_(3) PUCHAR AccelerometerData, _In_ size_t AccelerometerDataSize); NTSTATUS UpdateExtension(_Inout_ PWIIMOTE_DEVICE_CONTEXT WiimoteContext, _In_reads_bytes_(DataSize) PUCHAR Data, _In_ size_t DataSize); NTSTATUS UpdateNunchuck(_Inout_ PWIIMOTE_NUNCHUCK_STATE NunchuckState, _In_reads_bytes_(6) PUCHAR NunchuckData, _In_ size_t NunchuckDataSize); NTSTATUS UpdateBalanceBoard(_Inout_ PWIIMOTE_BALANCE_BOARD_STATE BalanceBoardState, _In_reads_bytes_(8) PUCHAR BalanceBoardData, _In_ size_t BalanceBoardDataSize); NTSTATUS UpdateClassicController(_Inout_ PWIIMOTE_CLASSIC_CONTROLLER_STATE ClassicControllerState, _In_reads_bytes_(6) PUCHAR ClassicControllerData, _In_ size_t ClassicControllerDataSize); NTSTATUS UpdateClassicControllerPro(_Inout_ PWIIMOTE_CLASSIC_CONTROLLER_STATE ClassicControllerState, _In_reads_bytes_(6) PUCHAR ClassicControllerProData, _In_ size_t ClassicControllerProDataSize); NTSTATUS UpdateWiiUProController(_Inout_ PWIIMOTE_DEVICE_CONTEXT WiimoteContext, _Inout_ PWIIMOTE_CLASSIC_CONTROLLER_STATE ClassicControllerState, _In_reads_bytes_(11) PUCHAR WiiUProControllerData, _In_ size_t WiiUProControllerDataSize); NTSTATUS UpdateGuitar(_Inout_ PWIIMOTE_GUITAR_STATE GuitarState, _In_reads_bytes_(6) PUCHAR GuitarData, _In_ size_t GuitarDataSize); NTSTATUS UpdateIRCamera(_In_ PWIIMOTE_IR_STATE IRState, _In_reads_bytes_(10) PUCHAR IRData, _In_ size_t IRDataSize, _Out_ PBOOLEAN IRDataIsValid); VOID UpdateClassicControllerButtons(_Inout_ PWIIMOTE_CLASSIC_CONTROLLER_STATE ClassicControllerState, _In_reads_bytes_(2) PUCHAR ButtonData); VOID UpdateClassicControllerAxes(_Inout_ PWIIMOTE_CLASSIC_CONTROLLER_STATE ClassicControllerState, _In_reads_bytes_(2) PUCHAR ButtoInputDatanData); BOOLEAN UpdateIRCameraPoint(_In_ PWIIMOTE_IR_POINT IRPointData1, _In_ PWIIMOTE_IR_POINT IRPointData2, _In_reads_bytes_(5) PUCHAR IRData); VOID WiimoteStateResetToNullState( _In_ PDEVICE_CONTEXT DeviceContext ) { PWIIMOTE_STATE WiimoteState = &DeviceContext->WiimoteContext.State; // Reset all to zero => No buttons pressed RtlSecureZeroMemory(WiimoteState, sizeof(WIIMOTE_STATE)); // Reset Accelerometers to null state WiimoteState->WiiRemoteState.Accelerometer.X = 0x80; WiimoteState->WiiRemoteState.Accelerometer.Y = 0x80; WiimoteState->WiiRemoteState.Accelerometer.Z = 0x80; // Reset IR data to "invalid data" for (size_t i = 0; i < WIIMOTE_IR_POINTS_BUFFER_SIZE; ++i) for (size_t j = 0; j < WIIMOTE_IR_POINTS; j++) { DeviceContext->WiimoteContext.State.IRState.Points[i][j].X = 0x3FF; DeviceContext->WiimoteContext.State.IRState.Points[i][j].Y = 0x3FF; } HIDWiimoteStateUpdated(DeviceContext); } NTSTATUS WiimoteStateUpdate( _In_ PDEVICE_CONTEXT DeviceContext, _In_reads_bytes_(DataSize) PUCHAR Data, _In_ _In_range_(1, SIZE_MAX) size_t DataSize ) { NTSTATUS Status = STATUS_SUCCESS; BOOLEAN ForwardUpdateToHID = TRUE; PWIIMOTE_DEVICE_CONTEXT WiimoteContext = &(DeviceContext->WiimoteContext); PWIIMOTE_WII_REMOTE_STATE WiiRemoteState = &(WiimoteContext->State.WiiRemoteState); BYTE ReportID = Data[0]; //Every Report but 0x3D has Core Buttons if (ReportID != 0x3D) { Status = UpdateCoreButtons(WiiRemoteState, Data + 1, DataSize - 1); if (!NT_SUCCESS(Status)) { return Status; } } // Process additional payload switch (ReportID) { case 0x31: // Accelerometer Status = UpdateAccelerometer(WiiRemoteState, Data + 3, DataSize - 3); if (!NT_SUCCESS(Status)) { return Status; } break; case 0x32: // 8 Byte Extension case 0x34: // 19 Byte Extension Status = UpdateExtension(WiimoteContext, Data + 3, DataSize - 3); if (!NT_SUCCESS(Status)) { return Status; } break; case 0x35: // Accelerometer & 16 Byte Extension Status = UpdateAccelerometer(WiiRemoteState, Data + 3, DataSize - 3); if (!NT_SUCCESS(Status)) { return Status; } Status = UpdateExtension(WiimoteContext, Data + 6, DataSize - 6); if (!NT_SUCCESS(Status)) { return Status; } break; case 0x36: // 10 Byte IR & 9 Byte Extension Status = UpdateIRCamera(&(WiimoteContext->State.IRState), Data + 3, DataSize - 3, &ForwardUpdateToHID); if (!NT_SUCCESS(Status)) { return Status; } break; } if (ForwardUpdateToHID) { HIDWiimoteStateUpdated(DeviceContext); } return Status; } NTSTATUS UpdateCoreButtons( _Inout_ PWIIMOTE_WII_REMOTE_STATE WiiRemoteState, _In_reads_bytes_(2) PUCHAR ButtonData, _In_ size_t ButtonDataSize ) { if (ButtonDataSize < 2) { Trace("Data Buffer too small to read Core Buttons"); return STATUS_INVALID_BUFFER_SIZE; } WiiRemoteState->CoreButtons.A = (ButtonData[1] & 0x08); WiiRemoteState->CoreButtons.B = (ButtonData[1] & 0x04); WiiRemoteState->CoreButtons.One = (ButtonData[1] & 0x02); WiiRemoteState->CoreButtons.Two = (ButtonData[1] & 0x01); WiiRemoteState->CoreButtons.Minus = (ButtonData[1] & 0x10); WiiRemoteState->CoreButtons.Plus = (ButtonData[0] & 0x10); WiiRemoteState->CoreButtons.Home = (ButtonData[1] & 0x80); WiiRemoteState->CoreButtons.DPad.Left = (ButtonData[0] & 0x01); WiiRemoteState->CoreButtons.DPad.Right = (ButtonData[0] & 0x02); WiiRemoteState->CoreButtons.DPad.Down = (ButtonData[0] & 0x04); WiiRemoteState->CoreButtons.DPad.Up = (ButtonData[0] & 0x08); return STATUS_SUCCESS; } NTSTATUS UpdateAccelerometer( _Inout_ PWIIMOTE_WII_REMOTE_STATE WiiRemoteState, _In_reads_bytes_(3) PUCHAR AccelerometerData, _In_ size_t AccelerometerDataSize ) { if (AccelerometerDataSize < 3) { Trace("Data Buffer too small to Update Accelerometer Data"); return STATUS_INVALID_BUFFER_SIZE; } /* Accelerometer data is originally 10 Bits wide. 8 MSBs are carried in the Accelermoter bytes. The 2 LSBs are packed into the Core Button bytes. (Only for X are actually 2 bits packed; for Y and Z only the second LSB is provided) For further processing only the 8 MSB are used. */ WiiRemoteState->Accelerometer.X = AccelerometerData[0]; WiiRemoteState->Accelerometer.Y = AccelerometerData[1]; WiiRemoteState->Accelerometer.Z = AccelerometerData[2]; return STATUS_SUCCESS; } NTSTATUS UpdateExtension( _Inout_ PWIIMOTE_DEVICE_CONTEXT WiimoteContext, _In_reads_bytes_(DataSize) PUCHAR Data, _In_ size_t DataSize ) { switch (WiimoteContext->Extension) { case Nunchuck: return UpdateNunchuck(&(WiimoteContext->State.NunchuckState), Data, DataSize); case BalanceBoard: return UpdateBalanceBoard(&(WiimoteContext->State.BalanceBoardState), Data, DataSize); case ClassicController: return UpdateClassicController(&(WiimoteContext->State.ClassicControllerState), Data, DataSize); case ClassicControllerPro: return UpdateClassicControllerPro(&(WiimoteContext->State.ClassicControllerState), Data, DataSize); case WiiUProController: return UpdateWiiUProController(WiimoteContext, &(WiimoteContext->State.ClassicControllerState), Data, DataSize); case Guitar: return UpdateGuitar(&(WiimoteContext->State.GuitarState), Data, DataSize); default: return STATUS_SUCCESS; } } NTSTATUS UpdateNunchuck( _Inout_ PWIIMOTE_NUNCHUCK_STATE NunchuckState, _In_reads_bytes_(6) PUCHAR NunchuckData, _In_ size_t NunchuckDataSize ) { if (NunchuckDataSize < 6) { Trace("Data Buffer too small to read Nunchuck Data"); return STATUS_INVALID_BUFFER_SIZE; } BYTE ButtonData = ~NunchuckData[5]; //Buttons NunchuckState->Buttons.Z = ButtonData & 0x01; NunchuckState->Buttons.C = ButtonData & 0x02; //Analog Stick NunchuckState->AnalogStick.X = NunchuckData[0]; NunchuckState->AnalogStick.Y = NunchuckData[1]; //Accelerometer NunchuckState->Accelerometer.X = NunchuckData[2]; NunchuckState->Accelerometer.Y = NunchuckData[3]; NunchuckState->Accelerometer.Z = NunchuckData[4]; return STATUS_SUCCESS; } NTSTATUS UpdateBalanceBoard( _Inout_ PWIIMOTE_BALANCE_BOARD_STATE BalanceBoardState, _In_reads_bytes_(8) PUCHAR BalanceBoardData, _In_ size_t BalanceBoardDataSize ) { if (BalanceBoardDataSize < 8) { Trace("Data Buffer too small to read Balance Board Data"); return STATUS_INVALID_BUFFER_SIZE; } // Sensor Data is Big-Endian, Windows is always Little-Endian BalanceBoardState->Sensor[WIIMOTE_BALANCE_BOARD_TOP_RIGHT] = RtlUshortByteSwap(*((PUSHORT)(BalanceBoardData + 0))); BalanceBoardState->Sensor[WIIMOTE_BALANCE_BOARD_BOTTOM_RIGHT] = RtlUshortByteSwap(*((PUSHORT)(BalanceBoardData + 2))); BalanceBoardState->Sensor[WIIMOTE_BALANCE_BOARD_TOP_LEFT] = RtlUshortByteSwap(*((PUSHORT)(BalanceBoardData + 4))); BalanceBoardState->Sensor[WIIMOTE_BALANCE_BOARD_BOTTOM_LEFT] = RtlUshortByteSwap(*((PUSHORT)(BalanceBoardData + 6))); return STATUS_SUCCESS; } NTSTATUS UpdateClassicController( _Inout_ PWIIMOTE_CLASSIC_CONTROLLER_STATE ClassicControllerState, _In_reads_bytes_(6) PUCHAR ClassicControllerData, _In_ size_t ClassicControllerDataSize ) { if (ClassicControllerDataSize < 6) { Trace("Data Buffer too small to read Classic Controller Data"); return STATUS_INVALID_BUFFER_SIZE; } // Buttons UpdateClassicControllerButtons(ClassicControllerState, ClassicControllerData + 4); // Axes UpdateClassicControllerAxes(ClassicControllerState, ClassicControllerData); // Trigger ClassicControllerState->LeftTrigger = 0xFF & ((0x60 & ClassicControllerData[2]) >> 2); ClassicControllerState->LeftTrigger |= 0xFF & ((0xE0 & ClassicControllerData[3]) >> 5); ClassicControllerState->RightTrigger = 0xFF & (0x1F & ClassicControllerData[3]); return STATUS_SUCCESS; } NTSTATUS UpdateClassicControllerPro( _Inout_ PWIIMOTE_CLASSIC_CONTROLLER_STATE ClassicControllerState, _In_reads_bytes_(6) PUCHAR ClassicControllerProData, _In_ size_t ClassicControllerProDataSize ) { if (ClassicControllerProDataSize < 6) { Trace("Data Buffer too small to read Classic Controller Pro Data"); return STATUS_INVALID_BUFFER_SIZE; } //Buttons UpdateClassicControllerButtons(ClassicControllerState, ClassicControllerProData + 4); // Axes UpdateClassicControllerAxes(ClassicControllerState, ClassicControllerProData); //Trigger ClassicControllerState->LeftTrigger = 0xFF; ClassicControllerState->RightTrigger = 0xFF; return STATUS_SUCCESS; } NTSTATUS UpdateWiiUProController( _Inout_ PWIIMOTE_DEVICE_CONTEXT WiimoteContext, _Inout_ PWIIMOTE_CLASSIC_CONTROLLER_STATE ClassicControllerState, _In_reads_bytes_(11) PUCHAR WiiUProControllerData, _In_ size_t WiiUProControllerDataSize ) { if (WiiUProControllerDataSize < 11) { Trace("Data Buffer too small to read Wii U Pro Controller Data"); return STATUS_INVALID_BUFFER_SIZE; } BYTE BatteryLevel = 0; BYTE ButtonData = ~WiiUProControllerData[10]; //Buttons UpdateClassicControllerButtons(ClassicControllerState, WiiUProControllerData + 8); ClassicControllerState->Buttons.LH = (ButtonData & 0x02); ClassicControllerState->Buttons.RH = (ButtonData & 0x01); //AnalogSticks ClassicControllerState->LeftAnalogStick.X = 0xFF & ((WiiUProControllerData[0] >> 4) | (WiiUProControllerData[1] << 4)); ClassicControllerState->LeftAnalogStick.Y = 0xFF & ((WiiUProControllerData[4] >> 4) | (WiiUProControllerData[5] << 4)); ClassicControllerState->RightAnalogStick.X = 0xFF & ((WiiUProControllerData[2] >> 4) | (WiiUProControllerData[3] << 4)); ClassicControllerState->RightAnalogStick.Y = 0xFF & ((WiiUProControllerData[6] >> 4) | (WiiUProControllerData[7] << 4)); //Unsupported Input ClassicControllerState->LeftTrigger = 0xFF; ClassicControllerState->RightTrigger = 0xFF; //Battery Level switch (WiiUProControllerData[10] & 0xF0) { case 0xC0: BatteryLevel = 0xFF; break; case 0xB0: BatteryLevel = 0xBF; break; case 0xA0: BatteryLevel = 0x7F; break; case 0x90: BatteryLevel = 0x3F; break; case 0x80: default: BatteryLevel = 0x10; } WiimoteContext->BatteryLevel = BatteryLevel; return STATUS_SUCCESS; } VOID UpdateClassicControllerButtons( _Inout_ PWIIMOTE_CLASSIC_CONTROLLER_STATE ClassicControllerState, _In_reads_bytes_(2) PUCHAR ButtonData ) { BYTE InvertedButtonData[2] = { 0 }; InvertedButtonData[0] = ~ButtonData[0]; InvertedButtonData[1] = ~ButtonData[1]; ClassicControllerState->Buttons.A = InvertedButtonData[1] & 0x10; ClassicControllerState->Buttons.B = InvertedButtonData[1] & 0x40; ClassicControllerState->Buttons.Y = InvertedButtonData[1] & 0x20; ClassicControllerState->Buttons.X = InvertedButtonData[1] & 0x08; ClassicControllerState->Buttons.Home = InvertedButtonData[0] & 0x08; ClassicControllerState->Buttons.Plus = InvertedButtonData[0] & 0x04; ClassicControllerState->Buttons.Minus = InvertedButtonData[0] & 0x10; ClassicControllerState->Buttons.DPad.Up = InvertedButtonData[1] & 0x01; ClassicControllerState->Buttons.DPad.Right = InvertedButtonData[0] & 0x80; ClassicControllerState->Buttons.DPad.Down = InvertedButtonData[0] & 0x40; ClassicControllerState->Buttons.DPad.Left = InvertedButtonData[1] & 0x02; ClassicControllerState->Buttons.L = InvertedButtonData[0] & 0x20; ClassicControllerState->Buttons.ZL = InvertedButtonData[1] & 0x80; ClassicControllerState->Buttons.R = InvertedButtonData[0] & 0x02; ClassicControllerState->Buttons.ZR = InvertedButtonData[1] & 0x04; ClassicControllerState->Buttons.LH = FALSE; ClassicControllerState->Buttons.RH = FALSE; } VOID UpdateClassicControllerAxes( _Inout_ PWIIMOTE_CLASSIC_CONTROLLER_STATE ClassicControllerState, _In_reads_bytes_(3) PUCHAR InputData ) { //Analog Sticks ClassicControllerState->LeftAnalogStick.X = 0xFF & ((0x3F & InputData[0]) << 2); ClassicControllerState->LeftAnalogStick.Y = 0xFF & ((0x3F & InputData[1]) << 2); ClassicControllerState->RightAnalogStick.X = 0xFF & ((0xC0 & InputData[0])); ClassicControllerState->RightAnalogStick.X |= 0xFF & ((0xC0 & InputData[1]) >> 2); ClassicControllerState->RightAnalogStick.X |= 0xFF & ((0x80 & InputData[2]) >> 4); ClassicControllerState->RightAnalogStick.Y = 0xFF & ((0x1F & InputData[2]) << 3); } NTSTATUS UpdateGuitar( _Inout_ PWIIMOTE_GUITAR_STATE GuitarState, _In_reads_bytes_(6) PUCHAR GuitarData, _In_ size_t GuitarDataSize ) { if (GuitarDataSize < 6) { Trace("Data Buffer too small to read Guitar Data"); return STATUS_INVALID_BUFFER_SIZE; } BYTE ButtonData[2] = { 0 }; ButtonData[0] = ~GuitarData[4]; ButtonData[1] = ~GuitarData[5]; // Buttons GuitarState->Buttons.Green = ButtonData[1] & 0x10; GuitarState->Buttons.Red = ButtonData[1] & 0x40; GuitarState->Buttons.Yellow = ButtonData[1] & 0x08; GuitarState->Buttons.Blue = ButtonData[1] & 0x20; GuitarState->Buttons.Orange = ButtonData[1] & 0x80; GuitarState->Buttons.Plus = ButtonData[0] & 0x04; GuitarState->Buttons.Minus = ButtonData[0] & 0x10; GuitarState->Buttons.Up = ButtonData[1] & 0x01; GuitarState->Buttons.Down = ButtonData[0] & 0x40; // Analog Sticks GuitarState->AnalogStick.X = 0xFF & ((0x3F & GuitarData[0]) << 2); GuitarState->AnalogStick.Y = 0xFF & ((0x3F & GuitarData[1]) << 2); // Analog Bars GuitarState->TouchBar = 0xFF & ((0x1F & GuitarData[2]) << 3); GuitarState->WhammyBar = 0xFF & ((0x1F & GuitarData[3]) << 3); return STATUS_SUCCESS; } NTSTATUS UpdateIRCamera( _In_ PWIIMOTE_IR_STATE IRState, _In_reads_bytes_(10) PUCHAR IRData, _In_ size_t IRDataSize, _Out_ PBOOLEAN IRDataIsValid ) { if (IRDataSize < 10) { Trace("Data Buffer too small to read IR Data"); return STATUS_INVALID_BUFFER_SIZE; } BYTE BufferIndex = IRState->PointsBufferPointer++; IRState->PointsBufferPointer %= WIIMOTE_IR_POINTS_BUFFER_SIZE; (*IRDataIsValid) = FALSE; (*IRDataIsValid) |= UpdateIRCameraPoint(&(IRState->Points[BufferIndex][0]), &(IRState->Points[BufferIndex][1]), IRData); (*IRDataIsValid) |= UpdateIRCameraPoint(&(IRState->Points[BufferIndex][2]), &(IRState->Points[BufferIndex][3]), IRData + 5); return STATUS_SUCCESS; } BOOLEAN UpdateIRCameraPoint( _In_ PWIIMOTE_IR_POINT IRPointData1, _In_ PWIIMOTE_IR_POINT IRPointData2, _In_reads_bytes_(5) PUCHAR IRData ) { USHORT X1 = IRData[0]; USHORT Y1 = IRData[1]; USHORT X2 = IRData[3]; USHORT Y2 = IRData[4]; X1 |= (0x30 & IRData[2]) << 4; Y1 |= (0xC0 & IRData[2]) << 2; X2 |= (0x03 & IRData[2]) << 8; Y2 |= (0x0C & IRData[2]) << 6; IRPointData1->X = X1; IRPointData1->Y = Y1; IRPointData2->X = X2; IRPointData2->Y = Y2; // Max for Y is 767, so 0x3FF Value means no Data return ((Y1 != 0x3FF) || (Y2 != 0x3FF)); } ================================================ FILE: HID Wiimote/WiimoteState.h ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: WiimoteState.h Abstract: Header file for WiimoteState.c */ #pragma once #include "HIDWiimote.h" // --- Wii Remote --- // typedef struct _WIIMOTE_WII_REMOTE_STATE { struct { BOOLEAN A; BOOLEAN B; BOOLEAN One; BOOLEAN Two; BOOLEAN Plus; BOOLEAN Minus; BOOLEAN Home; struct { BOOLEAN Up; BOOLEAN Down; BOOLEAN Left; BOOLEAN Right; } DPad; } CoreButtons; struct { BYTE X; BYTE Y; BYTE Z; } Accelerometer; } WIIMOTE_WII_REMOTE_STATE, *PWIIMOTE_WII_REMOTE_STATE; // --- IR --- // #define WIIMOTE_IR_POINTS 4 #define WIIMOTE_IR_POINTS_BUFFER_SIZE 5 #define WIIMOTE_IR_POINT_X_MAX 1023 #define WIIMOTE_IR_POINT_Y_MAX 767 typedef struct _WIIMOTE_IR_POINT { USHORT X; USHORT Y; } WIIMOTE_IR_POINT, *PWIIMOTE_IR_POINT; typedef struct _WIIMOTE_IR_STATE { WIIMOTE_IR_POINT Points[WIIMOTE_IR_POINTS_BUFFER_SIZE][WIIMOTE_IR_POINTS]; BYTE PointsBufferPointer; } WIIMOTE_IR_STATE, *PWIIMOTE_IR_STATE; // --- Nunchuck --- // typedef struct _WIIMOTE_NUNCHUCK_STATE { struct { BOOLEAN C; BOOLEAN Z; } Buttons; struct { BYTE X; BYTE Y; } AnalogStick; struct { BYTE X; BYTE Y; BYTE Z; } Accelerometer; } WIIMOTE_NUNCHUCK_STATE, *PWIIMOTE_NUNCHUCK_STATE; // --- Balance Board --- // #define WIIMOTE_BALANCE_BOARD_TOP_RIGHT 0 #define WIIMOTE_BALANCE_BOARD_BOTTOM_RIGHT 1 #define WIIMOTE_BALANCE_BOARD_TOP_LEFT 2 #define WIIMOTE_BALANCE_BOARD_BOTTOM_LEFT 3 #define WIIMOTE_BALANCE_BOARD_SENSOR_POINTS 4 #define WIIMOTE_BALANCE_BOARD_CALIBRATION_RECORDS 3 typedef struct _WIIMOTE_BALANCE_BOARD_STATE { USHORT Sensor[4]; USHORT Calibration[WIIMOTE_BALANCE_BOARD_SENSOR_POINTS][WIIMOTE_BALANCE_BOARD_CALIBRATION_RECORDS]; } WIIMOTE_BALANCE_BOARD_STATE, *PWIIMOTE_BALANCE_BOARD_STATE; // --- Classic Controller (Pro) / Wii U Pro Controller --- // typedef struct _WIIMOTE_CLASSIC_CONTROLLER_STATE { struct { BOOLEAN L; BOOLEAN R; BOOLEAN ZL; BOOLEAN ZR; BOOLEAN LH; BOOLEAN RH; BOOLEAN A; BOOLEAN B; BOOLEAN Y; BOOLEAN X; BOOLEAN Plus; BOOLEAN Minus; BOOLEAN Home; struct { BOOLEAN Up; BOOLEAN Down; BOOLEAN Left; BOOLEAN Right; } DPad; } Buttons; BYTE LeftTrigger; BYTE RightTrigger; struct { BYTE X; BYTE Y; } LeftAnalogStick; struct { BYTE X; BYTE Y; } RightAnalogStick; } WIIMOTE_CLASSIC_CONTROLLER_STATE, *PWIIMOTE_CLASSIC_CONTROLLER_STATE; // --- Guitar --- // typedef struct _WIIMOTE_GUITAR_STATE { struct { BOOLEAN Green; BOOLEAN Red; BOOLEAN Yellow; BOOLEAN Blue; BOOLEAN Orange; BOOLEAN Plus; BOOLEAN Minus; BOOLEAN Up; BOOLEAN Down; } Buttons; BYTE TouchBar; BYTE WhammyBar; struct { BYTE X; BYTE Y; } AnalogStick; } WIIMOTE_GUITAR_STATE, *PWIIMOTE_GUITAR_STATE; // --- Wiimote State --- // #pragma warning(push) #pragma warning(disable:4201) //nameless struct/union typedef struct _WIIMOTE_STATE { WIIMOTE_WII_REMOTE_STATE WiiRemoteState; WIIMOTE_IR_STATE IRState; union { WIIMOTE_NUNCHUCK_STATE NunchuckState; WIIMOTE_BALANCE_BOARD_STATE BalanceBoardState; WIIMOTE_CLASSIC_CONTROLLER_STATE ClassicControllerState; WIIMOTE_GUITAR_STATE GuitarState; }; } WIIMOTE_STATE, *PWIIMOTE_STATE; #pragma warning(pop) VOID WiimoteStateResetToNullState(_In_ PDEVICE_CONTEXT DeviceContext); NTSTATUS WiimoteStateUpdate(_In_ PDEVICE_CONTEXT DeviceContext, _In_reads_bytes_(DataSize) PUCHAR Data, _In_ size_t DataSize); ================================================ FILE: HID Wiimote/WiimoteToHIDParser.c ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: WiimoteToHIDParser.c Abstract: Parses the current Wiimote State to a HID Read Report */ #include "WiimoteToHIDParser.h" #include "Wiimote.h" VOID ParseBooleanAxis( _In_ BOOLEAN MinimumValue, _In_ BOOLEAN MaximumValue, _Inout_ PUCHAR AxisValue, _In_ BOOLEAN Signed ) { BYTE MinValue = (Signed ? 0x81 : 0x00); BYTE MaxValue = (Signed ? 0x7F : 0xFF); BYTE NullValue = (Signed ? 0x00 : 0x7F); (*AxisValue) = MinimumValue ? MinValue : MaximumValue ? MaxValue : NullValue; } VOID ParseBooleanNonByteAxis( _In_ BOOLEAN MinimumValue, _In_ BOOLEAN MaximumValue, _Inout_ PUCHAR AxisValue, _In_ UCHAR LeastSignificantBitPosition, _In_ BYTE Bits, _In_ BOOLEAN Signed ) { UCHAR Value; ParseBooleanAxis(MinimumValue, MaximumValue, &Value, Signed); (*AxisValue) |= (Value >> (8 - Bits)) << LeastSignificantBitPosition; } VOID ParseButton( _In_ BOOLEAN ButtonValue, _Inout_ PUCHAR ButtonBitField, _In_ UCHAR LeastSignificantBitPosition ) { if (ButtonValue) { (*ButtonBitField) |= (0x01 << LeastSignificantBitPosition); } } VOID ParseAnalogAxis( _In_ BYTE RawValue, _Out_ PUCHAR AxisValue, _In_ BOOLEAN Signed, _In_ BOOLEAN Invert ) { if (Invert) { RawValue = ~RawValue; } if (Signed) { RawValue ^= 0x80; } (*AxisValue) = RawValue; } VOID ParseAccelerometer( _In_ BYTE RawValue, _Out_ PUCHAR AxisValue, _In_ BOOLEAN Invert ) { // Gravity is always present. 10 Bit Accelerometer data would have value of 96 (9,8 m/s). // As only the 8 MSBs are used the value is 24. To caputure that constant pull a value range from 0 to 63 is used (32 = nullstate). // For a range of 63 6 bits are used. // Normally 0x80 (128) is the middle of the 8 bit range, so cap the accelerometer data to a range of 32 around 128. RawValue = max(RawValue, 0x80 - 0x20); RawValue = min(RawValue, 0x80 + 0x1F); RawValue -= (0x80 - 0x20); if (Invert) { RawValue = RawValue ^ 0x3F; } (*AxisValue) = RawValue << 2; } BYTE GetTriggerValue( _In_ BYTE Trigger, _In_ BOOLEAN Button ) { if (Trigger == 0xFF) { return (Button ? 0x7C : 0x00); } else { return (Trigger << 2); } } VOID ParseTrigger( _In_ BYTE TriggerLValue, _In_ BYTE TriggerRValue, _In_ BOOLEAN ButtonRValue, _In_ BOOLEAN ButtonLValue, _In_ BOOLEAN ButtonZRValue, _In_ BOOLEAN ButtonZLValue, _In_ BOOLEAN SplitAxis, _In_ BOOLEAN SwapButtons, _Out_ BYTE ReportZByte[1], _Out_ BYTE ReportRZByte[1] ) { TriggerLValue = GetTriggerValue(TriggerLValue, (SwapButtons) ? ButtonZLValue : ButtonLValue); TriggerRValue = GetTriggerValue(TriggerRValue, (SwapButtons) ? ButtonZRValue : ButtonRValue); if (SplitAxis) { *ReportZByte = TriggerLValue << 1; *ReportRZByte = TriggerRValue << 1; } else { *ReportZByte = 0x80 - TriggerLValue + TriggerRValue; } } VOID ParseDPad( _In_ BOOLEAN Up, _In_ BOOLEAN Right, _In_ BOOLEAN Down, _In_ BOOLEAN Left, _Out_ PUCHAR HatswitchBitField ) { /* Up 1 0000 0001 0000 0000 Up-Right 2 0000 0010 0000 0001 Right 3 0000 0011 0000 0010 Down-Right 4 0000 0100 0000 0011 Down 5 0000 0101 0000 0100 Down-Left 6 0000 0110 0000 0101 Left 7 0000 0111 0000 0110 Up-Left 8 0000 1000 0000 0111 */ // Thanks to Waterlimon for this solution // See http://www.gamedev.net/topic/667868-direction-booleans-into-single-integer/ for more solutions. // // Branchless polynomial version (just for fun): // int64_t x = 3 * (up - down) + left - right; // return x * (x * (x * (x * (x * (x * (x * (x * (-31) - 28) + 938) + 840) - 8519) - 6972) + 24412) + 12880) / 3360; // const BYTE ValueLookUpTable[3][3] = { { 8, 1, 2 }, { 7, 0, 3 }, { 6, 5, 4 }, }; //BOOLEAN is a UCHAR in C //so make sure its numerical value is 1, some may have other values due to bit operations. Up = Up ? 1 : 0; Down = Down ? 1 : 0; Left = Left ? 1 : 0; Right = Right ? 1 : 0; (*HatswitchBitField) = ValueLookUpTable[Down + 1 - Up][Right + 1 - Left]; } UCHAR JoinSensorValue( _In_ USHORT ValueOne, _In_ USHORT ValueTwo ) { USHORT Value = (ValueOne + ValueTwo); return (UCHAR)(Value / 4); } BYTE ParseBalanceBoardSensors( _In_ UCHAR PositiveValueOne, _In_ UCHAR PositiveValueTwo, _In_ UCHAR NegativeValueOne, _In_ UCHAR NegativeValueTwo ) { UCHAR PositiveValue = JoinSensorValue(PositiveValueOne, PositiveValueTwo); UCHAR NegativeValue = JoinSensorValue(NegativeValueOne, NegativeValueTwo); BYTE Value = PositiveValue + 0x7F - NegativeValue; return Value; } UCHAR GetCalibratedBoardValue( _In_ USHORT Value, _In_reads_(3) PUSHORT CalibrationData) { /* Calibration - return range 0 - 255 ----------- 0 0 ... 1 128 ... 2 255 */ if (Value <= CalibrationData[0]) { return 0; } if (Value >= CalibrationData[2]) { return 255; } size_t CalibrationHigherBound = (Value > CalibrationData[1]) ? 2 : 1; const UCHAR SegmentRange = 128; USHORT RawRange = CalibrationData[CalibrationHigherBound] - CalibrationData[CalibrationHigherBound - 1]; DWORD32 RawValue = (Value - CalibrationData[CalibrationHigherBound - 1]); RawValue *= SegmentRange; UCHAR ActualValue = (UCHAR)(RawValue / RawRange); ActualValue += (UCHAR)(CalibrationHigherBound - 1) * SegmentRange; return ActualValue; } BOOLEAN AccumulateIRPoint( _In_ PWIIMOTE_IR_POINT Point, _Inout_ PUINT16 X, _Inout_ PUINT16 Y ) { // X ranges from 0-1023; Y from 0-767; so if Y == 0x3FF (1023) the point data is empty if (Point->Y != 0x3FF) { (*X) += Point->X; (*Y) += Point->Y; return TRUE; } return FALSE; } BOOLEAN ParseIRPoints( _In_ WIIMOTE_IR_POINT Points[WIIMOTE_IR_POINTS], _Out_ PUINT32 X, _Out_ PUINT32 Y ) { BYTE ValidPointCount = 0; UINT16 GroupX = 0; UINT16 GroupY = 0; for (BYTE i = 0; i < WIIMOTE_IR_POINTS; i++) { if (AccumulateIRPoint(&Points[i], &GroupX, &GroupY)) { ValidPointCount++; } } if (ValidPointCount > 0) { (*X) += GroupX / ValidPointCount; (*Y) += GroupY / ValidPointCount; return TRUE; } return FALSE; } VOID ParseIRCamera( _In_ WIIMOTE_IR_POINT Points[WIIMOTE_IR_POINTS_BUFFER_SIZE][WIIMOTE_IR_POINTS], _Out_ PUSHORT XAxis, _Out_ PUSHORT YAxis, _In_ BYTE XPadding, _In_ BYTE YPadding ) { BYTE ValidBufferCount = 0; UINT32 X = 0; UINT32 Y = 0; for (BYTE i = 0; i < WIIMOTE_IR_POINTS_BUFFER_SIZE; i++) { if (ParseIRPoints(Points[i], &X, &Y)) { ValidBufferCount++; } } if (ValidBufferCount == 0) { return; } X /= ValidBufferCount; Y /= ValidBufferCount; //Invert X X = WIIMOTE_IR_POINT_X_MAX - X; X = (X >= (UINT32)(WIIMOTE_IR_POINT_X_MAX - XPadding)) ? WIIMOTE_IR_POINT_X_MAX - XPadding : X; X = (X <= XPadding) ? 0 : X - XPadding; Y = (Y >= (UINT32)(WIIMOTE_IR_POINT_Y_MAX - YPadding)) ? WIIMOTE_IR_POINT_Y_MAX - YPadding : Y; Y = (Y <= YPadding) ? 0 : Y - YPadding; // Value = OldValue * NewMax / OldMax // Bug or Feature in at least Windows 8.1 HID Class, LOGCIAL_MAXIMUM musst be power of 2 - 1 X *= 1023; X /= WIIMOTE_IR_POINT_X_MAX - 2 * XPadding; Y *= 1023; Y /= WIIMOTE_IR_POINT_Y_MAX - 2 * YPadding; (*XAxis) = RtlUshortByteSwap(X); (*YAxis) = RtlUshortByteSwap(Y); } VOID ParseWiimoteStateAsStandaloneWiiremote( _In_ PWIIMOTE_STATE WiimoteState, _In_ PWIIMOTE_SETTINGS WiimoteSettings, _Out_ PHID_GAMEPAD_REPORT GamepadReport ) { //Axis ParseBooleanAxis(WiimoteState->WiiRemoteState.CoreButtons.DPad.Up, WiimoteState->WiiRemoteState.CoreButtons.DPad.Down, &GamepadReport->XAxis, FALSE); ParseBooleanAxis(WiimoteState->WiiRemoteState.CoreButtons.DPad.Right, WiimoteState->WiiRemoteState.CoreButtons.DPad.Left, &GamepadReport->YAxis, FALSE); //Buttons ParseButton(WiimoteState->WiiRemoteState.CoreButtons.One, &GamepadReport->Buttons[0], 0); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.Two, &GamepadReport->Buttons[0], 1); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.A, &GamepadReport->Buttons[0], 2); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.B, &GamepadReport->Buttons[0], 3); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.Plus, &GamepadReport->Buttons[0], 4); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.Minus, &GamepadReport->Buttons[0], 5); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.Home, &GamepadReport->Buttons[0], 6); //Accelerometer if(WiimoteSettings->EnableWiimoteXAxisAccelerometer) ParseAccelerometer(WiimoteState->WiiRemoteState.Accelerometer.Y, &GamepadReport->RXAxis, TRUE); if (WiimoteSettings->EnableWiimoteYAxisAcceleromenter) ParseAccelerometer(WiimoteState->WiiRemoteState.Accelerometer.X, &GamepadReport->RYAxis, TRUE); //ParseAccelerometer(WiimoteState->Accelerometer.Z, RequestBuffer + 3, 4); } VOID ParseWiimoteStateAsNunchuckExtension( _In_ PWIIMOTE_STATE WiimoteState, _In_ PWIIMOTE_SETTINGS WiimoteSettings, _Out_ PHID_GAMEPAD_REPORT GamepadReport ) { //AnalogStick as Axis ParseAnalogAxis(WiimoteState->NunchuckState.AnalogStick.X, &GamepadReport->XAxis, FALSE, FALSE); ParseAnalogAxis(WiimoteState->NunchuckState.AnalogStick.Y, &GamepadReport->YAxis, FALSE, TRUE); //Buttons ParseButton(WiimoteState->WiiRemoteState.CoreButtons.A, &GamepadReport->Buttons[0], 0); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.B, &GamepadReport->Buttons[0], 1); ParseButton(WiimoteState->NunchuckState.Buttons.C, &GamepadReport->Buttons[0], 2); ParseButton(WiimoteState->NunchuckState.Buttons.Z, &GamepadReport->Buttons[0], 3); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.One, &GamepadReport->Buttons[0], 4); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.Two, &GamepadReport->Buttons[0], 5); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.Plus, &GamepadReport->Buttons[0], 6); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.Minus, &GamepadReport->Buttons[0], 7); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.Home, &GamepadReport->Buttons[1], 0); //Accelerometer if (WiimoteSettings->EnableWiimoteXAxisAccelerometer) ParseAccelerometer(WiimoteState->WiiRemoteState.Accelerometer.X, &GamepadReport->RXAxis, TRUE); if (WiimoteSettings->EnableWiimoteYAxisAcceleromenter) ParseAccelerometer(WiimoteState->WiiRemoteState.Accelerometer.Y, &GamepadReport->RYAxis, TRUE); //DPad ParseDPad( WiimoteState->WiiRemoteState.CoreButtons.DPad.Up, WiimoteState->WiiRemoteState.CoreButtons.DPad.Right, WiimoteState->WiiRemoteState.CoreButtons.DPad.Down, WiimoteState->WiiRemoteState.CoreButtons.DPad.Left, &GamepadReport->Hatswitch); } VOID ParseWiimoteStateAsBalanceBoard( _In_ PWIIMOTE_STATE WiimoteState, _Out_ PHID_GAMEPAD_REPORT GamepadReport ) { UCHAR TopRight = GetCalibratedBoardValue(WiimoteState->BalanceBoardState.Sensor[WIIMOTE_BALANCE_BOARD_TOP_RIGHT], WiimoteState->BalanceBoardState.Calibration[WIIMOTE_BALANCE_BOARD_TOP_RIGHT]); UCHAR BottomRight = GetCalibratedBoardValue(WiimoteState->BalanceBoardState.Sensor[WIIMOTE_BALANCE_BOARD_BOTTOM_RIGHT], WiimoteState->BalanceBoardState.Calibration[WIIMOTE_BALANCE_BOARD_BOTTOM_RIGHT]); UCHAR TopLeft = GetCalibratedBoardValue(WiimoteState->BalanceBoardState.Sensor[WIIMOTE_BALANCE_BOARD_TOP_LEFT], WiimoteState->BalanceBoardState.Calibration[WIIMOTE_BALANCE_BOARD_TOP_LEFT]); UCHAR BottomLeft = GetCalibratedBoardValue(WiimoteState->BalanceBoardState.Sensor[WIIMOTE_BALANCE_BOARD_BOTTOM_LEFT], WiimoteState->BalanceBoardState.Calibration[WIIMOTE_BALANCE_BOARD_BOTTOM_LEFT]); GamepadReport->XAxis = ParseBalanceBoardSensors(BottomRight, TopRight, TopLeft, BottomLeft); GamepadReport->YAxis = ParseBalanceBoardSensors(BottomLeft, BottomRight, TopLeft, TopRight); // Balance Board has only a single button, that is reported as "A" ParseButton(WiimoteState->WiiRemoteState.CoreButtons.A, &GamepadReport->Buttons[0], 0); } VOID ParseWiimoteStateAsClassicControllerExtension( _In_ PWIIMOTE_STATE WiimoteState, _In_ PWIIMOTE_SETTINGS WiimoteSettings, _Out_ PHID_GAMEPAD_REPORT GamepadReport ) { //LeftAnalogStick as Axis ParseAnalogAxis(WiimoteState->ClassicControllerState.LeftAnalogStick.X, &GamepadReport->XAxis, FALSE, FALSE); ParseAnalogAxis(WiimoteState->ClassicControllerState.LeftAnalogStick.Y, &GamepadReport->YAxis, FALSE, TRUE); //Buttons ParseButton(WiimoteState->WiiRemoteState.CoreButtons.A || WiimoteState->ClassicControllerState.Buttons.A, &GamepadReport->Buttons[0], 0); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.B || WiimoteState->ClassicControllerState.Buttons.B, &GamepadReport->Buttons[0], 1); ParseButton(WiimoteState->ClassicControllerState.Buttons.Y, &GamepadReport->Buttons[0], 2); ParseButton(WiimoteState->ClassicControllerState.Buttons.X, &GamepadReport->Buttons[0], 3); if (WiimoteSettings->SwapTriggerAndShoulder || WiimoteSettings->MapTriggerAsButtons) { ParseButton(WiimoteState->ClassicControllerState.Buttons.L, &GamepadReport->Buttons[0], 4); ParseButton(WiimoteState->ClassicControllerState.Buttons.R, &GamepadReport->Buttons[0], 5); } if (!WiimoteSettings->SwapTriggerAndShoulder || WiimoteSettings->MapTriggerAsButtons) { ParseButton(WiimoteState->ClassicControllerState.Buttons.ZL, &GamepadReport->Buttons[0], 6); ParseButton(WiimoteState->ClassicControllerState.Buttons.ZR, &GamepadReport->Buttons[0], 7); } ParseButton(WiimoteState->WiiRemoteState.CoreButtons.Plus || WiimoteState->ClassicControllerState.Buttons.Plus, &GamepadReport->Buttons[1], 0); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.Minus || WiimoteState->ClassicControllerState.Buttons.Minus, &GamepadReport->Buttons[1], 1); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.Home || WiimoteState->ClassicControllerState.Buttons.Home, &GamepadReport->Buttons[1], 2); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.One || WiimoteState->ClassicControllerState.Buttons.LH, &GamepadReport->Buttons[1], 3); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.Two || WiimoteState->ClassicControllerState.Buttons.RH, &GamepadReport->Buttons[1], 4); //Right Analog Stick as Second Axis ParseAnalogAxis(WiimoteState->ClassicControllerState.RightAnalogStick.X, &GamepadReport->RXAxis, FALSE, FALSE); ParseAnalogAxis(WiimoteState->ClassicControllerState.RightAnalogStick.Y, &GamepadReport->RYAxis, FALSE, TRUE); if (WiimoteSettings->MapTriggerAsAxis) { ParseTrigger( WiimoteState->ClassicControllerState.LeftTrigger, WiimoteState->ClassicControllerState.RightTrigger, WiimoteState->ClassicControllerState.Buttons.R, WiimoteState->ClassicControllerState.Buttons.L, WiimoteState->ClassicControllerState.Buttons.ZR, WiimoteState->ClassicControllerState.Buttons.ZL, WiimoteSettings->SplitTriggerAxis, WiimoteSettings->SwapTriggerAndShoulder, &GamepadReport->ZAxis, &GamepadReport->RZAxis ); } //DPad ParseDPad( WiimoteState->WiiRemoteState.CoreButtons.DPad.Up || WiimoteState->ClassicControllerState.Buttons.DPad.Up, WiimoteState->WiiRemoteState.CoreButtons.DPad.Right || WiimoteState->ClassicControllerState.Buttons.DPad.Right, WiimoteState->WiiRemoteState.CoreButtons.DPad.Down || WiimoteState->ClassicControllerState.Buttons.DPad.Down, WiimoteState->WiiRemoteState.CoreButtons.DPad.Left || WiimoteState->ClassicControllerState.Buttons.DPad.Left, &GamepadReport->Hatswitch); } VOID ParseWiimoteStateAsGuitarExtension( _In_ PWIIMOTE_STATE WiimoteState, _Out_ PHID_GAMEPAD_REPORT GamepadReport ) { // LeftAnalogStick as Axis ParseAnalogAxis(WiimoteState->GuitarState.AnalogStick.X, &GamepadReport->XAxis, FALSE, FALSE); ParseAnalogAxis(WiimoteState->GuitarState.AnalogStick.Y, &GamepadReport->YAxis, FALSE, TRUE); // Buttons ParseButton(WiimoteState->GuitarState.Buttons.Green, &GamepadReport->Buttons[0], 0); ParseButton(WiimoteState->GuitarState.Buttons.Red, &GamepadReport->Buttons[0], 1); ParseButton(WiimoteState->GuitarState.Buttons.Yellow, &GamepadReport->Buttons[0], 2); ParseButton(WiimoteState->GuitarState.Buttons.Blue, &GamepadReport->Buttons[0], 3); ParseButton(WiimoteState->GuitarState.Buttons.Orange, &GamepadReport->Buttons[0], 4); ParseButton(WiimoteState->GuitarState.Buttons.Up, &GamepadReport->Buttons[0], 5); ParseButton(WiimoteState->GuitarState.Buttons.Down, &GamepadReport->Buttons[0], 6); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.Plus || WiimoteState->GuitarState.Buttons.Plus, &GamepadReport->Buttons[1], 0); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.Minus || WiimoteState->GuitarState.Buttons.Minus, &GamepadReport->Buttons[1], 1); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.One, &GamepadReport->Buttons[1], 2); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.Two, &GamepadReport->Buttons[1], 3); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.A, &GamepadReport->Buttons[1], 4); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.B, &GamepadReport->Buttons[1], 5); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.Home, &GamepadReport->Buttons[1], 6); // Analog Bars ParseAnalogAxis(WiimoteState->GuitarState.WhammyBar, &GamepadReport->ZAxis, FALSE, FALSE); ParseAnalogAxis(WiimoteState->GuitarState.TouchBar, &GamepadReport->RZAxis, FALSE, TRUE); // DPad ParseDPad( WiimoteState->WiiRemoteState.CoreButtons.DPad.Up, WiimoteState->WiiRemoteState.CoreButtons.DPad.Right, WiimoteState->WiiRemoteState.CoreButtons.DPad.Down, WiimoteState->WiiRemoteState.CoreButtons.DPad.Left, &GamepadReport->Hatswitch); } VOID ParseWiimoteStateAsGamepad( _In_ PWIIMOTE_DEVICE_CONTEXT WiimoteContext, _Inout_updates_all_(BufferSize) PVOID Buffer, _In_ size_t BufferSize, _Out_ PSIZE_T BytesWritten ) { PHID_GAMEPAD_REPORT GamepadReport = (PHID_GAMEPAD_REPORT)Buffer; PWIIMOTE_STATE WiimoteState = &(WiimoteContext->State); PWIIMOTE_SETTINGS WiimoteSettings = &(WiimoteContext->Settings); if (BufferSize < sizeof(HID_GAMEPAD_REPORT)) { Trace("Gamepad Report Buffer seems to be too small: %d - %d", BufferSize, sizeof(HID_GAMEPAD_REPORT)); } //ASSERT(BufferSize < sizeof(HID_GAMEPAD_REPORT)); HID_GAMEPAD_REPORT_INIT(GamepadReport); switch (WiimoteContext->Extension) { case None: ParseWiimoteStateAsStandaloneWiiremote(WiimoteState, WiimoteSettings, GamepadReport); break; case Nunchuck: ParseWiimoteStateAsNunchuckExtension(WiimoteState, WiimoteSettings, GamepadReport); break; case BalanceBoard: ParseWiimoteStateAsBalanceBoard(WiimoteState, GamepadReport); break; case ClassicController: case ClassicControllerPro: case WiiUProController: ParseWiimoteStateAsClassicControllerExtension(WiimoteState, WiimoteSettings, GamepadReport); break; case Guitar: ParseWiimoteStateAsGuitarExtension(WiimoteState, GamepadReport); default: break; } (*BytesWritten) = sizeof(HID_GAMEPAD_REPORT); } VOID ParseWiimoteStateAsDPadMouse( _In_ PWIIMOTE_STATE WiimoteState, _Inout_updates_all_(BufferSize) PVOID Buffer, _In_ size_t BufferSize, _Out_ PSIZE_T BytesWritten ) { PHID_DPADMOUSE_REPORT DPadMouseReport = (PHID_DPADMOUSE_REPORT)Buffer; if (BufferSize < sizeof(HID_DPADMOUSE_REPORT)) { Trace("DPadMouse Report Buffer seems to be too small: %d - %d", BufferSize, sizeof(HID_DPADMOUSE_REPORT)); } //ASSERT(BufferSize < sizeof(HID_DPADMOUSE_REPORT)); HID_DPADMOUSE_REPORT_INIT(DPadMouseReport); //Buttons ParseButton(WiimoteState->WiiRemoteState.CoreButtons.One, &DPadMouseReport->Buttons, 0); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.Two, &DPadMouseReport->Buttons, 1); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.B, &DPadMouseReport->Buttons, 2); //Axis ParseBooleanNonByteAxis(WiimoteState->WiiRemoteState.CoreButtons.DPad.Up, WiimoteState->WiiRemoteState.CoreButtons.DPad.Down, &DPadMouseReport->X, 6, 2, TRUE); ParseBooleanNonByteAxis(WiimoteState->WiiRemoteState.CoreButtons.DPad.Right, WiimoteState->WiiRemoteState.CoreButtons.DPad.Left, &DPadMouseReport->Y, 6, 2, TRUE); (*BytesWritten) = sizeof(HID_DPADMOUSE_REPORT); } VOID ParseWiimoteStateAsIRMouse( _In_ PWIIMOTE_STATE WiimoteState, _Inout_updates_all_(BufferSize) PVOID Buffer, _In_ size_t BufferSize, _Out_ PSIZE_T BytesWritten ) { PHID_IRMOUSE_REPORT IRMouseReport = (PHID_IRMOUSE_REPORT)Buffer; if (BufferSize < sizeof(HID_IRMOUSE_REPORT)) { Trace("IRMouse Report Buffer seems to be too small: %d - %d", BufferSize, sizeof(HID_IRMOUSE_REPORT)); } //ASSERT(BufferSize < sizeof(HID_IRMOUSE_REPORT)); HID_IRMOUSE_REPORT_INIT(IRMouseReport); //Buttons ParseButton(WiimoteState->WiiRemoteState.CoreButtons.A, &IRMouseReport->Buttons, 0); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.B, &IRMouseReport->Buttons, 1); ParseButton(WiimoteState->WiiRemoteState.CoreButtons.Home, &IRMouseReport->Buttons, 2); //Axis ParseIRCamera(WiimoteState->IRState.Points, &IRMouseReport->X, &IRMouseReport->Y, 128, 121); (*BytesWritten) = sizeof(HID_IRMOUSE_REPORT); } ================================================ FILE: HID Wiimote/WiimoteToHIDParser.h ================================================ /* Copyright (C) 2017 Julian Lhr All rights reserved. Filename: WiimoteToHIDParser.h Abstract: Header file for WiimoteToHIDParser.c */ #pragma once #include "HIDWiimote.h" #include "HIDDescriptors.h" #include "WiimoteState.h" VOID ParseWiimoteStateAsGamepad(_In_ PWIIMOTE_DEVICE_CONTEXT WiimoteContext, _Inout_updates_all_(BufferSize) PVOID Buffer, _In_ size_t BufferSize, _Out_ PSIZE_T BytesWritten); VOID ParseWiimoteStateAsDPadMouse(_In_ PWIIMOTE_STATE WiimoteState, _Inout_updates_all_(BufferSize) PVOID Buffer, _In_ size_t BufferSize, _Out_ PSIZE_T BytesWritten); VOID ParseWiimoteStateAsIRMouse(_In_ PWIIMOTE_STATE WiimoteState, _Inout_updates_all_(BufferSize) PVOID Buffer, _In_ size_t BufferSize, _Out_ PSIZE_T BytesWritten); ================================================ FILE: HID Wiimote/resource.h ================================================ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by HID Wiimote.rc // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 101 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif ================================================ FILE: HID Wiimote Control Center/App.config ================================================ ================================================ FILE: HID Wiimote Control Center/App.xaml ================================================  ================================================ FILE: HID Wiimote Control Center/App.xaml.cs ================================================ /* Copyright (C) 2017 Julian Löhr All rights reserved. Filename: App.cs Abstract: App class */ using System; using System.Windows; namespace HIDWiimote.ControlCenter { /// /// Interaction logic for App.xaml /// public partial class App : Application { SingleInstanceProtector SingleInstanceProtector; public App() { AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; } private void OnStartup(object sender, StartupEventArgs e) { SingleInstanceProtector = new SingleInstanceProtector(); if (!SingleInstanceProtector.IsFirstInstance()) { SingleInstanceProtector.ShowOtherAppInstance(); Shutdown(); return; } DeviceDriverUninstallerRegistry.DeviceDriverState DPState = DeviceDriverUninstallerRegistry.GetDeviceDriverState(VersionStrings.DeviceDriverVersion, out string InstalledDeviceDriverVersionString); switch (DPState) { case DeviceDriverUninstallerRegistry.DeviceDriverState.NoneInstalled: // Installer Window StartupUri = new Uri("Main Windows\\InstallerWindow.xaml", UriKind.Relative); break; case DeviceDriverUninstallerRegistry.DeviceDriverState.OlderInstalled: // Update Windows StartupUri = new Uri("Main Windows\\UpdaterWindow.xaml", UriKind.Relative); break; case DeviceDriverUninstallerRegistry.DeviceDriverState.CurrentInstalled: // Control Center StartupUri = new Uri("Main Windows\\ControlCenterWindow.xaml", UriKind.Relative); break; case DeviceDriverUninstallerRegistry.DeviceDriverState.NewerInstalled: // Show Notice & shutdown MessageBox.Show(string.Format(HIDWiimote.ControlCenter.Properties.App.NewerInstalledDialog_MainMessage, VersionStrings.DeviceDriverVersion, InstalledDeviceDriverVersionString), "HID Wiimote Control Center", MessageBoxButton.OK, MessageBoxImage.Exclamation); Shutdown(); return; } } public static void ChangeMainWindow(Window NewWindow, Window CallingWindow) { Current.MainWindow = NewWindow; NewWindow.Show(); CallingWindow.Close(); } private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { Exception Exception = e.ExceptionObject as Exception; while (Exception != null) { MessageBox.Show("An unhandled exception of type '" + Exception.GetType() + "' occured in '" + Exception.Source + "'.\n\nAdditional information: " + Exception.Message + "\n\nStack trace: \n" + Exception.StackTrace, Exception.GetType().ToString(), MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.None, MessageBoxOptions.DefaultDesktopOnly); Exception = Exception.InnerException; } } } } ================================================ FILE: HID Wiimote Control Center/Control Center/DummyDeviceInterface.cs ================================================ /* Copyright (C) 2017 Julian Löhr All rights reserved. Filename: DummyDeviceInterface.cs Abstract: Dummy Implementation of the Device Interface for simpler UI debugging */ using System; using HIDWiimote.UserModeLib; using System.Threading; namespace HIDWiimote.ControlCenter.Control_Center { class DummyDeviceInterface : UserModeLib.IWiimoteDeviceInterface { private int DummySleep = 500; public event EventHandler DeviceRemoved { add { } remove { } } public event EventHandler StatusUpdate { add { } remove { } } public void Disconnect() { } public State Initialize() { return new State(); } public bool SetDriverMode(DriverMode NewMode) { Thread.Sleep(DummySleep); return true; } public bool SetEnableWiimoteXAxisAccelerometer(bool Enabled) { Thread.Sleep(DummySleep); return true; } public bool SetEnableWiimoteYAxisAccelerometer(bool Enabled) { Thread.Sleep(DummySleep); return true; } public bool SetSwapMouseButtons(bool Enabled) { Thread.Sleep(DummySleep); return true; } public bool SetSwapTriggerAndShoulder(bool Enabled) { Thread.Sleep(DummySleep); return true; } public bool SetSplitTrigger(bool Enabled) { Thread.Sleep(DummySleep); return true; } public bool SetMapTriggerAsAxis(bool Enabled) { Thread.Sleep(DummySleep); return true; } public bool SetMapTriggerAsButtons(bool Enabled) { Thread.Sleep(DummySleep); return true; } } } ================================================ FILE: HID Wiimote Control Center/Control Center/WiimoteDevice.cs ================================================ /* Copyright (C) 2017 Julian Löhr All rights reserved. Filename: WiimoteDevice.cs Abstract: Instance of a single Wii Remote Device used for data binding on UI */ using System; using System.ComponentModel; using System.Threading.Tasks; namespace HIDWiimote.ControlCenter.Control_Center { public class WiimoteDevice : INotifyPropertyChanged { public class Option : INotifyPropertyChanged { private Type _Value; private bool _UIEnabled = true; private Func InterfaceDelegate; public event PropertyChangedEventHandler PropertyChanged; public Option(Func InterfaceDelegate) { this.InterfaceDelegate = InterfaceDelegate; } public Type Value { get { return _Value; } set { ChangeValue(value); } } public bool UIEnabled { get { return _UIEnabled; } protected set { _UIEnabled = value; OnPropertyChanged("UIEnabled"); } } public void SetValue(Type Value) { _Value = Value; OnPropertyChanged("Value"); } protected void ChangeValue(Type RequestedValue) { UIEnabled = false; Task.Factory.StartNew(() => { if ((InterfaceDelegate == null) || (InterfaceDelegate(RequestedValue))) { SetValue(RequestedValue); } UIEnabled = true; }); } protected void OnPropertyChanged(string PropertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName)); } } private UserModeLib.IWiimoteDeviceInterface DeviceInterface; private bool _Initilized = false; private UserModeLib.Extension _Extension = UserModeLib.Extension.None; private byte _BatteryLevel = 0; private bool[] _LEDState = { false, false, false, false }; public Option Mode { get; set; } public Option EnableWiimoteXAxisAccelerometer { get; set; } public Option EnableWiimoteYAxisAccelerometer { get; set; } public Option SwapMouseButtons { get; set; } public Option SwapTriggerAndShoulder { get; set; } public Option SplitTriggerAxis { get; set; } public Option MapTriggerAsAxis { get; set; } public Option MapTriggerAsButtons { get; set; } public event PropertyChangedEventHandler PropertyChanged; public event EventHandler Disconneted; public WiimoteDevice(UserModeLib.IWiimoteDeviceInterface DeviceInterface) { this.DeviceInterface = DeviceInterface; DeviceInterface.StatusUpdate += OnStatusUpdate; DeviceInterface.DeviceRemoved += OnDeviceRemoved; Mode = new Option(DeviceInterface.SetDriverMode); EnableWiimoteXAxisAccelerometer = new Option(DeviceInterface.SetEnableWiimoteXAxisAccelerometer); EnableWiimoteYAxisAccelerometer = new Option(DeviceInterface.SetEnableWiimoteYAxisAccelerometer); SwapMouseButtons = new Option(DeviceInterface.SetSwapMouseButtons); SwapTriggerAndShoulder = new Option(DeviceInterface.SetSwapTriggerAndShoulder); SplitTriggerAxis = new Option(DeviceInterface.SetSplitTrigger); MapTriggerAsAxis = new Option(DeviceInterface.SetMapTriggerAsAxis); MapTriggerAsButtons = new Option(DeviceInterface.SetMapTriggerAsButtons); EnableWiimoteXAxisAccelerometer.PropertyChanged += OnEnableAccelerometerAxisChanged; EnableWiimoteYAxisAccelerometer.PropertyChanged += OnEnableAccelerometerAxisChanged; } public UserModeLib.Extension Extension { get { return _Extension; } set { _Extension = value; OnPropertyChanged("Extension"); } } public byte BatteryLevel { get { return (byte)(0x00FF - _BatteryLevel); } set { _BatteryLevel = value; OnPropertyChanged("BatteryLevel"); } } public bool[] LEDState { get { return _LEDState; } set { _LEDState = value; OnPropertyChanged("LEDState"); } } public bool EnableAccelerometers { get { return EnableWiimoteXAxisAccelerometer.Value || EnableWiimoteYAxisAccelerometer.Value; } set { EnableWiimoteXAxisAccelerometer.Value = value; EnableWiimoteYAxisAccelerometer.Value = value; OnPropertyChanged("EnableAccelerometers"); } } private void OnEnableAccelerometerAxisChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "Value") { OnPropertyChanged("EnableAccelerometers"); } } public bool Initilized { get { return _Initilized; } set { _Initilized = value; OnPropertyChanged("Initilized"); } } protected void OnPropertyChanged(string PropertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName)); } public void Disconnect() { DeviceInterface.Disconnect(); } public void Initilize() { Task.Factory.StartNew(InitilizeAction); } protected void InitilizeAction() { UserModeLib.State InitinalState = DeviceInterface.Initialize(); if(InitinalState == null) { DeviceInterface.Disconnect(); return; } ApplyState(InitinalState); Initilized = true; } private void OnDeviceRemoved(object sender, System.EventArgs e) { DeviceInterface.StatusUpdate -= OnStatusUpdate; DeviceInterface.DeviceRemoved -= OnDeviceRemoved; Disconneted?.Invoke(this, null); } private void OnStatusUpdate(object sender, UserModeLib.Status StatusUpdate) { ApplyStatus(StatusUpdate); } protected void ApplyState(UserModeLib.State State) { Mode.SetValue(State.Mode); EnableWiimoteXAxisAccelerometer.SetValue(State.EnableWiimoteXAxisAccelerometer); EnableWiimoteYAxisAccelerometer.SetValue(State.EnableWiimoteYAxisAccelerometer); SwapMouseButtons.SetValue(State.SwapMouseButtons); SwapTriggerAndShoulder.SetValue(State.SwapTriggerAndShoulder); SplitTriggerAxis.SetValue(State.SplitTrigger); MapTriggerAsAxis.SetValue(State.MapTriggerAsAxis); MapTriggerAsButtons.SetValue(State.MapTriggerAsButtons); ApplyStatus(State.Status); } protected void ApplyStatus(UserModeLib.Status Status) { Extension = Status.Extension; BatteryLevel = Status.BatteryLevel; LEDState = Status.LEDState; } } } ================================================ FILE: HID Wiimote Control Center/HID Wiimote Control Center.csproj ================================================  Debug AnyCPU {D91AA07C-75AF-47B7-B3EE-CBEFD7AA5616} WinExe Properties HIDWiimote.ControlCenter HID Wiimote Control Center v4.7.1 512 {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 4 true false publish\ true Disk false Foreground 7 Days false false true 0 1.0.0.%2a false true 2.0 LocalIntranet false Properties\app.manifest true bin\x86\Debug\ DEBUG;TRACE full x86 prompt MinimumRecommendedRules.ruleset bin\x86\Release\ TRACE true pdbonly x86 prompt MinimumRecommendedRules.ruleset true bin\x64\Debug\ DEBUG;TRACE full x64 prompt MinimumRecommendedRules.ruleset bin\x64\Release\ TRACE true pdbonly x64 prompt MinimumRecommendedRules.ruleset 4.0 MSBuild:Compile Designer True True ControlCenter.resx ControlCenterWindow.xaml True True Installer.resx About.xaml InstallerWindow.xaml LEDDisplay.xaml TaskList.xaml UpdaterWindow.xaml Designer MSBuild:Compile Designer MSBuild:Compile App.xaml Code Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Code True True App.resx True Settings.settings True PublicResXFileCodeGenerator ControlCenter.Designer.cs PublicResXFileCodeGenerator Installer.Designer.cs ResXFileCodeGenerator App.Designer.cs Designer SettingsSingleFileGenerator Settings.Designer.cs False Microsoft .NET Framework 4.5.2 %28x86 and x64%29 true False .NET Framework 3.5 SP1 false {591eee1a-3007-4d38-910a-af3d065105f9} HID Wiimote User Mode C:\Program Files (x86)\Windows Kits\10\bin\x86\signtool.exe copy /y "$(SolutionDir)ReleaseVersioning\VersionStrings.cs" "$(SolutionDir)HID Wiimote Control Center\Properties\VersionStrings.cs" "$(SignTool)" sign /a "$(TargetName)$(TargetExt)" ================================================ FILE: HID Wiimote Control Center/Main Windows/ControlCenterWindow.xaml ================================================  ================================================ FILE: HID Wiimote Control Center/Main Windows/ControlCenterWindow.xaml.cs ================================================ /* Copyright (C) 2017 Julian Löhr All rights reserved. Filename: ControlCenterWindow.xaml.cs Abstract: Main Window for the Application */ using HIDWiimote.ControlCenter.Control_Center; using System; using System.Collections.Generic; using System.Globalization; using System.Windows; using System.Windows.Data; namespace HIDWiimote.ControlCenter.Main_Windows { /// /// Interaction logic for ControlCenterWindow.xaml /// public partial class ControlCenterWindow : Window { List ConnectedWiimoteDevices = new List(); HIDWiimote.UserModeLib.WiimoteDeviceInterfaceDiscoverer DeviceInterfaceDiscoverer; public ControlCenterWindow() { InitializeComponent(); } private void OnInitialized(object sender, System.EventArgs e) { ConnectedDevicesListBox.ItemsSource = ConnectedWiimoteDevices; DeviceInterfaceDiscoverer = new UserModeLib.WiimoteDeviceInterfaceDiscoverer(); DeviceInterfaceDiscoverer.NewWiimoteDeviceInterfaceFound += OnNewWiimoteDeviceInterfaceFound; DeviceInterfaceDiscoverer.Start(); #if DEBUG OnNewWiimoteDeviceInterfaceFound(this, new DummyDeviceInterface()); #endif } private void OnNewWiimoteDeviceInterfaceFound(object sender, UserModeLib.IWiimoteDeviceInterface NewInterface) { Application.Current.Dispatcher.Invoke(() => { WiimoteDevice NewWiimoteDevice = new WiimoteDevice(NewInterface); NewWiimoteDevice.Disconneted += OnWiimoteDeviceDisconneted; ConnectedWiimoteDevices.Add(NewWiimoteDevice); ConnectedDevicesListBox.Items.Refresh(); if(ConnectedDevicesListBox.SelectedItem == null) { ConnectedDevicesListBox.SelectedItem = NewWiimoteDevice; } NewWiimoteDevice.Initilize(); }); } private void OnWiimoteDeviceDisconneted(object sender, EventArgs e) { Application.Current.Dispatcher.Invoke(() => { WiimoteDevice DisconnectedWiimoteDevice = sender as WiimoteDevice; ConnectedWiimoteDevices.Remove(DisconnectedWiimoteDevice); ConnectedDevicesListBox.Items.Refresh(); if ((ConnectedDevicesListBox.SelectedItem == null) && ConnectedDevicesListBox.HasItems) { ConnectedDevicesListBox.SelectedItem = ConnectedDevicesListBox.Items[0]; } }); } private void OnInstallerClick(object sender, RoutedEventArgs e) { App.ChangeMainWindow(new InstallerWindow(), this); } private void OnAboutClick(object sender, RoutedEventArgs e) { Secondary_Windows.About AboutDialog = new Secondary_Windows.About(); AboutDialog.Owner = this; AboutDialog.ShowDialog(); } private static Dictionary WiimoteDeviceModeTypeDescriptionsDictionary = new Dictionary() { { UserModeLib.DriverMode.Gamepad, HIDWiimote.ControlCenter.Properties.ControlCenter.ModeString_Gamepad }, { UserModeLib.DriverMode.PassThrough, HIDWiimote.ControlCenter.Properties.ControlCenter.ModeString_PassThrough }, { UserModeLib.DriverMode.GamepadAndIRMouse, HIDWiimote.ControlCenter.Properties.ControlCenter.ModeString_GamepadAndIRMouse }, { UserModeLib.DriverMode.IRMouse, HIDWiimote.ControlCenter.Properties.ControlCenter.ModeString_IRMouse }, { UserModeLib.DriverMode.DPadMouse, HIDWiimote.ControlCenter.Properties.ControlCenter.ModeString_DPadMouse } }; public Dictionary WiimoteDeviceModeTypeDescriptions { get { return WiimoteDeviceModeTypeDescriptionsDictionary; } } private void OnClosing(object sender, System.ComponentModel.CancelEventArgs e) { if(DeviceInterfaceDiscoverer != null) { DeviceInterfaceDiscoverer.Stop(); } foreach(WiimoteDevice WiimoteDevice in ConnectedWiimoteDevices) { WiimoteDevice.Disconneted -= OnWiimoteDeviceDisconneted; WiimoteDevice.Disconnect(); } ConnectedWiimoteDevices.Clear(); ConnectedDevicesListBox.Items.Refresh(); } } public class ExtensionToStringConverter : IValueConverter { public string WiimoteString { get; set; } public string NunchuckString { get; set; } public string ClassicControllerString { get; set; } public string ClassicControllerProString { get; set; } public string WiiUProControllerString { get; set; } public string BalanceBoardString { get; set; } public string GuitarHeroString { get; set; } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { UserModeLib.Extension Extension = (UserModeLib.Extension)value; switch (Extension) { case UserModeLib.Extension.None: return WiimoteString; case UserModeLib.Extension.Nunchuck: return NunchuckString; case UserModeLib.Extension.BalanceBoard: return BalanceBoardString; case UserModeLib.Extension.ClassicController: return ClassicControllerString; case UserModeLib.Extension.ClassicControllerPro: return ClassicControllerProString; case UserModeLib.Extension.WiiUProController: return WiiUProControllerString; case UserModeLib.Extension.Guitar: return GuitarHeroString; default: return "Error"; } } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } public class ModeToStringConverter : IValueConverter { public string GamepadString { get; set; } public string GamepadAndIRMouseString { get; set; } public string IRMouseString { get; set; } public string DPadMouseString { get; set; } public string PassThroughString { get; set; } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { UserModeLib.DriverMode Mode = (UserModeLib.DriverMode)value; switch (Mode) { case UserModeLib.DriverMode.Gamepad: return GamepadString; case UserModeLib.DriverMode.PassThrough: return PassThroughString; case UserModeLib.DriverMode.GamepadAndIRMouse: return GamepadAndIRMouseString; case UserModeLib.DriverMode.IRMouse: return IRMouseString; case UserModeLib.DriverMode.DPadMouse: return DPadMouseString; default: return "Error"; } } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } } ================================================ FILE: HID Wiimote Control Center/Main Windows/InstallerWindow.xaml ================================================