HID - abfrage eines Joysticks - HidD_GetInputReport problem
Verfasst: 12.11.2018 21:53
Die Joystickroutinen von PB sind ja nicht so prall (bspw. tauchen XINPUT-Geräte 2x auf), ich versuch gerade das ganze anders zu lösen. Zumal ich die Eingaben immer brauche, auch wenn das Fenster nicht im Focus ist.
XINPUT hat das Problem, das nur XBOX-Controller abgefragt werden können und nicht bspw. PS4- Controller.
Ich hab jetzt 1 1/2 Lösungen. Eine über die RAW-DATA-Routinen von Windows, die klappt wunderbar in 32Bit und 64Bit.
Jetzt wollte ich noch den Schritt machen und direkt auf abfrage abzufragen, das klappt aber überhaupt nicht.
HIDD_GetInputReport funktioniert nicht und liefert nie eine brauchbare Information.
Hat jemand brauchbaren Code, wie man die Buttons und Achsen nur mittels HID abfragen kann?
XINPUT hat das Problem, das nur XBOX-Controller abgefragt werden können und nicht bspw. PS4- Controller.
Ich hab jetzt 1 1/2 Lösungen. Eine über die RAW-DATA-Routinen von Windows, die klappt wunderbar in 32Bit und 64Bit.
Jetzt wollte ich noch den Schritt machen und direkt auf abfrage abzufragen, das klappt aber überhaupt nicht.
HIDD_GetInputReport funktioniert nicht und liefert nie eine brauchbare Information.
Hat jemand brauchbaren Code, wie man die Buttons und Achsen nur mittels HID abfragen kann?
Code: Alles auswählen
;https://www.codeproject.com/Articles/185522/Using-the-Raw-Input-API-to-Process-Joystick-Input
;https://docs.microsoft.com/en-us/windows/desktop/winprog/windows-data-types
;https://www.codeproject.com/Articles/192941/HID-Application-Class-for-Easy-Reading-of-Joystick
;https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf
;https://katyscode.wordpress.com/2013/08/30/xinput-tutorial-part-1-adding-gamepad-support-to-your-windows-game/
DeclareModule joy
EnableExplicit
#HIDID_PS4 = $09CC0000054C
#HIDID_XBOXONE = $02FF0000045E
#HIDID_XBOX360 = $028E0000045E
Structure _Axis_Info
exist.i
value.i
EndStructure
Structure _Axis
x._Axis_Info
y._Axis_Info
z._Axis_Info
rx._Axis_Info
ry._Axis_Info
rz._Axis_Info
Slider._Axis_info
Dial._Axis_Info
Wheel._Axis_Info
EndStructure
Structure _DPad
exist.i
x.i
y.i
EndStructure
Structure _Button
Number.i
Value.l
EndStructure
Structure _HID
VendorId.l
ProductId.l
EndStructure
Structure sJoystick
Name.s
StructureUnion
HID._HID
HIDID.Q
EndStructureUnion
StructureUnion
Axis._Axis
AxisNb._Axis_Info[9]
EndStructureUnion
DPad._DPad
Button._Button
EndStructure
Declare init()
Declare exit()
Declare scan();Search for devices
Declare Register(WindowNb,without_focus=#False)
Declare CheckEvent(WindowEvent)
Declare EnableRemapPS4(flag)
Declare Enumerate(List Handle.i())
Declare LastState(handle);return *joystick.joystick
Declare Examine(hDevice)
EndDeclareModule
Module Joy
Procedure.s ShowError ()
Protected error, *MemoryID,length,e$
error = GetLastError_ ()
If error
*MemoryID = AllocateMemory (255)
length = FormatMessage_ (#FORMAT_MESSAGE_FROM_SYSTEM, #Null, error, 0, *MemoryID, 255, #Null)
If length > 1 ; Some error messages are "" + Chr (13) + Chr (10)... stoopid M$... :(
e$ = PeekS (*MemoryID, length - 2)
Else
e$ = "Unknown error!"
EndIf
FreeMemory (*MemoryID)
ProcedureReturn ""+error+" "+e$
Else
ProcedureReturn "No error has occurred!"
EndIf
EndProcedure
Declare Parse(*PreparseData,hDevice,*report,reportLen,hidhandle=0)
Global DLLuser32, DLLhid
Global PS4Remap
;
; Case $30: *axis=Joysticks()\Joystick\Axis\x
; Case $31: *axis=Joysticks()\Joystick\Axis\y
; Case $32: *axis=Joysticks()\Joystick\Axis\z
; Case $33: *axis=Joysticks()\Joystick\Axis\rx
; Case $34: *axis=Joysticks()\Joystick\Axis\ry
; Case $35: *axis=Joysticks()\Joystick\Axis\rz
; Case $36: *axis=Joysticks()\Joystick\Axis\Slider
Macro PS4AxisRemap(d)
If ps4remap
If d=$32
d=$33
ElseIf d=$33
d=$32
ElseIf d=$35
d=$34
ElseIf d=$34
d=$35
EndIf
EndIf
EndMacro
Macro PS4ButtonRemap(d)
If ps4remap
Select d
Case 1:d=0
Case 2:d=1
;3=3
Case 0:d=2
Case 9:d=7
Case 13:d=6
Case 11:d=9
Case 10:d=8
;4=4
;5=5
Case 6:d=$FF
Case 7:d=$FF
Case 8:d=13
EndSelect
EndIf
EndMacro
;{ HID-Prototype
Prototype.l prot_GetRawInputDeviceList (pRawInputDeviceList.i,puiNumDevices.i,cbSize.l)
Prototype.l prot_GetRawInputDeviceInfoW (hDevice.i,uiCommand.l,pData.i,pcbSize.i)
Prototype.l prot_RegisterRawInputDevices (pRawInputDevices.i,uiNumDevices.l,cbSize.l)
Prototype.l prot_GetRawInputData (hRawInput.i,uiCommand.l,pdata.i,pcbSize.i,cbSizeHeader.l)
Prototype.l prot_HidP_GetCaps (pPreparsedData.i,pCapabilities.i)
Prototype.l prot_HidP_GetButtonCaps (ReportType.l, pButtonCaps.i, puiButtonCapsLength.i, pPreparsedData.i)
Prototype.l prot_HidP_GetValueCaps (ReportType.l, pValueCaps.i , puiValueCapsLength.i , pPreparsedData.i)
Prototype.l prot_HidP_GetUsages (ReportType.l, wUsagePage.w , uLinkCollection.u, pUsageList.i, plUsageLength.i, pPreparsedData.i, pcReport.i, lReportLength.l)
Prototype.l prot_HidP_GetUsageValue (ReportType.l, wUsagePage.w , ULinkCollection.u, wUsage.w, pulValue.i, pPreparsedData.i, pcReport.i, lReportLength.l)
Prototype.l prot_HidP_GetScaledUsageValue (ReportType.l, wUsagePage.w , ULinkCollection.u, wUsage.w, pulValue.i, pPreparsedData.i, pcReport.i, lReportLength.l)
Prototype.l prot_HidP_InitializeReportForID (ReportType.l,ReportID.a,pPreparsedData.i, pcReport.i, lReportLength.l)
Prototype.b prot_HidD_GetProductString (HidDeviceObject.i, pBuffer.i, BufferLength.l)
Prototype.b prot_HidD_GetPreparsedData (HidDeviceObject.i, pPreparsedData.i)
Prototype.b prot_HidD_FreePreparsedData (PreparsedData.i)
Prototype.b prot_HidD_GetInputReport (HidDeviceObject.i, pReportBuffer.i, lReportBufferLength.l)
Global GetRawInputDeviceList.prot_GetRawInputDeviceList
Global GetRawInputDeviceInfo.prot_GetRawInputDeviceInfoW
Global RegisterRawInputDevices.prot_RegisterRawInputDevices
Global GetRawInputData.prot_GetRawInputData
Global HidP_InitializeReportForID.prot_HidP_InitializeReportForID
Global HidP_GetCaps.prot_HidP_GetCaps
Global HidP_GetButtonCaps.prot_HidP_GetButtonCaps
Global HidP_GetValueCaps.prot_HidP_GetValueCaps
Global HidP_GetUsages.prot_HidP_GetUsages
Global HidP_GetUsageValue.prot_HidP_GetUsageValue
Global HidP_GetScaledUsageValue.prot_HidP_GetScaledUsageValue
Global HidD_GetProductString.prot_HidD_GetProductString
Global HidD_GetPreparsedData.prot_HidD_GetPreparsedData
Global HidD_FreePreparsedData.prot_HidD_FreePreparsedData
Global HidD_GetInputReport.prot_HidD_GetInputReport
;}
#HID_Error=$10000000
#Buf256Size=256*2;widechar
Global *buf256
;{ HID-Structures
Structure RAWINPUTDEVICELIST_ Align #PB_Structure_AlignC
hDevice.i
dwType.l
EndStructure
Macro RAWINPUTDEVICELIST:RAWINPUTDEVICELIST_:EndMacro
Structure RID_DEVICE_INFO_HID_ Align #PB_Structure_AlignC
dwVendorId.l
dwProductId.l
dwVersionNumber.l
usUsagePage.w
usUsage.w
EndStructure
Macro RID_DEVICE_INFO_HID:RID_DEVICE_INFO_HID_:EndMacro
Structure RID_DEVICE_INFO_KEYBOARD_ Align #PB_Structure_AlignC
dwType.l
dwSubType.l
dwKeyboardMode.l
dwNumberOfFunctionKeys.l
dwNumberOfIndicators.l
dwNumberOfKeysTotal.l
EndStructure
Macro RID_DEVICE_INFO_KEYBOARD:RID_DEVICE_INFO_KEYBOARD_:EndMacro
Structure RID_DEVICE_INFO_MOUSE_ Align #PB_Structure_AlignC
dwId.l
dwNumberOfButtons.l
dwSampleRate.l
fHasHorizontalWheel.l
EndStructure
Macro RID_DEVICE_INFO_MOUSE:RID_DEVICE_INFO_MOUSE_:EndMacro
Structure RID_DEVICE_INFO_ Align #PB_Structure_AlignC
cbSize.l
dwType.l
StructureUnion
mouse.RID_DEVICE_INFO_MOUSE_
keyboard.RID_DEVICE_INFO_KEYBOARD_
hid.RID_DEVICE_INFO_HID_
EndStructureUnion
EndStructure
Macro RID_DEVICE_INFO:RID_DEVICE_INFO_:EndMacro
Structure RAWINPUTDEVICE_ Align #PB_Structure_AlignC
usUsagePage.w
usUsage.w
dwFlags.l
hwndTarget.i
EndStructure
Macro RAWINPUTDEVICE:RAWINPUTDEVICE_:EndMacro
Structure RAWINPUTHEADER_ Align #PB_Structure_AlignC
dwType.l
dwSize.l
hDevice.i
wParam.i
EndStructure
Macro RAWINPUTHEADER:RAWINPUTHEADER_:EndMacro
Structure RAWMOUSE_BUTTON_ Align #PB_Structure_AlignC
usButtonFlags.w
usButtonData.w
EndStructure
Macro RAWMOUSE_BUTTON:RAWMOUSE_BUTTON_:EndMacro
Structure RAWMOUSE_ Align #PB_Structure_AlignC
usFlags.w
StructureUnion
ulButtons.l
usButton.RAWMOUSE_BUTTON
EndStructureUnion
ulRawButtons.l
lLastX.l
lLastY.l
ulExtraInformation.l
EndStructure
Macro RAWMOUSE:RAWMOUSE_:EndMacro
Structure RAWKEYBOARD_ Align #PB_Structure_AlignC
MakeCode.w
Flags.w
Reserved.w
VKey.w
Message.l
ExtraInformation.l
EndStructure
Macro RAWKEYBOARD:RAWKEYBOARD_:EndMacro
Structure RAWHID_ Align #PB_Structure_AlignC
dwSizeHid.l
dwCount.l
bRawData.b[1]
EndStructure
Macro RAWHID:RAWHID_:EndMacro
Structure RAWINPUT_ Align #PB_Structure_AlignC
header.RAWINPUTHEADER
StructureUnion
mouse.RAWMOUSE
keyboard.RAWKEYBOARD
hid.RAWHID
EndStructureUnion
EndStructure
Macro RAWINPUT:RAWINPUT_:EndMacro
Structure HIDP_CAPS Align #PB_Structure_AlignC
UsagePage.w
Usage.w
InputReportByteLength.u
OutputReportByteLength.u
FeatureReportByteLength.u
Reserved.u[17]
NumberLinkCollectionNodes.u
NumberInputButtonCaps.u
NumberInputValueCaps.u
NumberInputDataIndices.u
NumberOutputButtonCaps.u
NumberOutputValueCaps.u
NumberOutputDataIndices.u
NumberFeatureButtonCaps.u
NumberFeatureValueCaps.u
NumberFeatureDataIndices.u
EndStructure
Structure _HIDP_CAPS_Range Align #PB_Structure_AlignC
UsageMin.w
UsageMax.w
StringMin.u
StringMax.u
DesignatorMin.u
DesignatorMax.u
DataIndexMin.u
DataIndexMax.u
EndStructure
Structure _HIDP_CAPS_NotRange Align #PB_Structure_AlignC
Reserved1.w
Usage.w
StringIndex.u
Reserved2.u
DesignatorIndex.u
Reserved3.u
DataIndex.u
Reserved4.u
EndStructure
Structure HIDP_BUTTON_CAPS Align #PB_Structure_AlignC
UsagePage.w;
ReportID.a ;
IsAlias.b ;
BitField.u ;
LinkCollection.u;
LinkUsage.w ;
LinkUsagePage.w ;
IsRange.b ;
IsStringRange.b ;
IsDesignatorRange.b;
IsAbsolute.b ;
Reserved.l[10] ;
StructureUnion
Range._HIDP_CAPS_Range
NotRange._HIDP_CAPS_NotRange
EndStructureUnion
EndStructure
Structure HIDP_VALUE_CAPS Align #PB_Structure_AlignC
UsagePage.w;
ReportID.a ;
IsAlias.b ;
BitField.u ;
LinkCollection.u;
LinkUsage.w ;
LinkUsagePage.w ;
IsRange.b ;
IsStringRange.b ;
IsDesignatorRange.b;
IsAbsolute.b ;
HasNull.b ;
Reserved.a ;
BitSize.u
ReportCount.u ;
Reserved2.u[5] ;
UnitsExp.l ;
Units.l ;
LogicalMin.l
LogicalMax.l ;
PhysicalMin.l ;
PhysicalMax.l ;
StructureUnion
Range._HIDP_CAPS_Range
NotRange._HIDP_CAPS_NotRange
EndStructureUnion
EndStructure
;}
;{ Constants
#RIDI_DEVICENAME=$20000007
#RIDI_DEVICEINFO=$2000000b
#RIDI_PREPARSEDDATA=$20000005
#RIM_TYPEHID=2
#RIM_TYPEKEYBOARD=1
#RIM_TYPEMOUSE=0
#RID_HEADER=$10000005
#RID_INPUT=$10000003
#RIDEV_INPUTSINK=$00000100
#HIDP_STATUS_SUCCESS=$110000
Enumeration HIDP_REPORT_TYPE
#HidP_Input
#HidP_Output
#HidP_Feature
EndEnumeration
;}
Procedure init()
If DLLuser32<>0
ProcedureReturn #False
EndIf
DLLuser32=OpenLibrary(#PB_Any,"user32.dll")
DLLhid=OpenLibrary(#PB_Any,"hid.dll")
GetRawInputDeviceList= GetFunction(DLLuser32, "GetRawInputDeviceList")
GetRawInputDeviceInfo = GetFunction(DLLuser32, "GetRawInputDeviceInfoW")
RegisterRawInputDevices = GetFunction(DLLuser32, "RegisterRawInputDevices")
GetRawInputData = GetFunction(DLLuser32, "GetRawInputData")
HidP_GetCaps = GetFunction(DLLhid, "HidP_GetCaps")
HidP_GetButtonCaps = GetFunction(DLLhid, "HidP_GetButtonCaps")
HidP_GetValueCaps = GetFunction(DLLhid, "HidP_GetValueCaps")
HidP_GetUsages = GetFunction(DLLhid, "HidP_GetUsages")
HidP_GetUsageValue = GetFunction(DLLhid, "HidP_GetUsageValue")
HidP_InitializeReportForID = GetFunction(DLLhid, "HidP_InitializeReportForID")
HidD_GetProductString = GetFunction(DLLhid, "HidD_GetProductString")
HidD_GetPreparsedData = GetFunction(DllHid, "HidD_GetPreparsedData")
HidD_FreePreparsedData = GetFunction(DLLhid, "HidD_FreePreparsedData")
HidD_GetInputReport = GetFunction(DLLhid, "HidD_GetInputReport")
*buf256=AllocateMemory(#Buf256Size)
ProcedureReturn scan()
EndProcedure
Procedure exit()
If DLLuser32=0
ProcedureReturn #False
EndIf
CloseLibrary(DLLuser32)
CloseLibrary(DLLhid)
DLLuser32=0
DLLhid=0
GetRawInputDeviceList= 0
GetRawInputDeviceInfo = 0
RegisterRawInputDevices = 0
GetRawInputData = 0
HidP_GetCaps = 0
HidP_GetButtonCaps = 0
HidP_GetValueCaps = 0
HidP_GetUsages = 0
HidP_GetUsageValue = 0
HidP_GetScaledUsageValue = 0
HidP_InitializeReportForID = 0
HidD_GetProductString = 0
HidD_GetPreparsedData = 0
HidD_FreePreparsedData = 0
HidD_GetInputReport = 0
FreeMemory(*buf256)
*buf256=0
EndProcedure
Procedure EnableRemapPS4(flag)
PS4Remap=flag
EndProcedure
Structure _sJoysticks_caps
InputReportByteLength.u
NumberInputButtonCaps.u
NumberInputValueCaps.u
EndStructure
Structure _sJoysticks_Hid
hDevice.i
DevicePath.s
Usage.u
UsagePage.u
EndStructure
Structure sJoysticks
Hid._sJoysticks_Hid
Caps._sJoysticks_caps
Joystick.sJoystick
EndStructure
Global NewList Joysticks.sJoysticks()
Procedure ClearJoysticks()
ClearList( joysticks() )
EndProcedure
Procedure Enumerate(List handle.i())
ClearList(handle())
ForEach joysticks()
AddElement(handle())
handle()=Joysticks()\Hid\hDevice
Next
ProcedureReturn ListSize(joysticks())
EndProcedure
Procedure scan()
Protected size.u,count.u,i,hidHandle
Protected DeviceInfo.RID_DEVICE_INFO
Protected caps.HIDP_CAPS
Protected PD.i,*ButtonCaps.HIDP_BUTTON_CAPS,capsLength.u,pos
ClearJoysticks()
If GetRawInputDeviceList(#Null,@count,SizeOf (RAWINPUTDEVICELIST) )>#HID_Error Or count=0
ProcedureReturn #False
EndIf
Dim Devices.RAWINPUTDEVICELIST(count-1)
If GetRawInputDeviceList(@devices(),@count,SizeOf(RAWINPUTDEVICELIST))>#HID_Error
ProcedureReturn #False
EndIf
For pos=0 To count-1
If Devices(pos)\dwType=#RIM_TYPEHID
size.u=SizeOf(rid_device_info)
If GetRawInputDeviceInfo(devices(pos)\hDevice,#RIDI_DEVICEINFO,@DeviceInfo,@size)>#HID_Error
ClearStructure(DeviceInfo,RID_DEVICE_INFO)
EndIf
If DeviceInfo\hid\usUsagePage=$1 And (DeviceInfo\hid\usUsage=4 Or DeviceInfo\hid\usUsage=5)
AddElement(joysticks())
joysticks()\hid\hDevice = devices(pos)\hDevice
joysticks()\Joystick\HID\VendorId = DeviceInfo\hid\dwVendorId
joysticks()\Joystick\hid\ProductId = DeviceInfo\hid\dwProductId
joysticks()\hid\Usage = DeviceInfo\hid\usUsage
joysticks()\hid\UsagePage = DeviceInfo\hid\usUsagePage
;Device Path
size.u=#Buf256Size
If GetRawInputDeviceInfo(devices(pos)\hDevice,#RIDI_DEVICENAME,*buf256,@size)<#HID_Error
joysticks()\hid\DevicePath=PeekS(*buf256)
hidHandle=CreateFile_(*buf256,#GENERIC_READ|#GENERIC_WRITE,#FILE_SHARE_READ|#FILE_SHARE_WRITE,#Null,#OPEN_EXISTING,#Null,#Null)
If hidHandle
If HidD_GetProductString(hidHandle,*buf256,#Buf256Size)
joysticks()\Joystick\Name=PeekS(*buf256)
EndIf
If HidD_GetPreparsedData(hidHandle,@pd)
If HidP_GetCaps(pd, @caps)=#HIDP_STATUS_SUCCESS
joysticks()\Caps\InputReportByteLength = caps\InputReportByteLength
joysticks()\Caps\NumberInputButtonCaps = caps\NumberInputButtonCaps
joysticks()\Caps\NumberInputValueCaps = caps\NumberInputValueCaps
EndIf
;Number of Buttons
*ButtonCaps=AllocateMemory(SizeOf(HIDP_BUTTON_CAPS) * caps\NumberInputButtonCaps)
capsLength.u = Caps\NumberInputButtonCaps
If HidP_GetButtonCaps(#HidP_Input, *ButtonCaps, @capsLength,pd) = #HIDP_STATUS_SUCCESS
If *ButtonCaps\IsRange And *ButtonCaps\IsAbsolute And *ButtonCaps\UsagePage=$09
Joysticks()\Joystick\Button\Number = *ButtonCaps\Range\UsageMax - *ButtonCaps\range\UsageMin+1
EndIf
EndIf
FreeMemory(*ButtonCaps)
;Axis
Dim ValueCaps.HIDP_VALUE_CAPS(caps\NumberInputValueCaps-1)
capsLength.u = caps\NumberInputValueCaps
If HidP_GetValueCaps( #HidP_Input,@ValueCaps(), @capsLength,pd) = #HIDP_STATUS_SUCCESS
For i=0 To caps\NumberInputValueCaps-1
If ValueCaps(i)\IsAbsolute And ValueCaps(i)\IsRange=#False And ValueCaps(i)\UsagePage=1 And (ValueCaps(i)\NotRange\Usage=>$30 And ValueCaps(i)\NotRange\Usage<=$39)
If ValueCaps(i)\NotRange\Usage=$39
joysticks()\Joystick\DPad\exist=#True
Else
If joysticks()\Joystick\HIDid=#HIDID_PS4
PS4AxisRemap(ValueCaps(i)\NotRange\Usage)
EndIf
joysticks()\Joystick\AxisNb[ ValueCaps(i)\NotRange\Usage -$30 ]\exist=#True
EndIf
EndIf
Next
EndIf
HidD_FreePreparsedData(pd)
pd=0
EndIf
CloseHandle_(hidHandle)
EndIf
EndIf
EndIf
EndIf
Next
Protected json
json=CreateJSON(#PB_Any)
If json
InsertJSONList(JSONValue(json), joysticks())
Debug ComposeJSON(json, #PB_JSON_PrettyPrint)
FreeJSON(json)
EndIf
ProcedureReturn ListSize(joysticks())
EndProcedure
Procedure Register(WindowNb,without_focus=#False)
Dim rid.RAWINPUTDEVICE(1)
rid(0)\usUsagePage=1
rid(0)\usUsage=5
rid(0)\hwndTarget=WindowID(WindowNb)
rid(0)\dwFlags=#RIDEV_DEVNOTIFY
rid(1)\usUsagePage=1
rid(1)\usUsage=4
rid(1)\hwndTarget=WindowID(WindowNb)
rid(1)\dwFlags=#RIDEV_DEVNOTIFY
If without_focus
rid(0)\dwFlags | #RIDEV_INPUTSINK
rid(1)\dwFlags | #RIDEV_INPUTSINK
EndIf
ProcedureReturn registerrawinputdevices(rid(),2,SizeOf(RAWINPUTDEVICE))
EndProcedure
Macro _FreeWMInput()
If *rawinput
FreeMemory(*rawinput):*rawinput=0
EndIf
If *PreparseData
FreeMemory(*PreparseData):*PreparseData=0
EndIf
EndMacro
Procedure Parse_WM_Input()
Protected size.u,ret
Protected hDevice,*report,reportLen
Protected *Rawinput.RAWINPUT,*PreparseData,buffersize.u
;Get size
If GetRawInputData(EventlParam(),#RID_INPUT,#Null,@size,SizeOf(RAWINPUTHEADER))<>0
ProcedureReturn #False
EndIf
;Allocate Memory
*Rawinput=AllocateMemory(size)
If *Rawinput=0
_FreeWMInput()
ProcedureReturn #False
EndIf
;Get *RawInput
If GetRawInputData(EventlParam(),#RID_INPUT,*Rawinput,@size,SizeOf(RAWINPUTHEADER))<>size
_FreeWMInput()
ProcedureReturn #False
EndIf
hDevice=*Rawinput\header\hDevice
*report = @ *Rawinput\hid\bRawData
reportLen = *Rawinput\hid\dwSizeHid
Protected ok
;Find Joystick
ForEach Joysticks()
If hDevice= Joysticks()\hid\hDevice
ok=#True
Break
EndIf
Next
If ok=#False
_FreeWMInput()
ProcedureReturn #False
EndIf
;Get BUffersize
If GetRawInputDeviceInfo( hDevice, #RIDI_PREPARSEDDATA ,#Null, @buffersize)<>0
_FreeWMInput()
ProcedureReturn #False
EndIf
;Allocate
*PreparseData=AllocateMemory(buffersize)
If *PreparseData=0
_FreeWMInput()
ProcedureReturn #False
EndIf
;Get PreparseData
If GetRawInputDeviceInfo( hDevice, #RIDI_PREPARSEDDATA ,*PreparseData,@buffersize)<>buffersize
_FreeWMInput()
ProcedureReturn #False
EndIf
ret=Parse(*PreparseData,hDevice,*report,reportLen)
_FreeWMInput()
ProcedureReturn ret
EndProcedure
Procedure GetReport(HidDeviceObject.i, Type.i, id.a, *report.ascii, reportLen.l, *PreparseData)
Debug ""+HidDeviceObject+" "+type+" "+id+" "+ *report +" "+reportLen+" "+*PreparseData
If HidP_InitializeReportForID(type,id,*PreparseData,*report,reportLen) <> #HIDP_STATUS_SUCCESS
Debug "inital-error"
ProcedureReturn #False
EndIf
If HidD_GetInputReport(HidDeviceObject,*report,reportLen-1) = 0
Debug "input-Report-error"
ProcedureReturn #False
EndIf
ProcedureReturn #True
EndProcedure
Procedure Examine(hDevice)
Protected ok,hidHandle,pd,*ret,*report
;Find Joystick
ForEach Joysticks()
If hDevice= Joysticks()\hid\hDevice
ok=#True
Break
EndIf
Next
If ok=#False
ProcedureReturn #False
EndIf
*report=AllocateMemory(joysticks()\Caps\InputReportByteLength+2)
If *report
hidHandle=CreateFile_(joysticks()\Hid\DevicePath,#GENERIC_READ|#GENERIC_WRITE,#FILE_SHARE_READ|#FILE_SHARE_WRITE,#Null,#OPEN_EXISTING,#FILE_FLAG_OVERLAPPED,#Null)
If hidHandle=#INVALID_HANDLE_VALUE
hidHandle=0
EndIf
Debug "HidHandle:"+hidHandle
If hidHandle
Debug "ok"
If HidD_GetPreparsedData(hidHandle,@pd)
Protected hidcaps.HIDP_CAPS
If parse(pd,hDevice,*report,joysticks()\Caps\InputReportByteLength,hidHandle)
*ret=joysticks()\Joystick
EndIf
HidD_FreePreparsedData(pd)
pd=0
EndIf
CloseHandle_(hidHandle)
EndIf
FreeMemory(*report)
EndIf
ProcedureReturn *ret
EndProcedure
Macro _freeParse()
EndMacro
Procedure Parse(*PreparseData,hDevice,*report,reportLen,hidhandle=0); Joysticks() must be set!
Protected capsLength.u,usageLength.l,i,value.l,bitmask.l,half.i
; Check Buttons
;Get ButtonCaps
capsLength.u = joysticks()\Caps\NumberInputButtonCaps
Dim ButtonCaps.HIDP_BUTTON_CAPS( capsLength-1 )
If HidP_GetButtonCaps(#HidP_Input, @ButtonCaps(0), @capsLength,*PreparseData) <> #HIDP_STATUS_SUCCESS
ProcedureReturn #False
EndIf
;Get Buttons
If ButtonCaps(0)\IsRange And ButtonCaps(0)\IsAbsolute And ButtonCaps(0)\UsagePage=$09
If hidhandle And GetReport(hidhandle,#HidP_Input,buttoncaps(0)\ReportID,*report,reportLen,*PreparseData)=#False
Debug "GetReportError"
;ProcedureReturn #False
EndIf
usageLength.l=ButtonCaps(0)\Range\UsageMax - ButtonCaps(0)\range\UsageMin+1
Dim usage.u(usageLength)
joysticks()\Joystick\Button\Value=0
If HidP_GetUsages( #HidP_Input, ButtonCaps(0)\UsagePage, #Null, @usage(), @usageLength, *PreparseData, *report, reportLen) = #HIDP_STATUS_SUCCESS
For i=0 To usageLength-1
usage(i) - ButtonCaps(0)\Range\UsageMin
If joysticks()\Joystick\HIDid=#HIDID_PS4
PS4ButtonRemap(usage(i))
EndIf
If usage(i)<32
joysticks()\Joystick\Button\Value | (1 << usage(i))
EndIf
Next
EndIf
EndIf
;Get ValueCaps
capsLength.u = joysticks()\caps\NumberInputValueCaps
Dim ValueCaps.HIDP_VALUE_CAPS( capsLength-1 )
If HidP_GetValueCaps( #HidP_Input, @ValueCaps(0), @capsLength,*PreparseData) <> #HIDP_STATUS_SUCCESS
ProcedureReturn #False
EndIf
;Get Values
For i=0 To joysticks()\Caps\NumberInputValueCaps-1
If ValueCaps(i)\IsAbsolute And ValueCaps(i)\IsRange=#False And ValueCaps(i)\UsagePage=1 And (ValueCaps(i)\NotRange\Usage=>$30 And ValueCaps(i)\NotRange\Usage<=$39)
If hidhandle And GetReport(hidhandle,#HidP_Input,ValueCaps(i)\ReportID,*report,reportLen,*PreparseData)=#False
;ProcedureReturn #False
EndIf
If HidP_GetUsageValue( #HidP_Input, ValueCaps(i)\UsagePage, #Null, ValueCaps(i)\NotRange\Usage, @value.l,*PreparseData, *report, reportLen)= #HIDP_STATUS_SUCCESS
If ValueCaps(i)\NotRange\Usage=$39
;Debug ""+Joysticks()\Joystick\nb+" "+ValueCaps(i)\HasNull+" "+ValueCaps(i)\LogicalMin+" - "+ValueCaps(i)\LogicalMax
joysticks()\Joystick\DPad\x=0
joysticks()\Joystick\DPad\y=0
Select value-ValueCaps(i)\LogicalMin
Case 7,0,1:joysticks()\Joystick\DPad\y=-1
Case 5,4,3:joysticks()\Joystick\DPad\y=1
EndSelect
Select value-ValueCaps(i)\LogicalMin
Case 7,6,5:joysticks()\Joystick\DPad\x=-1
Case 1,2,3:joysticks()\Joystick\DPad\x=1
EndSelect
Else
If joysticks()\Joystick\HIDid=#HIDID_PS4
PS4AxisRemap(ValueCaps(i)\NotRange\Usage)
EndIf
bitmask= (1 << ValueCaps(i)\BitSize)-1
ValueCaps(i)\LogicalMin & bitmask
ValueCaps(i)\LogicalMax & bitmask
value & bitmask
value - ValueCaps(i)\LogicalMin
half = (ValueCaps(i)\LogicalMax- ValueCaps(i)\LogicalMin)/2
joysticks()\Joystick\AxisNb[ ValueCaps(i)\NotRange\Usage-$30 ]\value=(value-half)*100/half
EndIf
EndIf
EndIf
Next
ProcedureReturn #True
EndProcedure
Procedure CheckEvent(WindowEvent)
Protected ret=0
Select WindowEvent
Case #WM_INPUT
If Parse_WM_Input()
ret=joysticks()\Joystick
Else
ret=0
EndIf
Case #WM_INPUT_DEVICE_CHANGE
scan()
ret=0
EndSelect
ProcedureReturn ret
EndProcedure
Procedure LastState(handle)
Protected *ret=#Null
ForEach joysticks()
If joysticks()\Hid\hDevice=handle
*ret=joysticks()\Joystick
Break
EndIf
Next
ProcedureReturn *ret
EndProcedure
EndModule
CompilerSelect 2;- example 1=rawinput, 2=examine
CompilerCase 1
;Rawinput-version
Procedure FillEditor()
Protected ii, *joy.joy::sJoystick
NewList handles()
joy::Enumerate(handles())
a$=""
ForEach handles()
*joy=joy::LastState(handles())
If *joy
a$+"----------------"+ handles() +#CRLF$
a$+"Name: "+ *joy\Name +#CRLF$
a$+"Product: "+Hex( *joy\HIDID) +#CRLF$
a$+"--"+#CRLF$
a$+"Buttons:"+*joy\Button\Number + #CRLF$
a$+"Buttonmap:"+Right("000000000000000000000000000000"+Bin( *joy\Button\Value ),*joy\Button\Number)+" "+*joy\Button\Value+#CRLF$
For ii=0 To *joy\Button\Number-1
If (*joy\Button\Value >> ii) &1
a$+"nr:"+ii+#CRLF$
EndIf
Next
a$+"--"+#CRLF$
If *joy\Axis\x\exist
a$+"X:"+ *joy\axis\x\value+#CRLF$
EndIf
If *joy\Axis\y\exist
a$+"Y:"+ *joy\axis\y\value+#CRLF$
EndIf
If *joy\Axis\z\exist
a$+"Z:"+ *joy\axis\z\value+#CRLF$
EndIf
a$+"--"+#CRLF$
If *joy\Axis\rx\exist
a$+"rx:"+ *joy\axis\rx\value+#CRLF$
EndIf
If *joy\Axis\ry\exist
a$+"ry:"+ *joy\axis\ry\value+#CRLF$
EndIf
If *joy\Axis\rz\exist
a$+"rZ:"+ *joy\axis\rz\value+#CRLF$
EndIf
a$+"--"+#CRLF$
If *joy\Axis\Slider\exist
a$+"Slider:"+ *joy\axis\Slider\value+#CRLF$
EndIf
a$+"--"+#CRLF$
If *joy\DPad\exist
a$+"DigiPad X:"+ *joy\DPad\x +#CRLF$
a$+"DigiPad y:"+ *joy\DPad\y +#CRLF$
EndIf
EndIf
Next
If GetGadgetText(0)<> a$
SetGadgetText(0,a$)
EndIf
EndProcedure
count=joy::init()
Debug count
joy::EnableRemapPS4(#True)
If OpenWindow(0, 100, 200, 800, 600, "PureBasic Window", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
joy::Register(0,#True)
EditorGadget(0,0,0,WindowWidth(0),WindowHeight(0))
FillEditor()
Repeat
Event = WaitWindowEvent()
Select event
Case #PB_Event_CloseWindow ; If the user has pressed on the close button
Quit = 1
Default
If joy::CheckEvent(event)<> -1
FillEditor()
EndIf
EndSelect
Until Quit = 1
EndIf
CompilerCase 2
;examine-version
Procedure FillEditor()
Protected ii, *joy.joy::sJoystick
NewList handles()
joy::Enumerate(handles())
a$="Start"+#CRLF$
ForEach handles()
*joy=joy::Examine(handles())
If *joy
a$+"----------------"+ handles() +#CRLF$
a$+"Name: "+ *joy\Name +#CRLF$
a$+"Product: "+Hex( *joy\HIDID) +#CRLF$
a$+"--"+#CRLF$
a$+"Buttons:"+*joy\Button\Number + #CRLF$
a$+"Buttonmap:"+Right("000000000000000000000000000000"+Bin( *joy\Button\Value ),*joy\Button\Number)+" "+*joy\Button\Value+#CRLF$
For ii=0 To *joy\Button\Number-1
If (*joy\Button\Value >> ii) &1
a$+"nr:"+ii+#CRLF$
EndIf
Next
a$+"--"+#CRLF$
If *joy\Axis\x\exist
a$+"X:"+ *joy\axis\x\value+#CRLF$
EndIf
If *joy\Axis\y\exist
a$+"Y:"+ *joy\axis\y\value+#CRLF$
EndIf
If *joy\Axis\z\exist
a$+"Z:"+ *joy\axis\z\value+#CRLF$
EndIf
a$+"--"+#CRLF$
If *joy\Axis\rx\exist
a$+"rx:"+ *joy\axis\rx\value+#CRLF$
EndIf
If *joy\Axis\ry\exist
a$+"ry:"+ *joy\axis\ry\value+#CRLF$
EndIf
If *joy\Axis\rz\exist
a$+"rZ:"+ *joy\axis\rz\value+#CRLF$
EndIf
a$+"--"+#CRLF$
If *joy\Axis\Slider\exist
a$+"Slider:"+ *joy\axis\Slider\value+#CRLF$
EndIf
a$+"--"+#CRLF$
If *joy\DPad\exist
a$+"DigiPad X:"+ *joy\DPad\x +#CRLF$
a$+"DigiPad y:"+ *joy\DPad\y +#CRLF$
EndIf
EndIf
Next
If GetGadgetText(0)<> a$
SetGadgetText(0,a$)
EndIf
EndProcedure
count=joy::init()
Debug count
joy::EnableRemapPS4(#True)
If OpenWindow(0, 100, 200, 800, 600, "PureBasic Window", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
EditorGadget(0,0,0,WindowWidth(0),WindowHeight(0))
AddWindowTimer(0,1,1000/30);30fps
FillEditor()
Repeat
Event = WaitWindowEvent()
Select event
Case #PB_Event_Timer
FillEditor()
Case #PB_Event_CloseWindow ; If the user has pressed on the close button
Quit = 1
Default
If joy::CheckEvent(event)<> -1
FillEditor()
EndIf
EndSelect
Until Quit = 1
EndIf
CompilerEndSelect