Xbox 360 controller (VERY basic access!)

Share your advanced PureBasic knowledge/code with the community.
Hi-Toro
Enthusiast
Enthusiast
Posts: 270
Joined: Sat Apr 26, 2003 3:23 pm

Xbox 360 controller (VERY basic access!)

Post by Hi-Toro »

Hi all,

Just had a quick go at accessing the Xbox 360 (wired) controller from PB. This raw, user-unfriendly code just lists any plugged-in controllers, but it's a start, and it seemed a waste not to post it since I can't find any other related code using the forum search. I haven't tried anything more yet, but there's no reason the rest of the functions shouldn't work... this might encourage someone else to take it further anyway!

NB. Please note that a couple of the structure fields could possibly be wrong, eg. WCHAR, WORD vs SHORT, etc. This stuff always baffles me when converting from C/C++/C#, etc!

Code: Select all

; -----------------------------------------------------------------------------
; Quick Xbox 360 pad test...
; -----------------------------------------------------------------------------

; See function/structure reference on how to use this stuff...

; http://msdn.microsoft.com/library/Default.asp?url=/library/en-us/directx9_c/dx9_xinput_reference.asp

; IMPORTANT: Make sure standard M$ drivers are installed! Get them here...
; http://www.microsoft.com/hardware/gaming/Productlist.aspx?pid=all

; Some relevant constants found here:
; http://forum.thegamecreators.com/?m=forum_view&t=78938&b=6

; -----------------------------------------------------------------------------
; XInput constants...
; -----------------------------------------------------------------------------

; Versions...

#XINPUT_1_0						= "xinput9_1_0.dll" ; Old DLL!
#XINPUT_1_1						= "xinput1_1.dll"

; XINPUT_GAMEPAD .wButtons bits:

#XINPUT_GAMEPAD_DPAD_UP			= $00000001
#XINPUT_GAMEPAD_DPAD_DOWN		= $00000002
#XINPUT_GAMEPAD_DPAD_LEFT		= $00000004
#XINPUT_GAMEPAD_DPAD_RIGHT		= $00000008
#XINPUT_GAMEPAD_START			= $00000010
#XINPUT_GAMEPAD_BACK			= $00000020
#XINPUT_GAMEPAD_LEFT_THUMB		= $00000040
#XINPUT_GAMEPAD_RIGHT_THUMB		= $00000080
#XINPUT_GAMEPAD_LEFT_SHOULDER	= $0100
#XINPUT_GAMEPAD_RIGHT_SHOULDER	= $0200
#XINPUT_GAMEPAD_A				= $1000
#XINPUT_GAMEPAD_B				= $2000
#XINPUT_GAMEPAD_X				= $4000
#XINPUT_GAMEPAD_Y				= $8000

; Thumbstick values, from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/dx9_xinput_getting_started.asp

#XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE		= 7849
#XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE	= 8689
#XINPUT_GAMEPAD_TRIGGER_THRESHOLD		= 30

; Pass to XInputGetCapabilities as flag...

#XINPUT_FLAG_GAMEPAD			= $00000001

; Bit flags for XInputGetCapabilities...

#XINPUT_DEVTYPE_GAMEPAD			= $01

#XINPUT_DEVSUBTYPE_GAMEPAD		= $01
#XINPUT_DEVSUBTYPE_WHEEL		= $02
#XINPUT_DEVSUBTYPE_ARCADE_STICK	= $03
#XINPUT_DEVSUBTYPE_FLIGHT_SICK	= $04
#XINPUT_DEVSUBTYPE_DANCE_PAD	= $05

; Voice support...

#XINPUT_CAPS_VOICE_SUPPORTED	= $0004

; Misc...

#XINPUT_MAX_USERS			= 4
#XINPUT_ERROR_SUCCESS		= 0
#XINPUT_ERROR_UNSUPPORTED	= 404
#XINPUT_ERROR_DLLEXIST		= 405
#XINPUT_ERROR_DLLNOTEXIST	= 406

; -----------------------------------------------------------------------------
; Structures...
; -----------------------------------------------------------------------------

Structure XINPUT_GAMEPAD
    wButtons.w
    bLeftTrigger.b
    bRightTrigger.b
    sThumbLX.w
    sThumbLY.w
    sThumbRX.w
    sThumbRY.w
EndStructure

Structure XINPUT_VIBRATION
    wLeftMotorSpeed.w
    wRightMotorSpeed.w
EndStructure

Structure XINPUT_STATE
    dwPacketNumber.l
    Gamepad.XINPUT_GAMEPAD
EndStructure

