def find_all_hid_devices():
    "Finds all HID devices connected to the system"
    #
    # From DDK documentation (finding and Opening HID collection):
    # After a user-mode application is loaded, it does the following sequence
    # of operations:
    #
    #   * Calls HidD_GetHidGuid to obtain the system-defined GUID for HIDClass
    #     devices.
    #
    #   * Calls SetupDiGetClassDevs to obtain a handle to an opaque device
    #     information set that describes the device interfaces supported by all
    #     the HID collections currently installed in the system. The
    #     application should specify DIGCF_PRESENT and DIGCF_INTERFACEDEVICE
    #     in the Flags parameter passed to SetupDiGetClassDevs.
    #
    #   * Calls SetupDiEnumDeviceInterfaces repeatedly to retrieve all the
    #     available interface information.
    #
    #   * Calls SetupDiGetDeviceInterfaceDetail to format interface information
    #     for each collection as a SP_INTERFACE_DEVICE_DETAIL_DATA structure.
    #     The device_path member of this structure contains the user-mode name
    #     that the application uses with the Win32 function CreateFile to
    #     obtain a file handle to a HID collection.
    #
    # get HID device class guid
    guid = winapi.GetHidGuid()

    # retrieve all the available interface information.
    results = []
    required_size = DWORD()

    info_data         = winapi.SP_DEVINFO_DATA()
    info_data.cb_size = sizeof(winapi.SP_DEVINFO_DATA)

    with winapi.DeviceInterfaceSetInfo(guid) as h_info:
        for interface_data in winapi.enum_device_interfaces(h_info, guid):
            device_path = winapi.get_device_path(h_info,
                    interface_data,
                    byref(info_data))

            parent_device = c_ulong()

            #get parent instance id (so we can discriminate on port)
            if setup_api.CM_Get_Parent(byref(parent_device),
                    info_data.dev_inst, 0) != 0: #CR_SUCCESS = 0
                parent_device.value = 0 #null

            #get unique instance id string
            required_size.value = 0
            winapi.SetupDiGetDeviceInstanceId(h_info, byref(info_data),
                    None, 0,
                    byref(required_size) )

            device_instance_id = create_unicode_buffer(required_size.value)
            if required_size.value > 0:
                winapi.SetupDiGetDeviceInstanceId(h_info, byref(info_data),
                        device_instance_id, required_size,
                        byref(required_size) )

                hid_device = HidDevice(device_path,
                        parent_device.value, device_instance_id.value )
            else:
                hid_device = HidDevice(device_path, parent_device.value )

            # add device to results, if not protected
            if hid_device.vendor_id:
                results.append(hid_device)
    return results
Finds all HID devices connected to the system