DirectX:DirectInput:Tutorials:VB:DX7:Mouse Handling

From GPWiki
Jump to: navigation, search

Here kitty-kitty! It's time to catch a mouse. Actually, we're not going to catch it, we're going to acquire it. If you've been looking for a more robust and precise alternative to standard VB mouse handling, you've come to the right place my feline friend!

But enough babble, lets talk DirectX. There are a few things you'll have to come to terms with if you'd like to use DirectInput to handle your mousey:

  • The standard mouse cursor will disappear
  • You'll have to draw your own cursor
  • You won't be given absolute X and Y coordinates
  • There will be no events, you must actively poll the device
  • Mommy isn't here to hold your hand anymore

Still with me? Check out these initialization steps:

Dim mobjdx As New DirectX7 Dim mobjdi As DirectInput Dim mobjdiMouse As DirectInputDevice

   Set mobjdi = mobjdx.DirectInputCreate()
           
   Set mobjdiMouse = mobjdi.CreateDevice("GUID_SysMouse")
   
   mobjdiMouse.SetCommonDataFormat DIFORMAT_MOUSE
   mobjdiMouse.SetCooperativeLevel frmMouse.hWnd, DISCL_FOREGROUND Or DISCL_EXCLUSIVE
   mobjdiMouse.Acquire

Here we have initialized the DirectInput object, and then used it to create a device. The DirectInput.CreateDevice method accepts one argument, the GUID of the device we'd like to create. To access the system's standard mouse, simply pass GUID_SysMouse. Next, we set the data format we'll be using for the device. This tells DirectInput how to interpret the data that it receives. Obviously, we want to interpret the data as DIFORMAT_MOUSE. Finally, we set the cooperative level (much like DirectDraw), and call the DirectInputDevice.Acquire method to initialize data acquisition for the device.

It is important to note: If the Form object passed as the first parameter of the SetCooperativeLevel method is not yet visible, the Acquire method will fail! Be sure to call Form.Show when needed. Also, if we lose exclusivity (if some other program takes the mouse away from us), we will have to reacquire the mouse or face the consequences (errors)!

Once acquired, we can poll the device for input whenever we feel like:

Dim mdiMState As DIMOUSESTATE

   mobjdiMouse.GetDeviceStateMouse mdiMState

DIMOUSESTATE is like a UDT for mouse data. It can contain info on the X, Y, and Z (!!!) motion of the mouse, in addition to info on the various button states. Calling the DirectInputDevice.GetDeviceStateMouse method fills the variable with the most recent data received from the mouse. You may want to place some error handling code around this call, it will fail and raise an error if we've lost exclusivity.

The info returned, as I said before, is NOT absolute. Checking the value of mdiMState.x will NOT give you the current X-coordinate of the mouse. What it will give you is the mouse X-displacement since the last time you checked the mouse state. This means that you have to keep track of the mouse's position yourself:

Const MOUSE_SPEED = 2 Dim mintMouseX As Integer

   mintMouseX = mintMouseX + mdiMState.x * MOUSE_SPEED

This code will add the observed X-displacement of the mouse to the current cursor X-coordinate. Also, it multiplies the displacement by some constant, allowing us to increase the sensitivity of motion. Do the same thing for the Y-displacement, and you've got yourself some absolute coordinates! You should probably include some code that checks for the edges of the screen (or form) to ensure that the cursor doesn't escape and run amok.

Dim mblnLMouseButton As Boolean Dim mblnRMouseButton As Boolean

   If mdiMState.buttons(0) <> 0 Then mblnLMouseButton = True
   If mdiMState.buttons(0) = 0 Then mblnLMouseButton = False
   
   If mdiMState.buttons(1) <> 0 Then mblnRMouseButton = True
   If mdiMState.buttons(1) = 0 Then mblnRMouseButton = False

Buttons! Can't forget those! DirectInput gives support for up to 8 buttons (or something crazy like that), but we'll just use the standard left and right mouse buttons here. The buttons member of the DIMOUSESTATE type is an array, the first index represents the state of the left mouse button, the second index represents the state of the right mouse button. We need only check these values as compared to zero to determine if they are currently being held or not. Then, assigning values to some booleans makes it easy for us to check this info whenever we like.

That's all there is to it. You now have some variables that describe the X and Y coordinates, and some booleans that describe the button states. Use this information as you see fit!

   mobjdiMouse.Unacquire
       
   Set mobjdiMouse = Nothing
   Set mobjdi = Nothing

Termination is always fun. Don't forget to Unacquire the mouse when you're done.

Click here to download sample source code demonstrating DirectInput mouse handling.