Main Site Links Resources Tutorials
News VB Gaming Code Downloads DirectX 7
Contact Webmaster VB Programming Product Reviews DirectX 8
  General Multimedia Articles DirectX 9

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 (Mouse wheel movement)

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

DirectX 4 VB 2000 Jack Hoxley. All rights reserved.
Reproduction of this site and it's contents, in whole or in part, is prohibited,
except where explicitly stated otherwise.
Design by Mateo
Contact Webmaster