Detecting if a Game Pad is Plugged in or Removed

In the latest download of our shoot em up pc game TWTPB, iteration 23, I implemented basic game pad support. There are a number of issues with this implementation maybe the most prominent one being that it does not handle plugging in and out the game pad during play. I think that it is probably a common scenario to plug in a game pad after the game has started.

This is a short tutorial on how to get your game to react when an usb device, such as a game pad, is plugged in or removed from the computer. This is handy when using the DirectInput api. XInput handles this in a transparent way which is nice, but alas there are many game controls that are not XInput compatible so when developing a pc game you probably need support for both plain DirectInput devices and XInput devices. This tutorial is Windows specific and in the C++ language.

It is not that hard to get a message when a device is added or removed, but it involves some rarely used win32 code that I spent a good few hour trying to get to work.

To start things off Windows sends you the handy WM_DEVICECHANGE windows message message when a device is plugged in or removed from the pc. So in your window message handling function you should have something like this:


WndProc(HWND a_hWnd, UINT a_msg, WPARAM a_wparam, LPARAM a_lparam) {
   switch (a_msg) {
       ...
       case WM_DEVICECHANGE:
           if (a_wparam == DBT_DEVICEARRIVAL) {
               // Device plugged in code goes here
           } else if (a_wparam == DBT_DEVICEREMOVECOMPLETE) {
              // Device removed
           }
       break;
       ...
   }
   ...
}

The there are also a number of other messages sent in the wparam parameter. So the tricky part here is that you won't get the DBT_DEVICEARRIVAL or DBT_DEVICEREMOVECOMPLETE as a default. You will only get a number of DBT_DEVNODES_CHANGED messages whether a device is plugged in or removed and this is obviously not what we want in our game code.

You will have to tell Windows that you want additional information when a device is added. You can do this with the RegisterDeviceNotification function. This function is quite complicated and takes a number of strange parameters. I for one love when a function has a void pointer as a parameter, it's great, you can just send anything down there Eye-wink

Anyway the thing we want is to listen to in our game is the device broadcast messages. The following code sets that up. I added this to my window creation function since you need a window handle to the main window, declared as m_hWnd in the code below. The setup is actually much easier than you think by looking at the docs.


DEV_BROADCAST_DEVICEINTERFACE notificationFilter;
ZeroMemory(&notificationFilter, sizeof(notificationFilter));
 
notificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
notificationFilter.dbcc_size = sizeof(notificationFilter);
 
HDEVNOTIFY hDevNotify;
hDevNotify = RegisterDeviceNotification(m_hWnd, &notificationFilter,
   DEVICE_NOTIFY_WINDOW_HANDLE |
   DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
 
if(hDevNotify == NULL) {
   // do some error handling
}

By using the handy DEVICE_NOTIFY_ALL_INTERFACE_CLASSES flag we can skip most parameters in the notificationFilter parameter except type and size.

Also for this code to even compile you also need to have WINVER defined >= 0x0500 like


#define WINVER 0x0500

Now Windows will send you all messages when a game pad is attached or removed from the pc and you can take the appropriate action in your game code.

Hope you'll find this short article/tutorial handy! Feel free to comment or suggest improvements.

users avatar

May I ask you what language

May I ask you what language it is? Looks a bit like c++, but i can't tell since I don't use it *hinting that you maybe should tell in the tut* Smiling

______________________________________________
"The time you enjoy wasting isn't wasted time"

users avatar

Yepp it's C++ alright. Good

Yepp it's C++ alright. Good point Sticking out tongue

users avatar

Added some more color coding

Added some more color coding and clarified the m_hWnd parameter some more...

users avatar

All interfaces?

Using all interfaces will set up listening to hard disks and all kinds of other stuff.
It's not so hard to set this to just HID using a simple little constant array you set up.
Just set the notification filter's dbcc_classguid to this value:

static const GUID GuidDevInterfaceHID =
{0x745a17a0, 0x74d3, 0x11d0,
{ 0xb6, 0xfe, 0x00, 0xa0, 0xc9, 0x0f, 0x57, 0xda }};
notificationFilter.dbcc_classguid = GuidDevInterfaceHID;

There are two class GUIDs that both work for HIDs, this is just one of them (they both work exactly the same, not sure why there are two available).

users avatar

Neat! Thanks for the info

Neat!

Thanks for the info I'll make sure to check this out when I get back to coding after the summer Smiling

users avatar

Post new comment

Please solve the math problem above and type in the result. e.g. for 1+1, type 2.
The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <h1> <h2> <h3> <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • Textual smileys will be replaced with graphical ones.
  • Images can be added to this post.

More information about formatting options