DirectInput:
Joysticks
By: Jack Hoxley
Written: June 2000
Download:
DI_Joystick.Zip
(12kb)
Without a doubt; joysticks are
a games device - you wont need to use one unless you're creating a game. I've
never seen one used in a multimedia application before; and I doubt I ever will.
The joystick tends to be used
more in arcade style games; sports simulations in particular. You never ever
get joystick options in first person shooters; RPGs or RTS games. Even then
joysticks seem to play a back hand as a controller in some games - usually as
the second option. This is down to the fact that most PC games players prefer
to use their keyboard (I certainly do) or mouse. Joysticks tend to be a console
thing mostly. Despite this, you may well still want to use the joystick in your
applications
There are several different axis
available to you as a programmer; but you have to check if they're present first;
my cheap £2.99 joystick only has 2 buttons and 2 axis - only the newer
ones have lots of axis and lots of buttons. Here is a summary of what they are,
and what they do:
Axis/Button
name |
Use/Meaning |
X |
Movements
on the left-right axis |
Y |
Movements
up or Down |
Z |
Movements
on the Z axis; often the throttle control |
rX |
Rotation on
the X axis |
rY |
Rotation on
the Y axis |
rZ |
Rotation on
the Z axis (not very common) - usually the rudder control |
frX |
Torque on
the X axis |
frY |
Torque on
the Y axis |
frZ |
Torque on
the Z axis |
fX |
Force on the
X axis |
fY |
Force on the
Y axis |
fZ |
Force on the
Z axis |
vrX |
Angular velocity
on the X axis |
vrY |
Angular velocity
on the Y axis |
vrZ |
Angular velocity
on the Z axis |
Buttons(0
to 31) |
An array of
buttons; up to 32 buttons are supported by DirectInput |
POV |
Point Of View
Hats - controllers with up to 4 directions. The value is measured in hundredths
of degrees from north (away from user). |
Note that all entries listed between
frX and vrZ are extended capabilites - only available on the latest, most expensive
devices...
Getting input from the joystick
is very easy; and isn't particularly hardware intensive (as in not going to
slow things down). It is advisable that you download the sample program from
the top of the page to view it in it's full state, the code below is extracted
from this example.
Step1: Initialising Everything.
Because joysticks aren't an essential piece of most peoples computers you'll
find that lots of people (including myself) owning cheap lunps of plastic considered
hi-tech 10 years ago. Although hi-tech controllers have been around for quite
a while, you will still find lots of people without 32 buttons and 200 different
axis. Although enumeration isn't directly covered here it is very important
to check the capabilities of the user's controller. It is essential to gameplay
that a user can have control of everything - despite his/her hardware; nothing
is going to put them off playing it more than dying because they didn't have
button 11 to press...
Set di = dx.DirectInputCreate()
'Because DirectInput Enumerations contain information on lots of different
'devices we must specify what we're looking for - in this case we want a
'Joystick. We also want to make sure it's attached to the system. Without
'this flag, DI may detect a set of joystick drivers; and report that there
is
'a joystick - even when it's not actually present.
Set diDevEnum = di.GetDIEnumDevices(DIDEVTYPE_JOYSTICK, DIEDFL_ATTACHEDONLY)
'Warn the user that there is no joystick present.
If diDevEnum.GetCount = 0 Then
MsgBox "No joystick attached."
'There is no point continuing if there is
'no joystick
Unload Me
End If
'This is the enumeration; we've got this far
'so we know there is at least one. For the purpose of
'this tutorial we'll only bother using the default (first) device
'Dim i As Integer
'For i = 1 To diDevEnum.GetCount
'There may well only be 1
' Call lstJoySticks.AddItem(diDevEnum.GetItem(i).GetInstanceName)
'Next
'Get an event handle to associate with the device
EventHandle = dx.CreateEvent(Me) |
|
|
|
Step2: Getting hold of the
joystick
It is possible for more than one joystick to be attached; and for reasons just
stated above, it is quite possible one will be better than the other. This example
shows you how to get hold of the default (first detected) joystick:
'Create the joystick device
Set diDev = Nothing
'Get the 1st Joystick. You'll want to enumerate available
'devices first...
Set diDev = di.CreateDevice(diDevEnum.GetItem(1).GetGuidInstance)
'Tell DirectInput we're interacting with a Joystick
diDev.SetCommonDataFormat DIFORMAT_JOYSTICK
'With the cooperativelevel set to NONEXCLUSIVE we're
likely to lose the
'joystick easier - setting this to Exclusive will make it more difficult
'for windows or other applications to steal it from us.
diDev.SetCooperativeLevel Me.hWnd, DISCL_BACKGROUND Or DISCL_NONEXCLUSIVE
'Find out what device objects it has
diDev.GetCapabilities joyCaps
'Call IdentifyAxes(diDev)
'Ask for notification of events
Call diDev.SetEventNotification(EventHandle)
'Set deadzone for X and Y axis to 10 percent of the
range of travel
With DiProp_Dead .lData = 1000
.lObj = DIJOFS_X
.lSize = Len(DiProp_Dead)
.lHow = DIPH_BYOFFSET
.lObj = DIJOFS_X
diDev.SetProperty "DIPROP_DEADZONE", DiProp_Dead
.lObj = DIJOFS_Y
diDev.SetProperty "DIPROP_DEADZONE", DiProp_Dead
End With
' Set saturation zones for X and Y axis to 5 percent
of the range
With DiProp_Saturation
.lData = 9500
.lHow = DIPH_BYOFFSET
.lSize = Len(DiProp_Saturation)
.lObj = DIJOFS_X
diDev.SetProperty "DIPROP_SATURATION", DiProp_Saturation
.lObj = DIJOFS_Y
diDev.SetProperty "DIPROP_SATURATION", DiProp_Saturation
End With
SetProp 'See the full example for what this does;
it just sets up the range of the axis
'Get the joystick
diDev.Acquire
'Me.Caption = "Joystick Sample: Querying Properties"
'Get the list of current properties
' USB joysticks wont call this callback until you play with the joystick
' so we call the callback ourselves the first time
DirectXEvent_DXCallback 0
'Poll the device so that events are sure to be signaled.
'Usually this would be done in Sub Main or in the game rendering loop.
While running = True
DoEvents
diDev.Poll
Wend |
|
|
|
Step3: Getting input from
the joystick
Input from the joystick is done through the use of DirectXEvent. This procedure
is called by DirectInput everytime the user presses a button; the code that
we place in this procedure is what is executed each time - so we place code
that checks/updates the program based on what the user has just done:
'If we haven't initialised
yet; go no further
If diDev Is Nothing Then Exit Sub
'Get the device info
On Local Error Resume Next
diDev.GetDeviceStateJoystick js
'Js should now contain all the up-to-date information
'on the joystick. Unless there was an error:
'If we lost the joystick then we want to get it back again.
If Err.Number = DIERR_NOTACQUIRED Or Err.Number = DIERR_INPUTLOST Then
diDev.Acquire
Exit Sub
End If
'A simple example of moving a dummy sprite
'around based on input from the joystick
Select Case js.x
Case 0 'Full Left
Shape1.Left = 0
Case 5000 'Middle
Shape1.Left = 1
Case 10000 'Full Right
Shape1.Left = 2
End Select
Select Case js.y
Case 0 'Full up
Shape1.Top = 0
Case 5000 'Middle
Shape1.Top = 1
Case 10000 'Full down
Shape1.Top = 2
End Select
'There is more on getting information on the axis
in the complete example. |
|
|
|
You should now be able to get
information based on the X/Y coordinates of the joystick. This example doesn't
pay any attention to the buttons, hats or extra axis on a joystick; but the
code is available in the downloadable example (it's just commented out). You
can get the full program from the top of the page; or from the downloads
page.
|