Get Input - Keyboard

Welcome To The Intro

Before you take on your next blockbuster hit which will sport an unprecedented 3D Engine with real-time ray tracing and original music scores along with those realistic sounds of the ocean, do not forget one important part of the final product, user input. The use of DirectInput can easily improve the wealth of your game with its tons of features and input devices it supports. Aside from the advanced techniques of DirectInput, even the simpler methods of use can out do your basic form events. So right now, I'm hoping to teach you, the reader, the ins and outs of DirectInput and handling the keyboard so you can “Get Input” with your keyboard.

Get The Setup

Before we can officially start using DirectInput, you must make sure you have it referenced in your .NET solution and then actually "Imported" into the code file where our DirectInput Keyboard class will be created.

I went ahead and created a project for myself named "InputKeyboard" of the Windows Application type but you can name it whatever your heart desires. For the actual source files, there are two, one for the test form and another for the class we will write to handle the keyboard device. The form file name is “InputTutorial.vb” and the class file is “InputKeyboard.vb”. Now, you should be able to see the Solutions Explorer on the right side of the GUI or the tab for it, if you don't see it, and then click the tab for it. If you see no tab, then click on the View in the menu, then Solution Explorer.

Once you have that window shown, you'll see collapsed tree by the name "References", right-click on that and go to add references. It'll bring you to a dialog showing a bunch of DLLs you can reference to your project but scroll down the list "Microsoft.DirectX" along with "Microsoft.DirectX.DirectInput" and double-click on each and press OK on the dialog box. If you don't see it, you may have to look into installing DirectX9 on to your computer ( And if all goes well, we're almost ready to begin the coding!

Now that we have our project and references setup, we can simply add a couple lines to the top of the "InputKeyboard.vb" source file.

  1. Imports Microsoft.DirectX
  2. Imports Microsoft.DirectX.DirectInput

These two lines import the reference of the two namespaces, DirectX and DirectInput, into our source files allowing for an easier access to its content. If we didn't import it to the source file, we would have to type Microsoft.DirectX. etc... for every single thing...too much typing.

Where's My Keyboard

The first thing you'll need in order to retrieve input from the keyboard device, is a newly created keyboard device(obviously). Actually creating the Device is a simple as it can be. After the device is created you will need to set the type of data that will be read by the device and what priority and/or cooperative level it will have along with the rest of the applications also using that device type (ie Keyboard or Mouse).

  1. MyDevice = New Device(SystemGuid.Keyboard) 'Create the device, simple :)
  2. MyDevice.SetDataFormat(DeviceDataFormat.Keyboard) 'Our Device Should Read "Keyboard" Data
  3. MyDevice.SetCooperativeLevel(Owner, Flags) 'Owner is the form which owns the Device
  4. MyDevice.Properties.BufferSize = 8 'size of buffer, how much buffered data will be kept, more later
  5. MyDevice.Acquire()

We create the device as you would create a new instance of any class, but you must specify the type Device you’re creating with the reference to the GUID, SystemGuid.Keyboard is our reference to the keyboard, and should generally work with a majority of computers. The next line sets the data format to Keyboard which is exactly what we want.

The third line sets up the cooperative level for the device, which in human terms is how will the device be handling data from the keyboard in response to other applications. Remember, other applications use the keyboard to, so we need to know how we will act when the form using our Keyboard is not in focus and what not.

The owner variable is the reference to the form handling the device, and the variable flag is an enumerated type of CooperativeLevelFlags held within the DirectInput namespace.

  1. Enum CooperativeLevelFlags
  2.   Background 'The device window can be the focus or not the focused window and input will still be retrieved.
  3.   Exclusive 'The application gains right to exclusive access tothe keyboard, or being the only application to use the keyboard deviceat the time.
  4.   Foreground 'The device window must be focused for the device toretrieve data, if not, the device will be lost and you must reacquireit before being able to use it again.
  5.   NonExclusive 'Your application will allow sharing of the keyboard device,(but some other apps might not :P)
  6.   NoWindowsKey 'Disables use of the windows key(so that start menu won't popup when you press it
  7. End Enum

The combination of the flags should be Background or Foreground and Exclusive or NonExclusive, but be in mind some combinations will not work with the keyboard and mouse like Background and Exclusive because it forms a weird cooperative level, though the SDK does say it is possible for some types of devices.

The second to last line of code assigned the value of 8 to the property buffer size. It generally tells you that you can save up to 8 inputs from the keyboard at a time to read from the keyboard data buffer. And finally, the last code calls the Acquire procedure and that generally means we are ready to get some input!

I'd Like Some Data

Now that we know how the wonderful keyboard works and how it’s created, we will learn how to use it! From my knowledge (and I am no professional I might add), there are 2 basic ways of retrieving data from the Keyboard device in DirectInput. It is either "Immediate" or "Buffered". Both methods can be useful for a project so creating support for both integrated could be quite helpful.

With Immediate Data, DirectInput takes a quick snapshot of the current status of the Keyboard and returns the status of all of the available keys. This can be useful when you need quick input on something that doesn't require of knowing if the key was press down, or let go. I use these method for debugging purposes a lot too, placing the simple input code somewhere far out from my actual input code for the game itself.

  1. Dim State As KeyboardState
  2. State = m_Device.GetCurrentKeyboardState()

