Input

Why leave the safe world of form input events?

If OnKeyDown, OnMouseDown or OnMouseMove suit your needs, then why use anything else? Well, you may require better accuracy from your mouse. You may want faster response to a keypress. Or you just want to avoid the overhead of events and use a polled input solution. What about joysticks? There’s no built in support for that in .NET. Clearly there are multiple reasons.

 

So how do we use other forms of input?

There are multiple interfaces available to allow the capture of input from devices such as a keyboard, mouse or joystick:

Standard window messages (i.e. WM_KEY*, WM_MOUSE* and by extension, events)

  • Raw input
  • Direct Input
  • WinMM (for joysticks only)
  • XInput (for joysticks only)

The first option is really already done for you via the form events. The rest will require some effort to get working properly. Thankfully Gorgon includes a plug-in that allows us to use the raw input interfaces and the WinMM joystick interface.

 

How do we use this magical plug-in?

If you don’t want hand-holding you can view the source code for the INeedYourInput example (if you’ve installed the source code: <path_to_gorgon>\Source\Examples\Input\INeedYourInput).</path_to_gorgon>

 

OK, now that you’re sufficiently annoyed with having to look through awful source code we can begin:

 

Loading the plug-in.

The input interfaces are in the GorgonLibrary.InputDevices namespace. So place this in your using section (assuming C#, adjust for your language of choice):

using GorgonLibrary.InputDevices  // Or Import GorgonLibrary.InputDevices if you’re using VB.NET.

To load the plug-in we need to declare an input object that we wish to use and load the plug-in via the static Input.LoadInputPlugIn() method:

private Input _myInputObject;

 

void InitializeInput()

{

   _myInputObject = Input.LoadInputPlugIn(“<path_to_plugins>\GorgonInput.DLL”);  // Replace <path_to_plugins> with the path where GorgonInput.DLL is located.</path_to_plugins></path_to_plugins>

}

And that should load the input plug-in. Of course you’re welcome to load any input plug-in you wish (as long as it conforms to the Gorgon plug-in and input interfaces).

 

Using the damn thing.

So now you’ve loaded it, what do you do with it? If you scan the object in the debugger you’ll notice that the Mouse, Keyboard and Joysticks properties are set to NULL. This is by design:  The input device interfaces won’t be instantiated until the input system is bound to a window.  In fact it is impossible to create these interfaces without a window handle.  The handle gives the input library some context as to which window will receive the input.  This is particularly important in ”exclusive mode”.  This binding process also hooks some events to handle device acquisition during app focus changes.

So as indicated by the note above, we need to bind the input object to a window (or more accurately a control). To do this we call the Input.Bind(control) method:

void InitializeInput()

{

   // Previous code goes here.

 

   _myInputObject.Bind(myForm);

}

And from here you’ll want to enable which devices you want to use via the Enabled property on each of the devices:

void InitializeInput()

{

   // Previous code goes here.

 

   _myInputObject.Mouse.Enabled = true;

   _myInputObject.Mouse.Exclusive = true;

   _myInputObject.Mouse.AllowBackground = false;

}

For our little sample here we will set the mouse as Exclusive which is indicated by the Mouse.Exclusive property. This means that the window we’re bound with is the only window that will receive our mouse input. No other window will receive mouse input while our application is focused. If the application loses focus, for example if we press Alt+Tab to switch away the mouse control will come back. If you’re wanting to keep the mouse exclusive no matter what, then set the Mouse.AllowBackground property to true. Please note that this will restrict the mouse input to your application window only until your app is shut down, this may result in odd behaviour for the OS.

 

Getting data from our mouse.

We can retrieve mouse data in a couple of ways:

  • Events
  • Device polling

Please note that joysticks can only be polled and will NOT use events.

 

By using events we can assign event handlers to our mouse interface and retrieve data in a similar fashion to that of the windows forms events:

void InitializeInput()

{

   // Previous code goes here.

 

   _myInputObject.Mouse.MouseDown += new MouseInputEvent(MouseDown);

}

 

private void MouseDown(object sender, MouseInputEventArgs e)

{

   // Usually button 2 corresponds with the right mouse button, this may

   // depend on your system settings.

   if (e.Buttons == MouseButtons.Button2)

      MessageBox.Show(“Mouse button 2 was pressed.”);

}

As you can see it’s very similar to that of the Winforms mouse down event.

To achieve the same using polling:

void Gorgon_Idle(object sender, FrameEventArgs e)

{

   if ((_myInputObject.Mouse.Button & MouseButtons.Button2) == MouseButtons.Button2)

      MessageBox.Show(“Mouse button 2 was pressed.”);

}

There are advantages and disadvantages to either method, so the use of one over the other is dependent on your situation.

 

Other devices

The other devices work in a similar manner (except that joysticks don’t use events). The keyboard can be polled and use events in a similar fashion. Note that the keyboard does not allow for a background exclusive mode. This is keep people from shooting themselves in the foot.

 

Of particular interest for the keyboard interface is the Keyboard.KeyMappings property. This property is a collection of values that map to the key. The values in the collection contain not only the character representation of the key, but also a shifted version. For example, the KeyboardKeys.A code will return an ‘a’ for the non-shifted character and ‘A’ for the shifted character.

 

Plug-in design rationale.

The input plug-in system is designed to load multiple input plug-in types. The reason for this is that an input plug-in can supply interfaces for specific devices and ignore others (i.e. the device properties will be NULL).  For example: the joystick support in the included plug-in is weak. Incredibly weak. It supports the bare essentials and that’s it. This is because it relies on the joystick support in WinMM.dll and that provided support in that library is very basic. So if you want to take advantage of your XBox 360 controller and the specific functionality that’s included with that device you can create a plug-in which supports XInput and have it expose only joystick functionality. This way you can use the raw input plug-in and the specialized functionality from the XInput libraries.

 

It’s worth noting that the XBox 360 controller WILL work with the included plug-in.

 

The reasoning for this particular (and confusing) design was to address the issue that DirectInput is considered depreciated for mice and keyboard input. So the choice for the included Gorgon input plug-in was to go with raw input. The joystick functionality was merely added as a basic placeholder mostly to test the interfaces, but also to provide basic support for joysticks without requiring a dependency on DirectInput.

Leave a Reply