Google Answers Logo
View Question
 
Q: Trackball DPI ( Answered,   0 Comments )
Question  
Subject: Trackball DPI
Category: Computers > Hardware
Asked by: pdqjohnny-ga
List Price: $50.00
Posted: 05 Dec 2002 17:04 PST
Expires: 04 Jan 2003 17:04 PST
Question ID: 120050
How can I get the x,y coordinate output from a 6400 DPI optical
trackball into a VB program. I know how to get the mouse xy
coordinates but I want to get the higher resolution values the
trackball is sending to the computer.
Answer  
Subject: Re: Trackball DPI
Answered By: verteiron-ga on 05 Dec 2002 19:06 PST
 
The Window API, as you have no doubt discovered, only allows you to
retrieve screen coordinates of the mouse cursor. Getting the actual
coordinate data from the input device itself is quite a bit more
complex. In order to do this, you'll need to use DirectX. If you're
not familiar with using DirectX then this may be a bit tricky for you.
Don't panic! It requires a little adjustment of your usual programming
style, but it's not difficult (assuming you have a firm grasp of
Visual Basic itself).

You'll need to download the DirectX8 Visual Basic SDK if you don't
have it already. Once you've installed this, you'll need to add
"DirectX 8 for Visual Basic Type Library" to your list of References.

All set? Ok, here we go...

There are two main ways to allow your program to react to the input
data: polling the input device from a loop, or using events. Since
most VB programmers are more familiar with events, I'll be explaining
that method.

A good deal of the following code was taken from DirectX4VB's very
helpful DirectInput tutorial (see link at the bottom of this answer).

First, you'll need to create a DirectX8 object to represent the device
(in this case, the trackball) that you'll be receiving input from.
This is done by simply declaring the objects; first the DirectX
object, then the DirectInput object, and finally the DirectInputDevice
object:

Dim dxObject as DirectX8
Dim dxInputObject as DirectInput8
Dim dxiDevice as DirectInputDevice8

We also need to declare a constant for use later on:

Const BufferSize As Long = 10

And we need to create the Event handle for DirectX to trigger when it
receives input:

Dim hEvent as Long
Implements DirectXEvent8

All of the above statements will need to go into your General
Declarations. In addition, when working with DirectX it is HIGHLY
recommended that you use "Option Explicit". DirectX does not take
kindly to variables created on-the-fly.

Now that we've got the variables laid out, we need to actually
initialize DirectX and get control of our device. The following can go
in Form_Main, or a new Sub that will be called when you want to start
reading the mouse input. This code assumes your form is called
frmMain.

Me.Show 'Display the form if it isn't already

Set dxObject = New DirectX8 'must create the object.
Set dxInputObject = dxObject.DirectInputCreate
Set dxiDevice = dxInputObject.CreateDevice("guid_SysMouse")

Next, we need to tell DirectInput what type of device we want to get
data from, and what type of control we want to have over it.

Call dxiDevice.SetCommonDataFormat(DIFORMAT_MOUSE)
Call dxiDevice.SetCooperativeLevel(frmMain.hWnd, DISCL_FOREGROUND Or
DISCL_EXCLUSIVE)

DIFORMAT_MOUSE is a constant defined in DirectInput. It specifies that
we'll be receiving mouse-specific data. DISCL_FOREGROUND and
DISCL_EXCLUSIVE specify that no other applications will have access to
the input device while we're using it. Next, we'll need to set the
buffer size (or how many input events we can store at one time). To do
this, we need to create a variable to represent a DirectInput
property, set it, and call SetProperty to let DirectInput know what we
want:

Dim dxiProp As DIPROPLONG
dxiProp.lHow = DIPH_DEVICE
dxiProp.lObj = 0
dxiProp.lData = BufferSize 'The constant we declared up above
    
Call dxiDevice.SetProperty("DIPROP_BUFFERSIZE", dxiProp)

Finally, we need to set up the Event that we're going to use to read
the mouse input:

hEvent = DX.CreateEvent(frmMain)
dxiDevice.SetEventNotification hEvent

Now we're ready to start reading the device!

dxiDevice.Aquire

At this point, Windows loses control of the input device and your
application gains complete control of it. This means that you will
need to write code to check for such things as double-clicks, drags,
hovers, and other common tasks. Whenever DirectInput receives
information from the input device, it will fire the
DirectXEvent8_DXCallback event in frmMain. This event returns a single
parameter, eventid, which contains the handle for the DirectInput
event. Remember that this event may well be called hundreds of timse
per second or more, so it's vital that the code here be as simple and
efficient as possible. Here is some sample code for this event that
demonstrates how to retrieve coordinate data from the input device
(note that your code will probably need to be a lot more complicated
than this):

If Not (eventid = hEvent) Then Exit Sub 'event was not for us

  Dim dxiDeviceData(1 To BufferSize) As DIDEVICEOBJECTDATA 
  Dim numEvents As Long 'When using events, this should be just 1
  Dim i As Long 'looping variables
        

  numEvents = dxiDevice.GetDeviceData(dxiDeviceData, DIGDD_DEFAULT)
        
