ControllerListener status?

Hey,
what’s going on with the ControllerListener interface.
I see it’s still an open issue on the issue tracker, and as far as I can see DirectInput doesn’t generate events upon connecting and disconnecting devices.
(There are exceptions that will be thrown if a controller is disconnected, but that’s about it).
But it seems like it’s pretty easy to register that a window is listening to USB HID devices being connected/disconnected in Windows.
There’s a pretty ugly HID GUID constant that has to go in there, but…

I haven’t had the time to look into the jInput native code, nor do I have much C++ or Windows programming experience, but I did find code for setting up a window as listening to USB devices being connected/disconnected:


DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
HDEVNOTIFY hDeviceNotify = NULL;

ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));

NotificationFilter.dbcc_size = sizeof(DEV_BROADCADT_DEVICEINTERFACE);
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
NotificationFilter.dbcc_classguid = { 0x4d1e55b2, 0xf16f, 0x11Cf, { 0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } };

hDeviceNotify = RegisterDeviceNotification(hWnd, &NotificationFilter
DEVICE_NOTIFY_WINDOW_HANDLE);
if (hDeviceNotify == NULL)
{
    // Handle the error...
}

This is a modified version of the code I found, as it used loops to register all kinds of USB devices, I just removed the loop and moved the guid directly into the notification filter instead of using an array of guids to pick from.
And the callback in the window:

LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uiMsg)
    {
        case WM_DEVICECHANGE:
        {
            PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR) lParam;
            switch (wParam)
            {
                case DBT_DEVICEARRIVAL:
                    // Handle a device being connected
                    break;
                case DBT_DEVICEREMOVECOMPLETE:
                    // Handle a device being removed
                    break;
            }
        }
        break;
        default:
            return DefWindowProc(hWnd, uiMsg, wParam, lParam);
            break;
    }
    return 0;
}

Of course, if it turns out the device is not a game device (I’m guessing this would have to be checked by enumerating devices in DirectInput and checking if there are any new devices on the list), DefWindowProc should probably be called.
I have a feeling this might be slow, though. shrug
The callback is probably called pretty quickly, and upon disconnection it should at least be easy to check the device specific GUID against a stored list of game device GUIDs, to quickly call the ControllerListener’s controllerRemoved method, but detecting connections seems like the hard part.
For that matter, disconnects could probably be detected quite easily using DirectInput’s InputLost- or UnpluggedExceptions.

Of course, I haven’t tried these things.
Maybe I should make a small test application and see how fast/slow this would be at detecting me connecting/disconnecting a gamepad.

Well,
I found out a couple of things, trying to put together a small program listening to HID devices:

  1. HID devices don’t report whether they were connected or disconnected, only a DBT_DEVNODES_CHANGED, meaning you don’t really know much except that something was either connected or disconnected. So checking DBT_DEVICEARRIVAL and DBT_DEVICEREMOVECOMPLETE is completely unnecessary.
  2. There are two different HID device class guids that both seem to work, the one I used above, and a second one: 0x745a17a074d311d0b6fe00a0c90f57da

Using DirectInput’s exceptions to detect removal should be easy enough, but you’d still have to re-enumerate devices upon every such call to the WndProc callback with the WM_DEVICECHANGE message if you want to be able to tell the user that a device has been added. shrug
Re-enumerating would also tell you that a device has been removed, but perhaps this could be ignored as an exception might come first?
If an XInput driver is added (someone posted one that would work with jInput I believe), creating ControllerListener events for XInput devices would be relatively easy, as they actually have events like that, but then you might end up with two events for devices being added if you do the low level check with WM_DEVICECHANGE.

Any thoughts?

I think the easiest way to detect controllers added/removed is to rescan the device list and compare the new to the old. I have looked in the past and figured that might be the most reliable way.

Endolf