Structure XINPUT_KEYSTROKE
    VirtualKey.w
    Unicode.w ; WCHAR - "unsigned short is the WCHAR Windows UNICODE type" - http://blog.kowalczyk.info/archives/2006/01/
    Flags.w
    UserIndex.b
    HidCode.b
EndStructure

Structure XINPUT_CAPABILITIES
    Type.b
    SubType.b
    Flags.w
    Gamepad.XINPUT_GAMEPAD
    Vibration.XINPUT_VIBRATION
EndStructure

; -----------------------------------------------------------------------------
; D E M O . . .
; -----------------------------------------------------------------------------

Global XINPUT_VERSION.s ; Store version for later use...

xinput = OpenLibrary (#PB_Any, #XINPUT_1_1)

; Check for older version if unable to open version 1.1...

If xinput = 0

	; Try version 1.0...
	
	xinput = OpenLibrary (#PB_Any, #XINPUT_1_0)
	
	If xinput
		XINPUT_VERSION = "1.0"
	EndIf

Else
	XINPUT_VERSION = "1.1"
EndIf

If xinput

	; Just testing -- function addresses/availability...
	
	; Debug GetFunction (xinput, "XInputGetDSoundAudioDeviceGuids")
	; Debug GetFunction (xinput, "XInputGetCapabilities")
	; Debug GetFunction (xinput, "XInputGetKeystroke") ; For Xbox360 wireless controller only!
	; Debug GetFunction (xinput, "XInputGetState")
	; Debug GetFunction (xinput, "XInputSetState")

	; If XINPUT_VERSION = "1.1"
	; 	Debug GetFunction (xinput, "XInputEnable")
	; Else
	; 	Debug "XInputEnable () not available in version 1.0!"
	; EndIf

	xin_GetSoundIDs	= GetFunction (xinput, "XInputGetDSoundAudioDeviceGuids")
	xin_GetCaps		= GetFunction (xinput, "XInputGetCapabilities")
	xin_GetState	= GetFunction (xinput, "XInputGetState")
	xin_SetState	= GetFunction (xinput, "XInputSetState")
	
	If XINPUT_VERSION = "1.1"
		xin_Enable = GetFunction (xinput, "XInputEnable") ; Not in version 1.0!
	EndIf

;	CallFunctionFast (xin_GetState, 0, @xin_state.XINPUT_STATE)
;	Debug xin_state\dwPacketNumber

	; NOTE: "port" numbers are apparently assigned on the fly as
	; controllers are connected and disconnected... I think!
	
	; List plugged in controllers...
	
	For port = 0 To #XINPUT_MAX_USERS - 1

		; Note successful return value is actually 0 for XInputGetCapabilities... good old M$!
		
		If CallFunctionFast (xin_GetCaps, port, #XINPUT_FLAG_GAMEPAD, @caps.XINPUT_CAPABILITIES) = #XINPUT_ERROR_SUCCESS
		
			Debug "Xbox 360 controller plugged into port " + Str (port)

;			Debug caps\Type
;			Debug caps\SubType
		
			; This returns 0 for some reason. Should be $01! Don't know what's up. Probably
			; best to ignore and just check sub-type.
			
			If caps\Type = #XINPUT_DEVTYPE_GAMEPAD
				Debug "Controller type: game pad"
			EndIf

			If caps\SubType = #XINPUT_DEVSUBTYPE_GAMEPAD
				Debug "(Standard Xbox 360 game pad)"
			EndIf
		
		Else
			Debug "[No Xbox 360 controller plugged into port " + Str (port) + "]"
		EndIf

		Debug "--"
		
	Next
	
	CloseLibrary (xinput)

Else
	Debug "Can't open XInput DLL! Install latest DirectX 9 and Xbox 360 controller drivers!"
EndIf
James Boyd
http://www.hi-toro.com/
Death to the Pixies!
Hi-Toro
Enthusiast
Enthusiast
Posts: 270
Joined: Sat Apr 26, 2003 3:23 pm

Post by Hi-Toro »

Just a small update in case anyone searches for this stuff. I added a vibration test ages ago but I notice it's not in the previous post.

The real reason I'm updating now is because I just found I only had version 1.3 of the DLL installed, so this code didn't work. (It was pretty stupid before.) I've made it search for the most recent DLL now...

Code: Select all

; -----------------------------------------------------------------------------
; Quick Xbox 360 pad test... Hi-Toro / Public Domain
; -----------------------------------------------------------------------------

; See function/structure reference on how to use this stuff...

; http://msdn.microsoft.com/library/Default.asp?url=/library/en-us/directx9_c/dx9_xinput_reference.asp

; Make sure standard M$ drivers are installed! Get them here...
; http://www.microsoft.com/hardware/gaming/Productlist.aspx?pid=all

; -----------------------------------------------------------------------------
; System functions...
; -----------------------------------------------------------------------------

Procedure.s GetSystemFolder ()
    location$ = Space (#MAX_PATH)
    GetSystemDirectory_ (@location$, #MAX_PATH)
    ProcedureReturn location$
EndProcedure

; Find most recent version of XInput DLL...

Procedure.s FindXInput ()

	x$ = "xinput*_*.dll"

	dir = ExamineDirectory (#PB_Any, GetSystemFolder (), x$)

	; Early version of XInput DLL! Grrr...
	
	x$ = "xinput9_1_0.dll"

	If FileSize (GetSystemFolder () + "\" + x$) = -1
		x$ = "" ; Old DLL not found...
	EndIf

	If dir

		While NextDirectoryEntry (dir)

			x$ = DirectoryEntryName (dir)

			version = Val (Mid (x$, 7, 1) + Mid (x$, 9, 1))
		
			If version = 91
				If Mid (x$, 11, 1) = "0"
					version = 10 ; Ha! Stupid old "xinput9_1_0.dll" found -- really version 1.0!
				EndIf
			EndIf

			If version > hiversion
				hiversion = version
				xinput$ = x$
			EndIf

		Wend

	EndIf
	
	ProcedureReturn xinput$		
	
EndProcedure

; -----------------------------------------------------------------------------
; XInput constants...
; -----------------------------------------------------------------------------

; Versions...

#XINPUT_1_0						= "xinput9_1_0.dll" ; Old DLL!
#XINPUT_1_1						= "xinput1_1.dll"

; XINPUT_GAMEPAD .wButtons bits:

#XINPUT_GAMEPAD_DPAD_UP			= $00000001
#XINPUT_GAMEPAD_DPAD_DOWN		= $00000002
#XINPUT_GAMEPAD_DPAD_LEFT		= $00000004
#XINPUT_GAMEPAD_DPAD_RIGHT		= $00000008
#XINPUT_GAMEPAD_START			= $00000010
#XINPUT_GAMEPAD_BACK			= $00000020
#XINPUT_GAMEPAD_LEFT_THUMB		= $00000040
#XINPUT_GAMEPAD_RIGHT_THUMB		= $00000080
#XINPUT_GAMEPAD_LEFT_SHOULDER	= $0100
#XINPUT_GAMEPAD_RIGHT_SHOULDER	= $0200
#XINPUT_GAMEPAD_A				= $1000
#XINPUT_GAMEPAD_B				= $2000
#XINPUT_GAMEPAD_X				= $4000
#XINPUT_GAMEPAD_Y				= $8000

; Thumbstick values, from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/dx9_xinput_getting_started.asp

#XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE		= 7849
#XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE	= 8689
#XINPUT_GAMEPAD_TRIGGER_THRESHOLD		= 30

; Pass to XInputGetCapabilities as flag...

#XINPUT_FLAG_GAMEPAD			= $00000001

; Bit flags for XInputGetCapabilities...

#XINPUT_DEVTYPE_GAMEPAD			= $01

#XINPUT_DEVSUBTYPE_GAMEPAD		= $01
#XINPUT_DEVSUBTYPE_WHEEL		= $02
#XINPUT_DEVSUBTYPE_ARCADE_STICK	= $03
#XINPUT_DEVSUBTYPE_FLIGHT_SICK	= $04
#XINPUT_DEVSUBTYPE_DANCE_PAD	= $05

; Voice support...

#XINPUT_CAPS_VOICE_SUPPORTED	= $0004

; Misc...

#XINPUT_MAX_USERS			= 4
#XINPUT_ERROR_SUCCESS		= 0
#XINPUT_ERROR_UNSUPPORTED	= 404
#XINPUT_ERROR_DLLEXIST		= 405
#XINPUT_ERROR_DLLNOTEXIST	= 406

; -----------------------------------------------------------------------------
; Structures...
; -----------------------------------------------------------------------------

Structure XINPUT_GAMEPAD
    wButtons.w
    bLeftTrigger.b
    bRightTrigger.b
    sThumbLX.w
    sThumbLY.w
    sThumbRX.w
    sThumbRY.w
EndStructure

Structure XINPUT_VIBRATION
    wLeftMotorSpeed.w
    wRightMotorSpeed.w
EndStructure

Structure XINPUT_STATE
    dwPacketNumber.l
    Gamepad.XINPUT_GAMEPAD
EndStructure

Structure XINPUT_KEYSTROKE
    VirtualKey.w
    Unicode.w ; WCHAR - "unsigned short is the WCHAR Windows UNICODE type" - http://blog.kowalczyk.info/archives/2006/01/
    Flags.w
    UserIndex.b
    HidCode.b
EndStructure

Structure XINPUT_CAPABILITIES
    Type.b
    SubType.b
    Flags.w
    Gamepad.XINPUT_GAMEPAD
    Vibration.XINPUT_VIBRATION
EndStructure

; -----------------------------------------------------------------------------
; D E M O . . .
; -----------------------------------------------------------------------------

x$ = FindXInput ()

If x$ = ""
	Debug "XInput DLL not installed!"
	End
EndIf

xinput = OpenLibrary (#PB_Any, x$)

If xinput

	; Just testing -- function addresses/availability...
	
	; Debug GetFunction (xinput, "XInputGetDSoundAudioDeviceGuids")
	; Debug GetFunction (xinput, "XInputGetCapabilities")
	; Debug GetFunction (xinput, "XInputGetKeystroke") ; For Xbox360 wireless controller only!
	; Debug GetFunction (xinput, "XInputGetState")
	; Debug GetFunction (xinput, "XInputSetState")
	
	xin_GetSoundIDs	= GetFunction (xinput, "XInputGetDSoundAudioDeviceGuids")
	xin_GetCaps		= GetFunction (xinput, "XInputGetCapabilities")
	xin_GetState	= GetFunction (xinput, "XInputGetState")
	xin_SetState	= GetFunction (xinput, "XInputSetState")
	
	If x$ <> "xinput9_1_0.dll"
		xin_Enable = GetFunction (xinput, "XInputEnable") ; Not in version 1.0!
	EndIf

;	CallFunctionFast (xin_GetState, 0, @xin_state.XINPUT_STATE)
;	Debug xin_state\dwPacketNumber

	; NOTE: "port" numbers are apparently assigned on the fly as
	; controllers are connected and disconnected... I think!
	
	; List plugged in controllers...
	
	For port = 0 To #XINPUT_MAX_USERS - 1

		; Note successful return value is actually 0 for XInputGetCapabilities... good old M$!
		
		If CallFunctionFast (xin_GetCaps, port, #XINPUT_FLAG_GAMEPAD, @caps.XINPUT_CAPABILITIES) = #XINPUT_ERROR_SUCCESS
		
			Debug "Xbox 360 controller plugged into port " + Str (port)

;			Debug caps\Type
;			Debug caps\SubType
		
			; This returns 0 for some reason. Should be $01! Don't know what's up. Probably
			; best to ignore and just check sub-type.
			
			If caps\Type = #XINPUT_DEVTYPE_GAMEPAD
				Debug "Controller type: game pad"
			EndIf

			If caps\SubType = #XINPUT_DEVSUBTYPE_GAMEPAD
				
				Debug "(Standard Xbox 360 game pad)"
				
				Debug ""
				Debug "4 vibration tests..."
				Debug ""
				
				xv.XINPUT_VIBRATION
				
				; Motor values: 0-65535
				
    			xv\wLeftMotorSpeed = 15000
    			xv\wRightMotorSpeed = 0
				
				CallFunctionFast (xin_SetState, port, xv)
				
				Delay (2000)

    			xv\wLeftMotorSpeed = 5000
    			xv\wRightMotorSpeed = 40000
				
				CallFunctionFast (xin_SetState, port, xv)

				Delay (2000)
				
    			xv\wLeftMotorSpeed = 65535
    			xv\wRightMotorSpeed = 65535
				
				CallFunctionFast (xin_SetState, port, xv)
				
				Delay (2000)

    			xv\wLeftMotorSpeed = 10000
    			xv\wRightMotorSpeed = 10000
				
				CallFunctionFast (xin_SetState, port, xv)
				
				Delay (2000)

			EndIf
		
		Else
			Debug "[No Xbox 360 controller plugged into port " + Str (port) + "]"
		EndIf

		Debug "--"
		
	Next
	
	CloseLibrary (xinput)

Else
	Debug "Can't open XInput DLL! Install latest DirectX 9 and Xbox 360 controller drivers!"
EndIf
James Boyd
http://www.hi-toro.com/
Death to the Pixies!
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Post by PB »

I'll have a play soon; don't have time today. I have a Logitech Xbox 360
DriveFX steering wheel with a hacked Windows XP driver, so your code
might work with it. Give me a couple of days to see.
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
Post Reply