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