Page 1 of 1

3DConnexion 3D mouse example

Posted: Thu Jun 11, 2009 8:31 am
by Ziltch
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!!

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)

:D :D