spicetools/rawinput/hotplug.cpp

133 lines
4.8 KiB
C++
Raw Normal View History

2024-08-28 15:10:34 +00:00
#include <initguid.h>
#include "hotplug.h"
#include <dbt.h>
#include <devguid.h>
#include "misc/eamuse.h"
#include "rawinput.h"
#include "util/fileutils.h"
#include "util/logging.h"
namespace rawinput {
DEFINE_GUID(GUID_HID, 0x4D1E55B2L, 0xF16F, 0x11CF, 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30);
HotplugManager::HotplugManager(RawInputManager *ri_mgr, HWND hWnd) : ri_mgr(ri_mgr) {
// 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},
};
// 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());
}
}
HotplugManager::~HotplugManager() {
// unregister notifications
if (this->hotplug_hid != nullptr) {
UnregisterDeviceNotification(this->hotplug_hid);
}
}
LRESULT CALLBACK HotplugManager::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
// check for device change
if (msg == WM_DEVICECHANGE) {
// check type
switch (wParam) {
case DBT_DEVICEARRIVAL: {
// check arrived device type
auto hdr = (DEV_BROADCAST_HDR*) lParam;
switch (hdr->dbch_devicetype) {
case DBT_DEVTYP_DEVICEINTERFACE: {
auto dev = (const DEV_BROADCAST_DEVICEINTERFACE *) hdr;
this->ri_mgr->devices_scan_midi();
// check if class is not HID
if (memcmp(&dev->dbcc_classguid, &GUID_HID, sizeof(GUID_HID)) != 0)
break;
// hotplug
std::string name(dev->dbcc_name);
this->ri_mgr->devices_scan_rawinput(name);
this->ri_mgr->devices_register();
break;
}
case DBT_DEVTYP_VOLUME: {
auto dev = (const DEV_BROADCAST_VOLUME *) hdr;
auto unitmask = dev->dbcv_unitmask;
// check drive
unsigned long bit;
while (_BitScanForward(&bit, unitmask)) {
// remove drive from unitmask so it is not scanned again
unitmask &= ~(1 << bit);
// convert bit to drive letter char
char drive = 'A' + bit;
log_info("hotplug", "detected volume arrival: {}", drive);
#ifndef SPICETOOLS_SPICECFG_STANDALONE
// auto insert cards
for (int player = 0; player <= 1; player++) {
std::string path = to_string(drive) + ":\\card" + to_string(player) + ".txt";
if (fileutils::file_exists(path)) {
uint8_t card_data[8];
if (eamuse_get_card_from_file(path, card_data, player)) {
eamuse_card_insert(player, card_data);
}
}
}
#endif
}
break;
}
}
// success
return TRUE;
}
case DBT_DEVICEREMOVECOMPLETE: {
// check arrived device type
auto hdr = (DEV_BROADCAST_HDR*) lParam;
switch (hdr->dbch_devicetype) {
case DBT_DEVTYP_DEVICEINTERFACE: {
auto dev = (DEV_BROADCAST_DEVICEINTERFACE*) hdr;
std::string name(dev->dbcc_name);
// destruct device
this->ri_mgr->devices_remove(name);
}
}
// success
return TRUE;
}
case 7: { // windows 10 reports this for MIDI?
this->ri_mgr->devices_scan_midi();
break;
}
}
}
// default
return DefWindowProc(hwnd, msg, wParam, lParam);
}
}