Virtual Joystick

 Download CD Content

In this chapter, we take a look at the basics of building a utility for simulating a joystick. The basic concepts behind the joystick are to eliminate the need for a real joystick to be connected to the Tablet PC to play games. In theory, this sounds great, but realistically, the usefulness of this application is probably very limited depending on the game. With that said, you can use this same technique for controlling your own game projects (we'll do something similar in Chapter 26, Pong Game), and with some tweaking, this could be an interesting way to input information into any application without typing.

  Note 

The source code for the projects are located on the CD-ROM in the PROJECTS folder. You can either type them in as you go or you can copy the projects from the CD-ROM to your hard drive for editing.

Key Concepts

As you already know, the general idea behind this application is to simulate a joystick. Most games that support joysticks also offer the user the ability to use a keyboard. Obviously, there might be times that a Tablet PC user may not have his keyboard with him, but might want to play a game. The obvious approach to playing the game is to use the Input Panel, but this obstructs so much of the screen's real estate that it might be difficult to see the game you are playing.

Our approach is to develop an application based around the SendKeys method. By using SendKeys, we have the ability to send keystrokes to other applications. We can assign keys for the various directions and buttons that a joystick would normally use (see Figure 25.1). The keys correspond to the keys the game is set up to use. We'll store the keys in the Registry and retrieve them as needed.

click to expand
Figure 25.1: The joystick will look like this.

Getting Started

Begin by creating a new VB Window Forms application. As you can see in Figure 25.1, the GUI is quite simple. We use a background image on a form to simulate the appearance of a joystick. The image is available on the CD-ROM that is included with the book in the Chapter 25 project folder. After assigning the background to the image, resize the form to approximate its dimensions. The next step is to place label controls to represent the keys.

The following Label controls need to be created with the following names and placed in the correct locations:

  • lblUp
  • lbl45
  • lblRight
  • lbl135
  • lblDown
  • lbl225
  • lblLeft
  • lbl315

The previous labels handle the directional elements for the joystick. There are a few remaining labels that we need to add. First, we need to add labels called lblReturnPos and lblDelay, which help to control how long the application waits between virtual keystrokes. The last two steps are to add a Timer control, a StatusBar control, and an InkEdit control to the form. The InkEdit control will be used to change the values of the directions as the user will not have access to his keyboard. You can leave their names as the default. The form should now look like Figure 25.2 (so that you can see them better, the labels have had values assigned to them).

click to expand
Figure 25.2: The final GUI.

Writing Code

We begin with importing the appropriate namespaces. Add the following code to the Code Editor:

Imports Microsoft.Win32
Imports Microsoft.Ink
Imports System.Windows.Forms.Screen

We are now going to create the variables for our application, which include values for the directions, the screen dimensions for both x and y directions, a Boolean value for joystick enabled, and the Registry key value.

Here is the code:

Dim DUp, DDown, DLeft, DRight, D45, D135, D225, D315, DReturnPos, DDelay As Object
 Dim X As Integer = PrimaryScreen.Bounds.Width / 2
 Dim Y As Integer = PrimaryScreen.Bounds.Height / 2
 Dim JEnabled As Boolean

 Dim pRegKey As RegistryKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\VirtualJoystick")

The Registry

The Windows Registry is a central database for application configuration settings and other information required by the applications. In fact, this is its only purpose. We are going to manually add some values to the Registry so that we can see how this information is stored. For this application, you could enter values into the Registry manually, or you can simply run the Chapter25.Reg file included on the CD-ROM in the Chapter 25 folder. This adds the values to the Registry automatically for you.

  Note 

Making changes to the Registry can cause serious problems with your system. Refer to an appropriate text before making changes that you don't already understand. With this in mind, it is recommended that you enter the Registry values with the Chapter25.reg file.

After the values are entered, you can run the Registry Editor by choosing Run from the Start menu. Use the filename regedit, and then click OK to open it (see Figure 25.3). Depending on your previous use of the editor, your Registry may look very different from the one displayed in Figure 25.3. You can see from the figure that the Registry is hierarchical data storage for the settings and has five main keys listed under My Computer. You can look up the 'VirtualJoystick' application if you want. Either way, now that you have some idea of the values stored, you can close the Registry Editor.

click to expand
Figure 25.3: The Windows Registry Editor.

The .NET Framework provides two classes (Registry and RegistryKey) to work with the Registry. These classes are defined in the Microsoft.Win32 namespace, which is why we added a reference to it earlier.

The Registry Class

The Registry class is the first of the two classes we look at and contains members that provide access to Registry keys. We can define Registry keys in the following order:

CurrentUser: Stores information about user preferences

LocalMachine: Stores configuration information for the local machine

ClassesRoot: Stores information about types (and classes) and their properties

Users: Stores information about the default user configuration

PerformanceData: Stores performance information for software components

CurrentConfig: Stores non-user-specific hardware information

DynData: Stores dynamic data

As you noticed with the code we added, our data will be stored in LocalMachine under 'VirtualJoystick.' The Registry class has a field corresponding to each of these key types. The Registry class members are described in the following list:

ClassesRoot: Provides access to HKEY_CLASSES_ROOT key

CurrentConfig: Provides access to HKEY_CURRENT_CONFIG key

CurrentUser: Provides access to HKEY_CURRENT_USER key

DynData: Provides access to HKEY_DYN_DATA key

LocalMachine: Provides access to HKEY_LOCAL_MACHINE key

PerformanceData: Provides access to HKEY_PERFORMANCE_DATA key

Users: Provides access to HKEY_USERS key

As you can see from our code, if you want to access the HKEY_LOCAL_MACHINE key, you need to call the Registry.LocalMachine member, which returns a RegistryKey type.

The RegistryKey Class

The RegistryKey class contains members that allow us to add, remove, replace, and read Registry data. Some of its common properties are detailed in the following list:

Name: Represents the name of the key

SubKeyCount: Represents the count of subkeys at the base level, for current key

ValueCount: Represents the count of values in the key

Some of the common methods of the RegistryKey class are detailed in the following list:

Close: Closes the key

CreateSubKey: Creates a new subkey if doesn't exist; otherwise, opens an existing subkey

DeleteSubKey: Deletes the specified subkey

DeleteSubKeyTree: Deletes a subkey and any children

DeleteValue: Deletes the specified value from a key

GetSubKeyNames: Returns an array of strings that contains all the subkey names

GetValue: Returns the specified value

GetValueNames: Retrieves an array of strings that contains all the value names associated with this key

OpenSubKey: Opens a subkey

SetValue: Sets the specified value

Initializing Values

In the Form_Load event, we call the Init procedure, which we are about to create. The Init procedure gets values from the Registry. We use the GetValue method, which returns the value of a subkey in the form of Object. We then initialize the values displayed by the labels so that the user can visually see the values. Initializing the values for the labels calls the InitLabels procedure.

Here are the two procedures:

Private Sub Init()
 DUp = pRegKey.GetValue("Up")
 DDown = pRegKey.GetValue("Down")
 DLeft = pRegKey.GetValue("Left")
 DRight = pRegKey.GetValue("Right")
 D45 = pRegKey.GetValue("45")
 D135 = pRegKey.GetValue("135")
 D225 = pRegKey.GetValue("225")
 D315 = pRegKey.GetValue("315")
 DReturnPos = pRegKey.GetValue("ReturnPos") ' Setup delay & return position
 DDelay = pRegKey.GetValue("Delay")
 pRegKey.Close()

 JEnabled = False
 Timer1.Interval = Int(DDelay)

 InitLabels(DUp, lblUp)
 InitLabels(DDown, lblDown)
 InitLabels(DLeft, lblLeft)
 InitLabels(DRight, lblRight)
 InitLabels(D45, lbl45)
 InitLabels(D135, lbl135)
 InitLabels(D225, lbl225)
 InitLabels(D315, lbl315)
 InitLabels(DReturnPos, lblReturnPos)
 InitLabels(DDelay, lblDelay)

 InkEdit1.Text = ""

End Sub

Private Sub InitLabels(ByVal name As Object, ByVal lbl As Label)
 lbl.BackColor = Color.Transparent
 lbl.ForeColor = Color.Red
 lbl.TextAlign = ContentAlignment.MiddleCenter
 lbl.Text = name
End Sub

You may have noticed that we set the Timer1 Interval property equal to DDelay. This is the value we retrieved from the Registry. By default, this value is equal to 2000 milliseconds. It's now time to write the code that sends the keys to other applications using the Timer1_Elapsed event.

We begin by testing to see if the application is enabled. If so, we then use a series of If...Then and Case statements to determine where the mouse is positioned on the screen. Depending on where our pen position is on the screen, we send the appropriate keys. For example, if our pen is positioned in the middle of the screen, our joystick would be centered and would not send a key. If we were to move down, the application would then send the value of down.

Here is the code:

Private Sub Timer1_Elapsed(ByVal sender As System.Object, ByVal e As System.Timers.ElapsedEventArgs) Handles Timer1.Elapsed
 StatusBar1.Text = Control.MousePosition.ToString

 If JEnabled Then

 If Control.MousePosition.X > X + 50 And Control.MousePosition.Y < Y - 50 Then
 SendKeys.Send(D45)
 Exit Sub
 ElseIf Control.MousePosition.X > X + 50 And Control.MousePosition.Y > Y + 50 Then
 SendKeys.Send(D135)
 Exit Sub
 ElseIf Control.MousePosition.X < X - 50 And Control.MousePosition.Y > Y + 50 Then
 SendKeys.Send(D225)
 Exit Sub
 ElseIf Control.MousePosition.X < X - 50 And Control.MousePosition.Y < Y - 50 Then
 SendKeys.Send(D315)
 Exit Sub
 End If

 Select Case Control.MousePosition.X
 Case Is < X - 100
 SendKeys.Send(DLeft)
 Exit Sub
 Case Is > X + 100
 SendKeys.Send(DRight)
 Exit Sub
 End Select

 Select Case Control.MousePosition.Y
 Case Is < Y - 100
 SendKeys.Send(DUp)
 Exit Sub
 Case Is > Y + 100
 SendKeys.Send(DDown)
 Exit Sub
 End Select

 End If

End Sub 

There are a couple of things we have left to do. For starters, we need to have a way to instruct the application when it is enabled. An easy way to do this is to use the Form_MouseDown event and test for the right mouse button being pressed. If the right button is pressed, the application will set JEnabled to the opposite of itself, effectively setting it from True to False or False to True.

Here is the code:

Private Sub Form1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown
 If e.Button = MouseButtons.Right Then
 JEnabled = Not (JEnabled)
 End If
End Sub

The final step in the application is to look at how we can store new values for the various directions. We can use the SetValue method to set these values, but first, we need a way to change them. Each of the labels has a Click event and we can use the Click event for all of them. For this example, we look at only lblUp. This is also where the InkEdit control comes into play.

We begin this procedure by testing to see if the length of InkEdits text is equal to 1. If so, we assume that the value needs to be stored. Otherwise, we can assume the user entered an incorrect value because we only have the ability to store a single character. We now store the value and then set the InkEdit control to an empty string, finishing by closing the Registry.

Here is the code:

 Private Sub lblUp_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lblUp.Click
 Dim regKey As RegistryKey
 Dim ver As Decimal

 If InkEdit1.TextLength = 1 Then
regKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\VirtualJoystick", True)
 lblUp.Text = InkEdit1.Text
 InkEdit1.Text = ""
 regKey.SetValue("Up", lblUp.Text)
 regKey.Close()
 End If
 End Sub

The application is now finished. You can test it in several ways. An easy way is to open Notepad and then run the application. Next, right-click the application to enable it and then maximize Notepad. Depending on your pen's position, you should see the various keys being input into Notepad, as shown in Figure 25.4.

click to expand
Figure 25.4: The application is sending keys to Notepad.

Summary

In this chapter, we built a very unique application that emulates a joystick. We used a variety of new concepts, including reading and writing to the Registry. The application could easily be upgraded by adding code to create a taskbar icon for the application. You could also add the ability to alter the strings for each direction and save them to the Registry. Another interesting idea is to turn this application into a full-screen virtual keyboard, which would send keys to an application depending on the position of the mouse. In Chapter 26, we build a pong game that uses some of the concepts we've looked at for controlling movement.



Developing Tablet PC Applications
Developing Tablet PC Applications (Charles River Media Programming)
ISBN: 1584502525
EAN: 2147483647
Year: 2003
Pages: 191

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net