Blog

Input Handling in XNA Games &ndash; Part 1

May10

Written by:Tuesday, May 10, 2011

XNA makes input handling very easy. It provides one static class for each input device: Keyboard, Mouse, and GamePad. In each frame, you can query the device states and examine the current key and button states. But sooner or later you discover that there are a few tasks that are not supported:

detecting button clicks,

detecting double-clicks,

keeping track of which of the 4 controllers the user is using,

making the controls configurable,

and more.

This becomes especially apparent when you create a game with a complex user interface (windows, text boxes, etc.).

And to be clear: It is ok that these tasks are not supported because the XNA Framework is not a game engine!

While creating our XNA GUI library (see DigitalRune Game UI), we have identified several commonly needed tasks and packed them into an input service. This and the next blog posts describe our input service design.

Input Service

First step: We create an IInputService interface:

publicinterfaceIInputService { … }

All game components that process input should use this central interface. This interface will be implemented by the InputManager class. (Follow this link to learn more about services, managers and the service provider pattern: Service Provider articles.)

The InputManager implements IInputService and has one additional method:

publicclassInputManager : IInputService { …

///<summary>/// Updates the input states. This method must be called once per frame.///</summary>///<param name="deltaTime">The elapsed time since the last update.</param>publicvoid Update(float deltaTime) { … } }

The Update() method must be called once per frame, and it does all the “hard” work of our input manager.

It is worth to discuss why we do not simply use a static class with global variables. We have used the service provider pattern for several years now, and it is one of the most useful patterns for game programming. A few of its advantages in regard to input handling:

Only the developer who creates the InputManager instance and manages the game loop uses the InputManager class. The game components only use the IInputService – the additional members of the InputManager are thus hidden. The developer of a game component does not need to know that there is an InputManager.Update() method.

We can create a different IInputService implementation if necessary. For instance, an EmulationInputManager could emulate input for a missing controller. Or, a RecordAndPlaybackInputManager could record device input and play it back later. A few years ago we have used a similar solution to replay gameplay sessions.

If a game component only uses the interface, it is simpler to unit test the game component using mock objects.

Adding Functions to the Input Service

In the next blog posts, we will describe the functionality of the IInputService, including:

detecting clicks and double-clicks,

key repetition for held down keys,

mouse centering for relative mouse input,

using logical players to let the user play with any connected controller,

regulating the order of input handling and preemption if several components handle device input,

allowing the player to re-configure the input.

If you want to look at the final image in advance, here is the class diagram of the input classes in our DigitalRune Game UI library.

And here is the current documentation of our input classes: DigitalRune Game UI – Input Handling. (The library is currently an alpha version. We are still looking for possible improvements. Any feedback is welcome!)