nuclear@1: /************************************************************************************ nuclear@1: nuclear@1: Filename : OVR_Win32_HIDDevice.h nuclear@1: Content : Win32 HID device implementation. nuclear@1: Created : February 22, 2013 nuclear@1: Authors : Lee Cooper nuclear@1: nuclear@1: Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved. nuclear@1: nuclear@1: Use of this software is subject to the terms of the Oculus license nuclear@1: agreement provided at the time of installation or download, or which nuclear@1: otherwise accompanies this software in either electronic or hard copy form. nuclear@1: nuclear@1: *************************************************************************************/ nuclear@1: nuclear@1: #ifndef OVR_Win32_HIDDevice_h nuclear@1: #define OVR_Win32_HIDDevice_h nuclear@1: nuclear@1: #include "OVR_HIDDevice.h" nuclear@1: #include "OVR_Win32_DeviceManager.h" nuclear@1: nuclear@1: #include nuclear@1: #include nuclear@1: nuclear@1: //------------------------------------------------------------------------------------- nuclear@1: // Define needed "hidsdi.h" functionality to avoid requiring DDK installation. nuclear@1: // #include "hidsdi.h" nuclear@1: nuclear@1: #ifndef _HIDSDI_H nuclear@1: #define _HIDSDI_H nuclear@1: #include nuclear@1: nuclear@1: #define HIDP_STATUS_SUCCESS (0x11 << 16) nuclear@1: struct HIDP_PREPARSED_DATA; nuclear@1: nuclear@1: struct HIDD_ATTRIBUTES nuclear@1: { nuclear@1: ULONG Size; // = sizeof (struct _HIDD_ATTRIBUTES) nuclear@1: USHORT VendorID; nuclear@1: USHORT ProductID; nuclear@1: USHORT VersionNumber; nuclear@1: }; nuclear@1: nuclear@1: struct HIDP_CAPS nuclear@1: { nuclear@1: USHORT Usage; nuclear@1: USHORT UsagePage; nuclear@1: USHORT InputReportByteLength; nuclear@1: USHORT OutputReportByteLength; nuclear@1: USHORT FeatureReportByteLength; nuclear@1: USHORT Reserved[17]; nuclear@1: nuclear@1: USHORT NumberLinkCollectionNodes; nuclear@1: USHORT NumberInputButtonCaps; nuclear@1: USHORT NumberInputValueCaps; nuclear@1: USHORT NumberInputDataIndices; nuclear@1: USHORT NumberOutputButtonCaps; nuclear@1: USHORT NumberOutputValueCaps; nuclear@1: USHORT NumberOutputDataIndices; nuclear@1: USHORT NumberFeatureButtonCaps; nuclear@1: USHORT NumberFeatureValueCaps; nuclear@1: USHORT NumberFeatureDataIndices; nuclear@1: }; nuclear@1: nuclear@1: #include nuclear@1: #endif nuclear@1: nuclear@1: nuclear@1: namespace OVR { namespace Win32 { nuclear@1: nuclear@1: class HIDDeviceManager; nuclear@1: class DeviceManager; nuclear@1: nuclear@1: //------------------------------------------------------------------------------------- nuclear@1: // ***** Win32 HIDDevice nuclear@1: nuclear@1: class HIDDevice : public OVR::HIDDevice, public DeviceManagerThread::Notifier nuclear@1: { nuclear@1: public: nuclear@1: nuclear@1: HIDDevice(HIDDeviceManager* manager); nuclear@1: nuclear@1: // This is a minimal constructor used during enumeration for us to pass nuclear@1: // a HIDDevice to the visit function (so that it can query feature reports). nuclear@1: HIDDevice(HIDDeviceManager* manager, HANDLE device); nuclear@1: nuclear@1: ~HIDDevice(); nuclear@1: nuclear@1: bool HIDInitialize(const String& path); nuclear@1: void HIDShutdown(); nuclear@1: nuclear@1: // OVR::HIDDevice nuclear@1: bool SetFeatureReport(UByte* data, UInt32 length); nuclear@1: bool GetFeatureReport(UByte* data, UInt32 length); nuclear@1: nuclear@1: nuclear@1: // DeviceManagerThread::Notifier nuclear@1: void OnOverlappedEvent(HANDLE hevent); nuclear@1: UInt64 OnTicks(UInt64 ticksMks); nuclear@1: bool OnDeviceMessage(DeviceMessageType messageType, const String& devicePath, bool* error); nuclear@1: nuclear@1: private: nuclear@1: bool openDevice(); nuclear@1: bool initInfo(); nuclear@1: bool initializeRead(); nuclear@1: bool processReadResult(); nuclear@1: void closeDevice(); nuclear@1: void closeDeviceOnIOError(); nuclear@1: nuclear@1: bool inMinimalMode; nuclear@1: HIDDeviceManager* HIDManager; nuclear@1: HANDLE Device; nuclear@1: HIDDeviceDesc DevDesc; nuclear@1: nuclear@1: OVERLAPPED ReadOverlapped; nuclear@1: bool ReadRequested; nuclear@1: nuclear@1: enum { ReadBufferSize = 96 }; nuclear@1: UByte ReadBuffer[ReadBufferSize]; nuclear@1: nuclear@1: UInt16 InputReportBufferLength; nuclear@1: UInt16 OutputReportBufferLength; nuclear@1: UInt16 FeatureReportBufferLength; nuclear@1: }; nuclear@1: nuclear@1: //------------------------------------------------------------------------------------- nuclear@1: // ***** Win32 HIDDeviceManager nuclear@1: nuclear@1: class HIDDeviceManager : public OVR::HIDDeviceManager nuclear@1: { nuclear@1: friend class HIDDevice; nuclear@1: public: nuclear@1: nuclear@1: HIDDeviceManager(DeviceManager* manager); nuclear@1: virtual ~HIDDeviceManager(); nuclear@1: nuclear@1: virtual bool Initialize(); nuclear@1: virtual void Shutdown(); nuclear@1: nuclear@1: virtual bool Enumerate(HIDEnumerateVisitor* enumVisitor); nuclear@1: virtual OVR::HIDDevice* Open(const String& path); nuclear@1: nuclear@1: // Fills HIDDeviceDesc by using the path. nuclear@1: // Returns 'true' if successful, 'false' otherwise. nuclear@1: bool GetHIDDeviceDesc(const String& path, HIDDeviceDesc* pdevDesc) const; nuclear@1: nuclear@1: GUID GetHIDGuid() { return HidGuid; } nuclear@1: nuclear@1: static HIDDeviceManager* CreateInternal(DeviceManager* manager); nuclear@1: nuclear@1: private: nuclear@1: nuclear@1: DeviceManager* Manager; // Back pointer can just be a raw pointer. nuclear@1: nuclear@1: HMODULE hHidLib; nuclear@1: GUID HidGuid; nuclear@1: nuclear@1: // Macros to declare and resolve needed functions from library. nuclear@1: #define OVR_DECLARE_HIDFUNC(func, rettype, args) \ nuclear@1: typedef rettype (__stdcall *PFn_##func) args; \ nuclear@1: PFn_##func func; nuclear@1: #define OVR_RESOLVE_HIDFUNC(func) \ nuclear@1: func = (PFn_##func)::GetProcAddress(hHidLib, #func) nuclear@1: nuclear@1: OVR_DECLARE_HIDFUNC(HidD_GetHidGuid, void, (GUID *hidGuid)); nuclear@1: OVR_DECLARE_HIDFUNC(HidD_SetNumInputBuffers, BOOLEAN, (HANDLE hidDev, ULONG numberBuffers)); nuclear@1: OVR_DECLARE_HIDFUNC(HidD_GetFeature, BOOLEAN, (HANDLE hidDev, PVOID buffer, ULONG bufferLength)); nuclear@1: OVR_DECLARE_HIDFUNC(HidD_SetFeature, BOOLEAN, (HANDLE hidDev, PVOID buffer, ULONG bufferLength)); nuclear@1: OVR_DECLARE_HIDFUNC(HidD_GetAttributes, BOOLEAN, (HANDLE hidDev, HIDD_ATTRIBUTES *attributes)); nuclear@1: OVR_DECLARE_HIDFUNC(HidD_GetManufacturerString, BOOLEAN, (HANDLE hidDev, PVOID buffer, ULONG bufferLength)); nuclear@1: OVR_DECLARE_HIDFUNC(HidD_GetProductString, BOOLEAN, (HANDLE hidDev, PVOID buffer, ULONG bufferLength)); nuclear@1: OVR_DECLARE_HIDFUNC(HidD_GetSerialNumberString, BOOLEAN, (HANDLE hidDev, PVOID buffer, ULONG bufferLength)); nuclear@1: OVR_DECLARE_HIDFUNC(HidD_GetPreparsedData, BOOLEAN, (HANDLE hidDev, HIDP_PREPARSED_DATA **preparsedData)); nuclear@1: OVR_DECLARE_HIDFUNC(HidD_FreePreparsedData, BOOLEAN, (HIDP_PREPARSED_DATA *preparsedData)); nuclear@1: OVR_DECLARE_HIDFUNC(HidP_GetCaps, NTSTATUS,(HIDP_PREPARSED_DATA *preparsedData, HIDP_CAPS* caps)); nuclear@1: nuclear@1: HANDLE CreateHIDFile(const char* path, bool exclusiveAccess = true) const nuclear@1: { nuclear@1: return ::CreateFileA(path, GENERIC_WRITE|GENERIC_READ, nuclear@1: (!exclusiveAccess) ? (FILE_SHARE_READ|FILE_SHARE_WRITE) : 0x0, nuclear@1: NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); nuclear@1: } nuclear@1: nuclear@1: // Helper functions to fill in HIDDeviceDesc from open device handle. nuclear@1: bool initVendorProductVersion(HANDLE hidDev, HIDDeviceDesc* desc) const; nuclear@1: bool initUsage(HANDLE hidDev, HIDDeviceDesc* desc) const; nuclear@1: void initStrings(HANDLE hidDev, HIDDeviceDesc* desc) const; nuclear@1: nuclear@1: bool getFullDesc(HANDLE hidDev, HIDDeviceDesc* desc) const; nuclear@1: }; nuclear@1: nuclear@1: }} // namespace OVR::Win32 nuclear@1: nuclear@1: #endif // OVR_Win32_HIDDevice_h