Windows Phone 7 : Reading the Keyboard and Text Input (part 1) - Using a Hardware Keyboard

9/23/2013 9:19:06 PM

There are two different areas where we might consider reading some form of keyboard input from the user: for controlling a game (by using the cursor keys, for example) and for text input (perhaps to enter a name in a high-score table).

The first of these requires the presence of a hardware keyboard. Keyboards can make a huge difference to some applications such as when taking notes or writing e-mail, and they can be useful for gaming, too.

Some of your users will have such a keyboard, and others (probably the majority) will not. For this reason, it is strongly advised not to make having a hardware keyboard a requirement of your game. By all means allow the keyboard to enhance the gaming experience, but please do ensure that it still works for those users who have only a touch screen for control.

For text input, users can type on a hardware keyboard if they have one, or use the onscreen keyboard known as the Soft Input Panel (SIP) if they do not. The methods both produce the same end result from the perspective of your game: it can ask for some text input, which it receives from the user. Exactly how the user enters it is not something that your game needs to worry about.

Let's take a look at how to interact with hardware keyboards and how to get the user to enter some text into your game.

1. Using a Hardware Keyboard

Just as XNA provides the TouchPanel object to allow us to read input from the touch screen, it also provides the Keyboard object to allow keyboard input to be read. It provides a single method, GetState, which provides a snapshot of the current keyboard activity. Just as with the TouchPanel, this object allows us to poll the keyboard state rather than use an event-based model such as the one you might be familiar with if you have spent time in WinForms development.

GetState returns a KeyboardState object from which we can read whatever information we need to control a game. There are three methods that can be called on the KeyboardState object:

  • GetPressedKeys returns an array of Keys values from which the complete set of current pressed keys can be read. If you want to allow a large range of keys to be used (such as to read the input when the user is typing, for example), this is probably the best method for querying the keyboard. Note that the array contains simple keycodes and nothing more: no information about pressed or released states is contained within this data.

  • IsKeyDown returns a boolean indicating whether a specific key (provided as a parameter) is currently pressed down.

  • IsKeyUp is the reverse of IsKeyDown, checking to see whether a specific key is not currently pressed.

All these functions operate using the XNA-provided Keys enumeration. This enumeration includes a huge range of keys that might potentially be pressed, even though some of them won't exist on any given target device. The alphabetical characters have values in the enumeration with names from A to Z; because the enumeration deals only with pressed keys rather than typed characters, there is no provision for lowercase letters. The numeric digits are represented by the names D0 to D9 (enumerations do not allow names starting with digits, so a prefix had to be applied to these items to make their names valid). The cursor keys are represented by the values named Up, Down, Left, and Right.

If you are unsure about which enumeration item corresponds to a key on the keyboard, add some code to your Update function that waits for GetPressedKeys to return one or more items and then set a breakpoint when this condition is met. You can then interrogate the contents of the Keys array to see which keycode has been returned.

1.1. Direct Keyboard Polling

The example project KeyboardInput provides a very simple implementation of moving a sprite around the screen using the cursor keys. The code to perform this, taken from the Update function, is shown in Listing 1.

Example 1. Using the keyboard to move a sprite
// Move the sprite?
if (Keyboard.GetState().IsKeyDown(Keys.Up)) sprite.PositionY -= 2;
if (Keyboard.GetState().IsKeyDown(Keys.Down)) sprite.PositionY += 2;
if (Keyboard.GetState().IsKeyDown(Keys.Left)) sprite.PositionX -= 2;
if (Keyboard.GetState().IsKeyDown(Keys.Right)) sprite.PositionX += 2;

If you are lucky enough to have a device with a hardware keyboard, you can try the example and see how it responds. If you don't have such a device, you can use the emulator to experiment instead. But you will notice something that seems to be a bit of a problem here: pressing the cursor keys in the emulator has no effect; the sprite doesn't move at all.

The reason for this is that the emulator disables keyboard input by default. There are three keys that can be pressed on the PC keyboard to change this: the Page Up key will enable keyboard input, Page Down will disable it, and the Pause/Break key will toggle its enabled state. By default, keyboard input is disabled.

