DirectXInput:
Mouse Control
Author:
Jack Hoxley
Written: 3rd August 2001
Contact: [EMail]
Download: DI8_Mouse.Zip
(12kb)
Contents
of this lesson
1. Introduction
2. Setting Up The Device
3. Getting Input From The Device
4. Event Based and Polling Based
Input.
1.
Introduction
Welcome
back to part two of the DirectInput8 series -
you'll need to have read part 1 before embarking
on this part (read it
here). The main reason behind this is that
once you've got the basics (covered in the first
part) under your belt the rest is extremely easy.
As
you're aware this tutorial covers using the mouse
- I hope I can take it for granted that you know
how to use your mouse! and if you know how to
use your mouse then programming for it is just
as simple. I dont think I need to insult your
intelligence by explaining mouse movement and
mouse buttons to you... For this very reason,
we can jump straight into the action, very little
preamble is required and the code is pretty simple
anyway...
2.
Setting Up The Device
This
is extremely simple really, we need do little
more than reconfigure a couple of lines from our
original keyboard example. I'm only going to show
you the changed lines here, a complete working
sample is available to download - and you can
poke around with that as much as you fancy...
First
up, a few new constants and declarations:
'//Speed - this is how fast the mouse cursor will move: Private Const mSpeed As Single = 2 '//BufferSize - how much data DI will store for us: Private Const BufferSize As Long = 10 'events
'//Status
variables and other
stuff :)
Private mPosition As
Point 'where the mouse
is currently located...
|
|
|
|
Not exactly complicated really. As we'll see later
on, DirectInput reports mouse movement on the
X/Y axis as one of {-1, 0, +1}, which is perfect
as a multiplier (hence the mSpeed constant). Alter
this value to increase/decrease the speed that
the mouse moves at - you'll need to put an option
in your game to this effect as DirectInput doesn't
use any of the control-panel settings (ie, it
wont move as fast as the user has probably set
it to). Also note that as this value increases
the "jerkiness" of the movement increases
- above 4 it'll appear quite jerky, and any diagonal
movement will look very strange indeed... you
can quite easily compensate for this with a little
clever thinking.
The
next step is to modify the actual initialisation
routine:
Set DIDevice = DI.CreateDevice("guid_SysMouse") Call DIDevice.SetCommonDataFormat(DIFORMAT_MOUSE) Call DIDevice.SetCooperativeLevel(frmMain.hWnd, DISCL_FOREGROUND Or DISCL_EXCLUSIVE)
|
|
|
|
Gets harder everytime! you'll notice that it's
only the parameters that have changed - these
lines were present in the keyboard example (and
will be for all DirectInput applications). The
main difference here that isn't so obvious is
the change of cooperativelevel, in fact we are
actually telling DirectInput that we dont want
to cooperate with anyone - we want the mouse entirely
to ourselves. This may not be a good move for
windowed mode applications (why you'd need DI
in a plain windows environment is a little odd
anyway), but for fullscreen games its exactly
what you need. The point to bare in mind (and
you'll notice it when you run the sample code)
is that windows looses the mouse - calls to GetCursorPos(
) and related API calls will either fail or just
return the data as of just before DirectInput
stole the show. The bottom line is, no windows
cursor will appear, no other windows applications
(or windows itself) will get any mouse input.
The only way the user can mess this up is by pressing
the AppMenu key, the Start Key or by Alt+Tab-ing
away from your application.
That's
all the initialisation that needs to be done for
the mouse, now we concern ourselves with doing
something with it all!
3.
Getting Input From The Device
This
is the important part - why use DirectInput if
you dont want to know what it has to tell you!
Luckily the basics of mouse input are extremely
simple, and follow the same pattern whether you're
using event based or polling based methods (see
the next section).
The
only tricky parts are when it comes to detecting
the various types of event - DirectInput will
tell you if the mouse has moved or if a button
is up/down; but you'll need to write code to detect
a double-click, single-click, and mouse-move event,
sounds simple - but it's not always so. I experimented
with a few methods but couldn't find a generic
solution to all of them, so I've left it out -
my tip to you: record the events in order, in
a buffer, and then analyse the buffer for patterns
(two clicks in <40ms = Double Click for example).
'0. Any Variables Dim DevData(1 To BufferSize) As DIDEVICEOBJECTDATA 'storage for the event data Dim nEvents As Long 'how many events have just happened (usually 1) Dim I As Long 'looping variables
'1. retrieve the data from the device. nEvents = DIDevice.GetDeviceData(DevData, DIGDD_DEFAULT) '2. loop through all the events For I = 1 To nEvents Select Case DevData(I).lOfs Case DIMOFS_X 'the mouse has moved along the X Axis mPosition.x = mPosition.x + (DevData(I).lData * mSpeed) If mPosition.x < 0 Then mPosition.x = 0 If mPosition.x > frmMain.ScaleWidth Then mPosition.x = frmMain.ScaleWidth imgCursor.Top = mPosition.y imgCursor.Left = mPosition.x
Case DIMOFS_Y 'the mouse has moved along the Y axis mPosition.y = mPosition.y + (DevData(I).lData * mSpeed) If mPosition.y < 0 Then mPosition.y = 0 If mPosition.y > frmMain.ScaleHeight Then mPosition.y = frmMain.ScaleHeight imgCursor.Top = mPosition.y imgCursor.Left = mPosition.x
Case DIMOFS_Z 'the mouse has moved along the Z axis (not sure what this one means...!)
Case DIMOFS_BUTTON0 'the first (left) button has been pressed lblmisc(2).Caption = "Button 0 State: " & IIf(DevData(I).lData = 0, "Up", "Down")
Case DIMOFS_BUTTON1 'the second (right) button has been pressed lblmisc(3).Caption = "Button 1 State: " & IIf(DevData(I).lData = 0, "Up", "Down")
Case DIMOFS_BUTTON2 'the third (middle usually) button has been pressed lblmisc(4).Caption = "Button 2 State: " & IIf(DevData(I).lData = 0, "Up", "Down")
Case DIMOFS_BUTTON3 lblmisc(5).Caption = "Button 3 State: " & IIf(DevData(I).lData = 0, "Up", "Down")
Case DIMOFS_BUTTON4 lblmisc(6).Caption = "Button 4 State: " & IIf(DevData(I).lData = 0, "Up", "Down")
Case DIMOFS_BUTTON5 lblmisc(7).Caption = "Button 5 State: " & IIf(DevData(I).lData = 0, "Up", "Down")
Case DIMOFS_BUTTON6 lblmisc(8).Caption = "Button 6 State: " & IIf(DevData(I).lData = 0, "Up", "Down")
Case DIMOFS_BUTTON7 lblmisc(9).Caption = "Button 7 State: " & IIf(DevData(I).lData = 0, "Up", "Down")
End Select Next I
|
|
|
|
Not too hard is it, once you've retrieved the
data it's just a big select-case of all the possible
states (all possible states are listed). Most
of the code above is for the user-interface in
the sample program, and not actually required
for the general use of DirectInput-Mouse. It's
in this select-case tree that you'd normally parse
out the input to other functions (mouse move events
to the camera control/player movement (for a FPS)).
The
above code is really all that's necessary for
getting input from the mouse, using that code
you have control over 3 axis' (although I've never
seen a use for the Z axis) and 8 buttons (if available).
4.
Event Based and Polling Based Input
For
the final part of this tutorial we go back to
the input collection method - as discussed in
the first part of this series. Event based over
Polling based is mostly down to your opinion,
and how you wish to structure your game engine.
As you may have gathered from the first part of
this series, Event based programming is by far
my current favourite method, it's sometimes harder
to structure, but I like the cleaner and faster
code it produces - and tracking the bugs are so
easy it's almost fun! Polling will give you the
same results, but it will often result in idle-time
spent hassling DirectInput for data that's not
there...
Either
way, polling based vs event based the code for
this sample is pretty much identical (it's shown
in the prev. section). Download the sample for
a better look at how everything fits together
- it saves me filling this space up with lots
of relatively useless text!
There,
everything you should need to know about using
the mouse in DirectInput8 - not really that hard
was it. I strongly suggest that you download the
source code for this tutorial from the top of
the page, or from the downloads
page.
|