The above code retrieves the snapshot of the device keys into the class KeyboardState which is also an array. You can get a retrieve the input of the key by taking what key you want from the DirectInput.Key enumeration as the index in the KeyboardState array. The values are simply just Booleans, true and false for up or down.

When receiving input with buffered data, the device had recorded the last inputs into the keyboard up to the size of the Buffer (set when we created the device). This input proves far superior so you can really tell how many times a key was pressed. With immediate, between the times of calling for the input, that same key may have been pressed.

  1. '//Local Variables
  2. Dim Data As BufferedData, Buffer As BufferedDataCollection, continue As Boolean
  3. '//Get Input Data
  4. Try
  5.   Buffer = m_Device.GetBufferedData()
  6. Catch e As InputException 'Handles our errors, will try to recapture the device
  7.   Do
  8.     continue = False
  9.     Application.DoEvents()
  10.     Try
  11.       m_Device.Acquire()
  12.     Catch e2 As InputLostException
  13.       continue = True
  14.     Catch e3 As OtherApplicationHasPriorityException
  15.       continue = True
  16.     End Try
  17.     If Not Owner.Created Then Exit Do
  18.   Loop While continue
  19. End Try
  20. '//Process Buffered Data
  21. If Buffer Is Nothing Then Exit Sub
  22. 'Go through each element of data, and see if the key
  23. 'was pressed or let go
  24. For Each Data In Buffer
  25.   If Data.Data And &H80 Then
  26.     RaiseEvent KeyDown(Data.Offset) 'Calls KeyDown Event
  27.   Else
  28.     RaiseEvent KeyUp(Data.Offset) 'Calls KeyUp Event
  29.   End If
  30. Next

Now you're probably thinking, what the heck happened? The immediate data was so easy to get, while the buffered has like 20x more code. Let’s decipher this baby! The Data (BufferedData) represents one element in the collection of BufferedData, or the Buffer variable. So BufferedData is contained within BufferedDataCollection. The continue Boolean is used for handling any errors we have with getting input from the device.

We use to try statement to make sure if the call to retrieve the buffered data fails or not, if it does fail then we have a list of catch statements to help us from returned errors and telling us to keep continuing. Now from this code you can see the Owner.Created statement and that'll help us from keeping in an infinite loop. If the form isn't even visible or created yet, then we will quit as we will never get the device acquired until we do.

After the error handling we check if there is any buffered data, if there isn't then we exit the sub routine, if there is we process it. We process the whole collection by making a for...each loop to go through each element contained. We check the bytes using the Data property of the BufferedData class and "anding" it to the hex value of &H80. This allows us to retrieve whether the button was let go or let down. When we figure out which it was (up or down), we can call our own custom events (similar to Form Events) to handle the input.

We now have the basis of creating our own Keyboard class!

I'm A Class Clown

Now that we have the essentials and basic usage of the Keyboard device, we can create a class to wrap it up and make using it simpler, robust, and reusable in any project! The design for the class is very simple and it is downloadable and inside "InputKeyboard.vb" file.

It follows what I just created earlier in the tutorial pretty much identically. The constructor for the class will initialize the Device and set it up for use. I created a special sub routine to manually set the buffer size and there are two other functions in which you can receive keyboard data. The GetKeyState function retrieves immediate data of a particular key you want input data for, while the Update sub reads all the buffered Data and processes it by calling custom events.

Our events are simply KeyUp, and KeyDown. If you're good, you could think of a way to manage if a key is still being pressed. But to write the actual events to the class events you do it the same way you would for any events in VB .NET, but if you don't know, here's some extra info.

  1. Private WithEvents Keyboard As InputKeyboard
  2. Private Sub Keyboard_KeyUp(TheKey As Key) Handles InputKeyboard.KeyUp
  3.   If TheKey = Key.Escape Then DoFoo
  4. End Sub

You can write the sub with any name you want it to be, but the arguments much match up with the arguments of the Event. Every time the event is raised, this sub will also be called to handle the event. You can also create multiple subs and functions that can handle the same event being rose which is pretty cool. Be sure that you include the WithEvents keyword with the declaration of the class. It tells the compiler that we're enabling be able to write the events for that class.

I'm Tired And Going To Sleep

I'm finally concluding this epic tutorial by spending the next hour playing the cheap game known as Madden 2004. I've been writing this tutorial for the last 90 minutes and I'm glad I'm finally done. I hope this can help you understand the basics of DirectInput using the Keyboard. I'm not the best at this; I'm just sharing my knowledge on the subject which I learned straight from the SDK and putting it into human words.

If you have any questions or comments you can email me at, IM at X WookieMan X, or see me rounding the forums at Lucky's by the handle of Luminous. Well I'm out, later

Gregory English

Example Program


Tutorial Console

Tutorial by:

Gregory English

Date: 2003 Dec 8


Latest comment

by: Gregory English

There is no definite function for it anywhere, I myself have yet to find a nice and simple solution to this myself. All of the number constants have text in the constant name so you just can't change it to a string for simple use.

The best thing I have come up with is the old hack and slash way of comparing the 26 letters of the alphabit and the 20 number keys(the top row, and the numpad) in that way.

I was tackling this while writing the tutorial but couldn't think of a good way to do it so I didn't even include it.

Post a Comment

Printer Friendly

Copyright © 2002 - 2004 Eric Coleman, Peter Kuchnio , et. al.
There have been 120 visitors within the last 20 minutes
RSS News Feed