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! |
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.
|