Now we need to loop through all the events, just in case there is more
than one in the buffer. lOfs is a structure that contains all the
information about the input device's report:

For i = 1 To numEvents
  Select Case dxiDeviceData(i).lOfs
    Case DIMOFS_X
      'the mouse has moved along the X Axis
       'dxiDeviceDate(i).lData contains 1, 0 or -1
    Case DIMOFS_Y
      'the mouse has moved along the Y axis
      'dxiDeviceDate(i).lData contains 1, 0 or -1
    Case DIMOFS_BUTTON0
      'the first (left) button has been pressed/released
      'dxiDeviceDate(i).lData contains 0 or 1
    Case DIMOFS_BUTTON1
      'the second (right) button has been pressed/released
      'dxiDeviceDate(i).lData contains 0 or 1
    'These constants go all the way up to BUTTON7

   End Select
Next I
    
DoEvents 'otherwise you may lock your system

You can keep track of the current position of the cursor by adding the
value in dxiDeviceDate(i).lData to the last known position of the
mouse or trackball. In this manner you may take full advantage of your
trackball's native resolution. Be sure you release control of the
input device back to Windows when you're done with it! This can be
done by using

dxiDevice.UnAquire

on the form's termination event. Be SURE to call this before your
program quits; otherwise you may be stuck without a mouse cursor!

The code I have listed here is for the purpose of demonstration only.
It contains no error handling, and it doesn't actually do anything
with the data it retrieves. You will need to use what I have listed
here and in the links below to integrate this functionality into your
program.

The following links proved extremely useful while researching this
question. DirectX4VB in particular provides detailed instructions,
along with downloadable sample applications demonstrating the usage of
all aspects of DirectX (including DirectInput).

DirectX4VB DirectInput8 tutorials:
http://www.exhedra.com/DirectX4VB/TUT_DX8_DI.asp

MSDN, Using DirectInput (Visual Basic):
http://msdn.microsoft.com/library/en-us/dx8_vb/directx_vb/Input/Using/UsingDirectinput.asp

Download DirectX SDK download:
http://msdn.microsoft.com/downloads/sample.asp?url=/MSDN-FILES/027/001/771/msdncompositedoc.xml

I hope you find this information helpful!

Clarification of Answer by verteiron-ga on 05 Dec 2002 19:09 PST
The line

hEvent = DX.CreateEvent(frmMain)

SHOULD read

hEvent = dxObject.CreateEvent(frmMain)

Request for Answer Clarification by pdqjohnny-ga on 08 Dec 2002 18:02 PST
Hi;
I put the code into VB6 in the general section on frm.Main and it runs
down till it gets to Implements DirectXEvents8 and errors message is
Object module needs to implement 'DXCallback' for interface
'DirectXEvent8'

Did I miss something here?

 
Dim dxObject As DirectX8
Dim dxInputObject As DirectInput8
Dim dxiDevice As DirectInputDevice8
 
'We also need to declare a constant for use later on:
 
Const BufferSize As Long = 10
Dim xposition As Long
Dim yposition As Long
'And we need to create the Event handle for DirectX to trigger when it
receives input:
 
Dim hEvent As Long
Implements DirectXEvent8


Private Sub Form_Load()
Me.Show 'Display the form if it isn't already
 
Set dxObject = New DirectX8 'must create the object.
Set dxInputObject = dxObject.DirectInputCreate
Set dxiDevice = dxInputObject.CreateDevice("guid_SysMouse")
 
'Next, we need to tell DirectInput what type of device we want to get
'data from, and what type of control we want to have over it.
 
Call dxiDevice.SetCommonDataFormat(DIFORMAT_MOUSE)
Call dxiDevice.SetCooperativeLevel(frmMain.hWnd, DISCL_FOREGROUND Or
DISCL_EXCLUSIVE)
Dim dxiProp As DIPROPLONG
dxiProp.lHow = DIPH_DEVICE
dxiProp.lObj = 0
dxiProp.lData = BufferSize 'The constant we declared up above
     
Call dxiDevice.SetProperty("DIPROP_BUFFERSIZE", dxiProp)

'Finally, we need to set up the Event that we're going to use to read
the mouse input:
 
hEvent = dxObject.CreateEvent(frmMain)
dxiDevice.SetEventNotification hEvent
 
' Now we 're ready to start reading the device!
 
dxiDevice.Aquire
If Not (eventid = hEvent) Then Exit Sub 'event was not for us
 
  Dim dxiDeviceData(1 To BufferSize) As DIDEVICEOBJECTDATA
  Dim numEvents As Long 'When using events, this should be just 1
  Dim i As Long 'looping variables
         
 
  numEvents = dxiDevice.GetDeviceData(dxiDeviceData, DIGDD_DEFAULT)
         
