3DConnexion 3D mouse example
Posted: Thu Jun 11, 2009 8:31 am
I have recently got a SpaceNavigator 3D mouse.
http://www.3dconnexion.com/3dmouse/spacenavigator.php
Here is some code I have pieced together to show a method of using it in PureBasic.
If any PureBasic users have a 3Dconnexion 3D mouse , it would be great to get feedback!
Have Fun!!

http://www.3dconnexion.com/3dmouse/spacenavigator.php
Here is some code I have pieced together to show a method of using it in PureBasic.
If any PureBasic users have a 3Dconnexion 3D mouse , it would be great to get feedback!
Have Fun!!
Code: Select all
;PureBasic 4.31 3DCONNEXION 3D mouse test (ADAmor Ziltch Jun 2009)
Structure RAWINPUTHEADER
dwType.l
dwSize.l
hDevice.l
wParam.l
EndStructure
Structure USBUTTON
usButtonFlags.w
usButtonData.w
EndStructure
Structure RAWMOUSE
usFlags.w
StructureUnion
ulButtons.l
usButton.USBUTTON
EndStructureUnion
ulRawButtons.l
lLastX.l
lLastY.l
ulExtraInformation.l
EndStructure
Structure RAWKEYBOARD
MakeCode.w
Flags.w
Reserved.w
VKey.w
Message.l
ExtraInformation.l
EndStructure
Structure RAWHID
dwSizeHid.l
dwCount.l
bRawData.b[16]
EndStructure
Structure RAWINPUT
header.RAWINPUTHEADER
StructureUnion
mouse.RAWMOUSE
keyboard.RAWKEYBOARD
hid.RAWHID
EndStructureUnion
EndStructure
Structure RAWINPUTDEVICELIST
hDevice.l
dwType.l
EndStructure
Structure RAWINPUTDEVICE
usUsagePage.w
usUsage.w
dwFlags.l
hwndTarget.l
EndStructure
Structure RID_DEVICE_INFO_MOUSE
dwId.l
dwNumberOfButtons.l
dwSampleRate.l
fHasHorizontalWheel.b
EndStructure
Structure RID_DEVICE_INFO_KEYBOARD
dwType.l
dwSubType.l
dwKeyboardMode.l
dwNumberOfFunctionKeys.l
dwNumberOfIndicators.l
dwNumberOfKeysTotal.l
EndStructure
Structure RID_DEVICE_INFO_HID
dwVendorId.l
dwProductId.l
dwVersionNumber.l
usUsagePage.w
usUsage.w
EndStructure
Structure RID_DEVICE_INFO
cbSize.l
dwType.l
StructureUnion
mouse.RID_DEVICE_INFO_MOUSE
keyboard.RID_DEVICE_INFO_KEYBOARD
hid.RID_DEVICE_INFO_HID
EndStructureUnion
EndStructure
#RIM_TYPEHID = 2
#RID_INPUT = $10000003
#RIDEV_NOLEGACY = $00000030
#RIM_TYPEMOUSE = 0
#RIM_TYPEKEYBOARD = 1
#RIM_TYPEHID = 2
#RID_HEADER = $10000005
#RIDEV_INPUTSINK = $00000100
#HID_USAGE_PAGE_GENERIC = $00000001
#RIDEV_REMOVE = $00000001
#WM_INPUT = $000000FF
#RIDI_DEVICENAME = $20000007
#RIDI_DEVICEINFO = $2000000b
#MOUSE_VIRTUAL_DESKTOP = $02
#MOUSE_ATTRIBUTES_CHANGED = $04
Global hWnd.l
Global Sprit.l
Global x.d,y.d,z.d
Global yaw.d,pitch.d,rot.d,zoom.d
Global Dim all6DOFs(7)
; bGotTranslation=#False
; bGotRotation=#False
zoom.d=36
Global ScreenWidth,ScreenHeight
ScreenWidth = 720
ScreenHeight = 720
Procedure DrawScreen()
ClearScreen(RGB(Abs(rot)/1.4, pitch ,yaw))
If StartDrawing(ScreenOutput())
DrawText(10,10,"x,y,z "+Str(x)+","+Str(y)+","+Str(zoom),RGB(255-Abs(rot)/1.4, 255-pitch ,255-yaw),RGB(Abs(rot)/1.4, pitch ,yaw))
DrawText(10,30,"yaw,pitch,rot "+Str(yaw)+","+Str(pitch)+","+Str(rot),RGB(255-Abs(rot)/1.4, 255-pitch ,255-yaw),RGB(Abs(rot)/1.4, pitch ,yaw))
StopDrawing()
EndIf
If Start3D()
ZoomSprite3D(Sprit, zoom, zoom)
RotateSprite3D(Sprit, rot, 0)
DisplaySprite3D(Sprit, x,y, 255)
; ...
Stop3D()
EndIf
FlipBuffers(#PB_Screen_SmartSynchronization) ;#PB_Screen_NoSynchronization
EndProcedure
Procedure.l WindowProc(hWnd.l, Msg.l, wParam.l, lParam.l)
Shared *GetRawInputData
Shared bGotTranslation.b,bGotRotation.b,lasttime.l,LastVecType
Protected result.l = #PB_ProcessPureBasicEvents
Protected VecType.b
If (Msg = #WM_INPUT)
If CallFunctionFast(*GetRawInputData, lParam, #RID_INPUT, #Null, @pcbSize.l, SizeOf(RAWINPUTHEADER)) = 0
*pRawData.RAWINPUT = AllocateMemory(pcbSize)
If CallFunctionFast(*GetRawInputData, lParam, #RID_INPUT, *pRawData, @pcbSize, SizeOf(RAWINPUTHEADER))<>-1
VecType.b=*pRawData\hid\bRawData[0]
;LastVecType=VecType
;Translation Or Rotation packet? They come in two different packets.
If VecType= 1 ; Translation vector
all6DOFs(0) = (*pRawData\hid\bRawData[1] & $000000ff) | ((*pRawData\hid\bRawData[2]<<8) & $ffffff00);
all6DOFs(1) = (*pRawData\hid\bRawData[3] & $000000ff) | ((*pRawData\hid\bRawData[4]<<8) & $ffffff00);
all6DOFs(2) = (*pRawData\hid\bRawData[5] & $000000ff) | ((*pRawData\hid\bRawData[6]<<8) & $ffffff00);
bGotTranslation = #True;
ElseIf VecType = 2 ; Rotation vector
all6DOFs(3) = (*pRawData\hid\bRawData[1] & $000000ff) | ((*pRawData\hid\bRawData[2]<<8) & $ffffff00);
all6DOFs(4) = (*pRawData\hid\bRawData[3] & $000000ff) | ((*pRawData\hid\bRawData[4]<<8) & $ffffff00);
all6DOFs(5) = (*pRawData\hid\bRawData[5] & $000000ff) | ((*pRawData\hid\bRawData[6]<<8) & $ffffff00);
bGotRotation = #True;
ElseIf VecType = 3 ; Buttons (display most significant byte To least)
Debug "Button mask:"+Str(*pRawData\hid\bRawData[3])+","+Str(*pRawData\hid\bRawData[2])+","+Str(*pRawData\hid\bRawData[1])
EndIf
If (bGotTranslation And bGotRotation)
bGotTranslation =#False
bGotRotation = #False
;Debug "all6DOFs: "+Str( all6DOFs(0))+","+Str(all6DOFs(1))+","+Str(all6DOFs(2))+","+Str( all6DOFs(3))+","+Str( all6DOFs(4))+","+Str(all6DOFs(5))
dx.d=all6DOFs(0)/10.0
dy.d=all6DOFs(1)/10.0
dz.d=all6DOFs(2)/20.0
dyaw.d=all6DOFs(3)/20.0
dpitch.d=all6DOFs(4)/20.0
drot.d=all6DOFs(5)/80.0
If Abs(dz)>5
zoom.d=zoom-dz
If zoom<2
zoom=2
EndIf
If zoom>128
zoom=128
EndIf
EndIf
If Abs(dx)>5
x=x+dx
If x<5
x=5
EndIf
If x>ScreenWidth-zoom
x=ScreenWidth-zoom
EndIf
EndIf
If Abs(dy)>5
y=y+dy
If y<5
y=5
EndIf
If y>ScreenHeight-zoom
y=ScreenHeight-zoom
EndIf
EndIf
If Abs(dyaw)>5
yaw=yaw+dyaw
If yaw<0
yaw=0
EndIf
If yaw>255 ;using this for color , so limit to 255
yaw=255
EndIf
EndIf
If Abs(dpitch)>5
pitch=pitch+dpitch
If pitch<0
pitch=0
EndIf
If pitch>255 ;using this for color , so limit to 255
pitch=255
EndIf
EndIf
If Abs(drot)>1
rot=rot+drot
If rot< -360
rot=0
EndIf
If rot>360
rot=0
EndIf
EndIf
;Debug "all6DOFs: "+Str( x)+","+Str(y)+","+Str(z)+" , "+Str(yaw)+","+Str(pitch)+","+Str(rot)
EndIf
FreeMemory(*pRawData)
EndIf
EndIf
result = DefWindowProc_(hWnd, Msg, wParam, lParam)
EndIf
ProcedureReturn result
EndProcedure
Procedure Init3Dmouse()
nDevices.l
OpenLibrary(0, "user32.dll")
Shared *GetRawInputDeviceList
Shared *GetRawInputDeviceInfo
Shared *RegisterRawInputDevices
Shared *GetRawInputData
*GetRawInputDeviceList = GetFunction(0, "GetRawInputDeviceList")
*GetRawInputDeviceInfo = GetFunction(0, "GetRawInputDeviceInfoA")
*RegisterRawInputDevices = GetFunction(0,"RegisterRawInputDevices")
*GetRawInputData = GetFunction(0,"GetRawInputData")
If *GetRawInputDeviceList
If CallFunctionFast(*GetRawInputDeviceList,0, @nDevices, SizeOf(RAWINPUTDEVICELIST)) = -1
; MessageRequester( "OK","Devices ="+Str(nDevices),#PB_MessageRequester_Ok)
; Else
MessageRequester( "Error","No RawInput devices attached" ,#PB_MessageRequester_Ok )
End
EndIf
EndIf
RAWINPUTDEVICELISTsize=SizeOf(RAWINPUTDEVICELIST)
;*g_pRawInputDeviceList = AllocateMemory(RAWINPUTDEVICELISTsize * nDevices)
Dim g_pRawInputDeviceList.RAWINPUTDEVICELIST(nDevices)
;Now get the Data on the attached devices
If (CallFunctionFast(*GetRawInputDeviceList, @g_pRawInputDeviceList(), @nDevices, SizeOf(RAWINPUTDEVICELIST)) = -1)
MessageRequester( "Error","Error from GetRawInputDeviceList", #PB_MessageRequester_Ok )
ProcedureReturn
EndIf
;*g_pRawInputDevices = AllocateMemory( nDevices * SizeOf(RAWINPUTDEVICE) )
Dim g_pRawInputDevices.RAWINPUTDEVICE(nDevices)
g_nUsagePage1Usage8Devices = 0
; Look through device List For RIM_TYPEHID devices With UsagePage == 1, Usage == 8
For i=0 To nDevices-1
;*g_pRawInputDeviceList2.RAWINPUTDEVICELIST = *g_pRawInputDeviceList +i*RAWINPUTDEVICELISTsize
If g_pRawInputDeviceList(i)\dwType = #RIM_TYPEHID
nchars = 300;
deviceName.s=Space(nchars)
If CallFunctionFast(*GetRawInputDeviceInfo, g_pRawInputDeviceList(i)\hDevice,#RIDI_DEVICENAME, @deviceName, @nchars) = 0
deviceName=""
; Debug "dev "+Str(i)+" GetRawInputDevice name failed"
EndIf
;Debug "Device["+Str(i)+"]: name = " + deviceName ;handle="=Str(g_pRawInputDeviceList(i).hDevice)+"
dinfo.RID_DEVICE_INFO
sizeofdinfo = SizeOf(dinfo)
dinfo\cbSize = sizeofdinfo
If (CallFunctionFast(*GetRawInputDeviceInfo, g_pRawInputDeviceList(i)\hDevice, #RIDI_DEVICEINFO, @dinfo, @sizeofdinfo ) >= 0)
If dinfo\dwType = #RIM_TYPEHID
;RID_DEVICE_INFO_HID *phidInfo = dinfo.hid;
;Debug "VID = " + Str(dInfo\hid\dwVendorId)+ " PID = " + Str(dInfo\hid\dwProductId)+" Version = " + Str(dInfo\hid\dwVersionNumber)
;Debug "UsagePage = "+ Str(dInfo\hid\usUsagePage)+ " Usage = " + Str(dInfo\hid\usUsage)
; Add this one To the List of interesting devices?
; Actually only have To do this once To get input from all usage 1, usagePage 8 devices
; This just keeps out the other usages of non 3dconnexion devices.
; You might want To put up a List For users To Select amongst the different devices.
; In particular, To assign separate functionality To the different devices.
If (dInfo\hid\usUsagePage = 1 And dInfo\hid\usUsage = 8)
g_pRawInputDevices(g_nUsagePage1Usage8Devices)\usUsagePage = dInfo\hid\usUsagePage
g_pRawInputDevices(g_nUsagePage1Usage8Devices)\usUsage = dInfo\hid\usUsage
g_pRawInputDevices(g_nUsagePage1Usage8Devices)\dwFlags = 0
g_pRawInputDevices(g_nUsagePage1Usage8Devices)\hwndTarget = NULL
g_nUsagePage1Usage8Devices=g_nUsagePage1Usage8Devices+1
EndIf
EndIf
Else
Debug "dev "+Str(i)+" GetRawInputDeviceInfo failed"
EndIf
;Else
; Debug Str(g_pRawInputDeviceList(i)\hDevice)+" dev "+Str(i)+" Not RIM_TYPEHID it is = "+Hex(g_pRawInputDeviceList(i)\dwType)
EndIf
Next
;Debug " *** g_nUsagePage1Usage8Devices="+Str(g_nUsagePage1Usage8Devices)
If (CallFunctionFast(*RegisterRawInputDevices, @g_pRawInputDevices(), g_nUsagePage1Usage8Devices, SizeOf(RAWINPUTDEVICE) ) = 0 )
MessageRequester( "Error","Error calling RegisterRawInputDevices. No 3D mouse found.", #PB_MessageRequester_Ok )
ProcedureReturn
EndIf
EndProcedure
Init3Dmouse()
SetWindowCallback(@WindowProc())
hWnd.l = OpenWindow(0, #PB_Ignore, #PB_Ignore, ScreenWidth, ScreenHeight, "PureBasic 4.31 3DCONNEXION 3D mouse test (ADAmor Ziltch Jun 2009)",#PB_Window_MaximizeGadget|#PB_Window_SizeGadget)
If InitSprite() = 0 Or InitSprite3D() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0
MessageRequester("Error", "Can't open the sprite system", 0)
End
EndIf
OpenWindowedScreen(WindowID(0), 0,0, ScreenWidth, ScreenHeight, 1,0,0)
CreateSprite(0, 40, 40,#PB_Sprite_Texture)
If StartDrawing(SpriteOutput(0))
Box(0, 0, 40, 40, RGB(255, 50, 105))
Circle(10,14, 6, RGB(155, 0, 55))
Circle(28,14, 6, RGB(155, 0, 55))
StopDrawing()
EndIf
Sprit=CreateSprite3D(#PB_Any, 0)
SetTimer_(WindowID(0), 1, 30, @DrawScreen())
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
CloseLibrary(0)

