mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
rawinput: fix hotplug for keyboard and mouse (#810)
## Link to GitHub Issue or related Pull Request, if one exists n/a ## Description of change Fix a long-standing issue of hotplug not working for keyboards and mice. The code only registered for HID notifications; we also need to do it for the keyboard GUID and mouse GUID. ## Testing Confirmed that keyboards and mice can be hot unplugged and plugged.
This commit is contained in:
@@ -4,6 +4,10 @@
|
||||
|
||||
#include <dbt.h>
|
||||
#include <devguid.h>
|
||||
#include <hidclass.h>
|
||||
#include <ntddkbd.h>
|
||||
#include <ntddmou.h>
|
||||
#include <objbase.h>
|
||||
|
||||
#include "misc/eamuse.h"
|
||||
#include "rawinput.h"
|
||||
@@ -12,31 +16,42 @@
|
||||
|
||||
namespace rawinput {
|
||||
|
||||
DEFINE_GUID(GUID_HID, 0x4D1E55B2L, 0xF16F, 0x11CF, 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30);
|
||||
static bool is_rawinput_interface(const GUID &guid) {
|
||||
return IsEqualGUID(guid, GUID_DEVINTERFACE_HID)
|
||||
|| IsEqualGUID(guid, GUID_DEVINTERFACE_KEYBOARD)
|
||||
|| IsEqualGUID(guid, GUID_DEVINTERFACE_MOUSE);
|
||||
}
|
||||
|
||||
HotplugManager::HotplugManager(RawInputManager *ri_mgr, HWND hWnd) : ri_mgr(ri_mgr) {
|
||||
auto register_notification = [hWnd](const GUID &guid, const char *name) -> HANDLE {
|
||||
DEV_BROADCAST_DEVICEINTERFACE settings {
|
||||
.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE),
|
||||
.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE,
|
||||
.dbcc_reserved = 0,
|
||||
.dbcc_classguid = guid,
|
||||
.dbcc_name = {0},
|
||||
};
|
||||
|
||||
// init settings
|
||||
DEV_BROADCAST_DEVICEINTERFACE settings_hid {
|
||||
.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE),
|
||||
.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE,
|
||||
.dbcc_reserved = 0,
|
||||
.dbcc_classguid = GUID_HID,
|
||||
.dbcc_name = {0},
|
||||
auto notification = RegisterDeviceNotification(hWnd, &settings, DEVICE_NOTIFY_WINDOW_HANDLE);
|
||||
if (notification == nullptr) {
|
||||
log_warning("hotplug", "failed to register {} notifications: {}", name, GetLastError());
|
||||
}
|
||||
return notification;
|
||||
};
|
||||
|
||||
// register notifications
|
||||
this->hotplug_hid = RegisterDeviceNotification(hWnd, &settings_hid, DEVICE_NOTIFY_WINDOW_HANDLE);
|
||||
if (this->hotplug_hid == nullptr) {
|
||||
log_warning("hotplug", "failed to register HID notifications: {}", GetLastError());
|
||||
}
|
||||
this->hotplug_hid = register_notification(GUID_DEVINTERFACE_HID, "HID");
|
||||
this->hotplug_keyboard = register_notification(GUID_DEVINTERFACE_KEYBOARD, "keyboard");
|
||||
this->hotplug_mouse = register_notification(GUID_DEVINTERFACE_MOUSE, "mouse");
|
||||
}
|
||||
|
||||
HotplugManager::~HotplugManager() {
|
||||
|
||||
// unregister notifications
|
||||
if (this->hotplug_hid != nullptr) {
|
||||
UnregisterDeviceNotification(this->hotplug_hid);
|
||||
for (auto notification : {this->hotplug_hid, this->hotplug_keyboard, this->hotplug_mouse}) {
|
||||
if (notification != nullptr) {
|
||||
UnregisterDeviceNotification(notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,11 +69,16 @@ namespace rawinput {
|
||||
switch (hdr->dbch_devicetype) {
|
||||
case DBT_DEVTYP_DEVICEINTERFACE: {
|
||||
auto dev = (const DEV_BROADCAST_DEVICEINTERFACE *) hdr;
|
||||
this->ri_mgr->midi_scan_start();
|
||||
|
||||
// check if class is not HID
|
||||
if (memcmp(&dev->dbcc_classguid, &GUID_HID, sizeof(GUID_HID)) != 0)
|
||||
// check if this is one of the registered RawInput interfaces
|
||||
if (!is_rawinput_interface(dev->dbcc_classguid)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// keyboard and mouse class events accompany the HID event, so scan MIDI only once
|
||||
if (IsEqualGUID(dev->dbcc_classguid, GUID_DEVINTERFACE_HID)) {
|
||||
this->ri_mgr->midi_scan_start();
|
||||
}
|
||||
|
||||
// hotplug
|
||||
std::string name(dev->dbcc_name);
|
||||
@@ -109,6 +129,9 @@ namespace rawinput {
|
||||
switch (hdr->dbch_devicetype) {
|
||||
case DBT_DEVTYP_DEVICEINTERFACE: {
|
||||
auto dev = (DEV_BROADCAST_DEVICEINTERFACE*) hdr;
|
||||
if (!is_rawinput_interface(dev->dbcc_classguid)) {
|
||||
break;
|
||||
}
|
||||
std::string name(dev->dbcc_name);
|
||||
|
||||
// destruct device
|
||||
|
||||
@@ -9,7 +9,9 @@ namespace rawinput {
|
||||
class HotplugManager {
|
||||
private:
|
||||
RawInputManager *ri_mgr;
|
||||
HANDLE hotplug_hid;
|
||||
HANDLE hotplug_hid = nullptr;
|
||||
HANDLE hotplug_keyboard = nullptr;
|
||||
HANDLE hotplug_mouse = nullptr;
|
||||
|
||||
public:
|
||||
HotplugManager(RawInputManager *ri_mgr, HWND hwnd);
|
||||
|
||||
@@ -246,7 +246,8 @@ void rawinput::RawInputManager::devices_scan_rawinput(const std::string &device_
|
||||
return;
|
||||
}
|
||||
|
||||
// iterate devices
|
||||
// hotplug gives us an interface path rather than a RawInput handle, so find its
|
||||
// matching entry; an empty path means this is a full device scan
|
||||
for (UINT device_cur_index = 0; device_cur_index < device_no; device_cur_index++) {
|
||||
auto device = &device_list.get()[device_cur_index];
|
||||
if (device_name.length() == 0) {
|
||||
|
||||
Reference in New Issue
Block a user