'Now we need to loop through all the events, just in case there is
more than one in the buffer. lOfs is a structure that contains all the
information about the input device's report:
 
For i = 1 To numEvents
  Select Case dxiDeviceData(i).lOfs
    Case DIMOFS_X
      'the mouse has moved along the X Axis
       'dxiDeviceDate(i).lData contains 1, 0 or -1
    Case DIMOFS_Y
      'the mouse has moved along the Y axis
      'dxiDeviceDate(i).lData contains 1, 0 or -1
    Case DIMOFS_BUTTON0
      'the first (left) button has been pressed/released
      'dxiDeviceDate(i).lData contains 0 or 1
    Case DIMOFS_BUTTON1
      'the second (right) button has been pressed/released
      'dxiDeviceDate(i).lData contains 0 or 1
    'These constants go all the way up to BUTTON7
 
   End Select
   xposition = dxiDeviceDate(i).lData + xposition
   yposition = dxiDeviceDate(i).lData + yposition
Next i
     
DoEvents 'otherwise you may lock your system

End Sub

Private Sub Form_Terminate()
dxiDevice.UnAquire
End Sub

Clarification of Answer by verteiron-ga on 09 Dec 2002 00:15 PST
This section:
--------------
If Not (eventid = hEvent) Then Exit Sub 'event was not for us 
  
  Dim dxiDeviceData(1 To BufferSize) As DIDEVICEOBJECTDATA 
  Dim numEvents As Long 'When using events, this should be just 1 
  Dim i As Long 'looping variables 
          
  
  numEvents = dxiDevice.GetDeviceData(dxiDeviceData, DIGDD_DEFAULT) 
          
'Now we need to loop through all the events, just in case there is
more than one in the buffer. lOfs is a structure that contains all the
information about the input device's report:
  
For i = 1 To numEvents 
  Select Case dxiDeviceData(i).lOfs 
    Case DIMOFS_X 
      'the mouse has moved along the X Axis 
       'dxiDeviceDate(i).lData contains 1, 0 or -1 
    Case DIMOFS_Y 
      'the mouse has moved along the Y axis 
      'dxiDeviceDate(i).lData contains 1, 0 or -1 
    Case DIMOFS_BUTTON0 
      'the first (left) button has been pressed/released 
      'dxiDeviceDate(i).lData contains 0 or 1 
    Case DIMOFS_BUTTON1 
      'the second (right) button has been pressed/released 
      'dxiDeviceDate(i).lData contains 0 or 1 
    'These constants go all the way up to BUTTON7 
  
   End Select 
   xposition = dxiDeviceDate(i).lData + xposition 
   yposition = dxiDeviceDate(i).lData + yposition 
Next i 
      
DoEvents 'otherwise you may lock your system 
--------------

needs to be in the DirectXEvent8_Callback event. If you click on the
Object dropdown, DirectXEvent8 will be listed, with Callback as its
only event. Move the code listed above out of Form_Load and into
DirectXEvent8_Callback. Also, correct the lines that compute the
xposition and yposition; right now they read "dxiDeviceDate" instead
of "dxiDeviceData".

In addition, for xposition and yposition to keep track of the cursor
coordinates, I believe you will have to move them out of their current
location and into their respective CASE statements:

Case DIMOFS_X 
   xposition = dxiDeviceDate(i).lData + xposition 
Case DIMOFS_Y
   yposition = dxiDeviceDate(i).lData + yposition 

Finally, make sure that you use "dxiDevice.Acquire" and
"dxiDevice.Unacquire" (this one was my fault, I had them spelled
without the "c" in my sample code). After making all of the above
changes, I was able to compile and run the program without trouble and
track the mouse movement.

Remember, while this program will return the accurate mouse values
you're looking for, it will take a while to get used to the way
DirectX handles itself. If you find yourself lost, I highly recommend
you visit the DirectX4VB DirectInput8 tutorials I linked to in my
original answer. They provide a very comprehensive overview of
DirectInput and DirectX in general. In addition, their sample
application for tracking the mouse via DirectInput demonstrates how to
keep track of its position as well as a few other tricks. Download it
here:

http://www.exhedra.com/DirectX4VB/CodeDownloads.asp

I hope this helps you out! It looks like you're doing well so far.
Comments  
There are no comments at this time.

Important Disclaimer: Answers and comments provided on Google Answers are general information, and are not intended to substitute for informed professional medical, psychiatric, psychological, tax, legal, investment, accounting, or other professional advice. Google does not endorse, and expressly disclaims liability for any product, manufacturer, distributor, service or service provider mentioned or any opinion expressed in answers or comments. Please read carefully the Google Answers Terms of Service.

If you feel that you have found inappropriate content, please let us know by emailing us at answers-support@google.com with the question ID listed above. Thank you.
Search Google Answers for
Google Answers  


Google Home - Answers FAQ - Terms of Service - Privacy Policy