Press the Page Up key and then try the cursor keys again. The sprite should spring into life (if it doesn't, click within the screen area of the emulator and try pressing Page Up again). Knowing how to enable the keyboard is useful in other areas within the emulator, too—it makes it much easier to use the web browser, for example!

Polling for input in this way is ideal for games. There is no keyboard repeat delay between the first report of a key being pressed and subsequent reports for the same key, and no repeat speed to worry about that would cause delays between reports of a held key even after the initial delay had expired. Polling gives us a true and accurate picture of each key state every time we ask for it.

It also allows us to easily check for multiple keys pressed together. If you try pressing multiple cursor keys, you will see that the sprite is happy to move diagonally. This is perfect for gaming, in which pressing multiple keys together is a common requirement.

1.2. Checking for Key Pressed and Key Released States

If you need to monitor for the point in time where the user has just pressed or released a key, XNA's Keyboard object doesn't provide any information to this effect for you to use. It is easy to work this out with a little extra code, however.

Once the keyboard state has been read, the returned KeyboardState structure keeps its values even after the keyboard state has moved on. By keeping a copy of the previous state and comparing it with the current state, we can tell when a key has been pressed or released: if it was up last time but is down now, the key has just been pressed; if it was down last time but is up now, it has just been released.

We can easily use this approach to look for individual keys or can loop through the array returned from GetPressedKeys in order to look for all keys that were pressed or released since the last update. Listing 2 shows how details of all pressed and released keys can be printed to the Debug window. This code can also be found within the KeyboardInput example project.

Example 2. Checking for pressed and released keys
// Read the current keyboard state
currentKeyState = Keyboard.GetState();

// Check for pressed/released keys.
// Loop for each possible pressed key (those that are pressed this update)
Keys[] keys = currentKeyState.GetPressedKeys();
for (int i = 0; i < keys.Length; i++)
// Was this key up during the last update?
if (_lastKeyState.IsKeyUp(keys[i]))
// Yes, so this key has been pressed
System.Diagnostics.Debug.WriteLine("Pressed: " + keys[i].ToString());
// Loop for each possible released key (those that were pressed last update)
keys = _lastKeyState.GetPressedKeys();
for (int i = 0; i < keys.Length; i++)
// Is this key now up?
if (currentKeyState.IsKeyUp(keys[i]))
// Yes, so this key has been released
System.Diagnostics.Debug.WriteLine("Released: " + keys[i].ToString());

// Store the state for the next loop
_lastKeyState = currentKeyState;

There are two important things to remember when monitoring for pressed and released keys. First, you must check them during every single update if you want to avoid missing key state updates. Second, you should query the keyboard state only once per update and should store this retrieved state data away for use during the next update. Without following this approach, the state might change between the individual calls to GetState resulting in key state changes being overwritten and lost.
  •  Galaxy Note II vs Galaxy Mega
  •  It's Not Finished Yet!
  •  Looking For Advice On Choosing The Best Phone?
  •  Windows Phone 8 : Working with the Camera (part 3) - Camera Lens App
  •  Windows Phone 8 : Working with the Camera (part 2) - Raw Hardware Access
  •  Windows Phone 8 : Working with the Camera (part 1) - Using the PhotoCamera Class
  •  BlackBerry Development : Pushing Data to External Users - Web Signals (part 6) - Building a Web Signal - Unsubscribing from a Subscription
  •  BlackBerry Development : Pushing Data to External Users - Web Signals (part 5) - Building a Web Signal - Requesting the Status of a Subscription
  •  BlackBerry Development : Pushing Data to External Users - Web Signals (part 4) - Building a Web Signal - Pushing Data to Subscribers
  •  BlackBerry Development : Pushing Data to External Users - Web Signals (part 3) - Building a Web Signal - Web Signal Domains, Web Signal Subscriber Registration
    Top 10
    Review : Sigma 24mm f/1.4 DG HSM Art
    Review : Canon EF11-24mm f/4L USM
    Review : Creative Sound Blaster Roar 2
    Review : Philips Fidelio M2L
    Review : Alienware 17 - Dell's Alienware laptops
    Review Smartwatch : Wellograph
    Review : Xiaomi Redmi 2
    Extending LINQ to Objects : Writing a Single Element Operator (part 2) - Building the RandomElement Operator
    Extending LINQ to Objects : Writing a Single Element Operator (part 1) - Building Our Own Last Operator
    3 Tips for Maintaining Your Cell Phone Battery (part 2) - Discharge Smart, Use Smart
    - First look: Apple Watch

    - 3 Tips for Maintaining Your Cell Phone Battery (part 1)

    - 3 Tips for Maintaining Your Cell Phone Battery (part 2)
    - How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 1)

    - How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 2)

    - How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 3)
    Popular Tags
    Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Biztalk Exchange Server Microsoft LynC Server Microsoft Dynamic Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Indesign Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe After Effects Adobe Photoshop Adobe Fireworks Adobe Flash Catalyst Corel Painter X CorelDRAW X5 CorelDraw 10 QuarkXPress 8 windows Phone 7 windows Phone 8