From a0732c321661af4c2577bbf6ab9699025cf868bc Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Fri, 11 Mar 2022 04:12:44 +1100 Subject: osd/modules/input/input_rawinput.cpp: Allow re-plugging mouse/keyboard. --- src/osd/modules/input/input_common.h | 6 +- src/osd/modules/input/input_rawinput.cpp | 269 +++++++++++++++++++------------ src/osd/modules/input/input_windows.cpp | 22 +-- src/osd/modules/input/input_xinput.cpp | 12 +- src/osd/windows/window.cpp | 18 ++- src/osd/windows/winmain.h | 2 + 6 files changed, 203 insertions(+), 126 deletions(-) diff --git a/src/osd/modules/input/input_common.h b/src/osd/modules/input/input_common.h index 49c4e768dcf..45661fe957c 100644 --- a/src/osd/modules/input/input_common.h +++ b/src/osd/modules/input/input_common.h @@ -295,7 +295,8 @@ private: std::vector> m_list; public: - size_t size() const { return m_list.size(); } + auto size() const { return m_list.size(); } + auto empty() const { return m_list.empty(); } auto begin() { return m_list.begin(); } auto end() { return m_list.end(); } @@ -318,7 +319,8 @@ public: m_list.erase(std::remove_if(std::begin(m_list), std::end(m_list), device_matches), m_list.end()); } - void for_each_device(std::function action) + template + void for_each_device(T &&action) { for (auto &device: m_list) action(device.get()); diff --git a/src/osd/modules/input/input_rawinput.cpp b/src/osd/modules/input/input_rawinput.cpp index 248b7bb48ab..10b47a60e31 100644 --- a/src/osd/modules/input/input_rawinput.cpp +++ b/src/osd/modules/input/input_rawinput.cpp @@ -19,6 +19,7 @@ #include #include #include +#include // MAME headers #include "emu.h" @@ -35,12 +36,6 @@ namespace { -// Typedefs for dynamically loaded functions -typedef UINT (WINAPI *get_rawinput_device_list_ptr)(PRAWINPUTDEVICELIST, PUINT, UINT); -typedef UINT (WINAPI *get_rawinput_data_ptr)( HRAWINPUT, UINT, LPVOID, PUINT, UINT); -typedef UINT (WINAPI *get_rawinput_device_info_ptr)(HANDLE, UINT, LPVOID, PUINT); -typedef BOOL (WINAPI *register_rawinput_devices_ptr)(PCRAWINPUTDEVICE, UINT, UINT); - class safe_regkey { private: @@ -294,7 +289,7 @@ public: rawinput_keyboard_device(running_machine &machine, std::string &&name, std::string &&id, input_module &module) : rawinput_device(machine, std::move(name), std::move(id), DEVICE_CLASS_KEYBOARD, module), - keyboard({{0}}) + keyboard({ { 0 } }) { } @@ -326,7 +321,7 @@ class rawinput_mouse_device : public rawinput_device private: std::mutex m_device_lock; public: - mouse_state mouse; + mouse_state mouse; rawinput_mouse_device(running_machine &machine, std::string &&name, std::string &&id, input_module &module) : rawinput_device(machine, std::move(name), std::move(id), DEVICE_CLASS_MOUSE, module), @@ -442,12 +437,7 @@ public: class rawinput_module : public wininput_module { private: - osd::dynamic_module::ptr m_user32_dll; - get_rawinput_device_list_ptr get_rawinput_device_list = nullptr; - get_rawinput_data_ptr get_rawinput_data = nullptr; - get_rawinput_device_info_ptr get_rawinput_device_info = nullptr; - register_rawinput_devices_ptr register_rawinput_devices = nullptr; - std::mutex m_module_lock; + std::mutex m_module_lock; public: rawinput_module(const char *type, const char *name) : wininput_module(type, name) @@ -456,163 +446,234 @@ public: bool probe() override { - m_user32_dll = osd::dynamic_module::open({ "user32.dll" }); - - get_rawinput_device_list = m_user32_dll->bind("GetRawInputDeviceList"); - get_rawinput_data = m_user32_dll->bind("GetRawInputData"); - get_rawinput_device_info = m_user32_dll->bind("GetRawInputDeviceInfoW"); - register_rawinput_devices = m_user32_dll->bind("RegisterRawInputDevices"); - - return get_rawinput_device_list && get_rawinput_data && get_rawinput_device_info && register_rawinput_devices; + return true; } void input_init(running_machine &machine) override { - // get the number of devices, allocate a device list, and fetch it + // get initial number of devices UINT device_count = 0; - if ((*get_rawinput_device_list)(nullptr, &device_count, sizeof(RAWINPUTDEVICELIST)) != 0) + if (GetRawInputDeviceList(nullptr, &device_count, sizeof(RAWINPUTDEVICELIST)) != 0) + { + osd_printf_error("Error getting initial number of RawInput devices.\n"); return; - - if (device_count == 0) + } + if (!device_count) return; - auto rawinput_devices = std::make_unique(device_count); - if ((*get_rawinput_device_list)(rawinput_devices.get(), &device_count, sizeof(RAWINPUTDEVICELIST)) == UINT(-1)) + std::unique_ptr rawinput_devices; + UINT retrieved; + do + { + rawinput_devices.reset(new (std::nothrow) RAWINPUTDEVICELIST [device_count]); + if (!rawinput_devices) + { + osd_printf_error("Error allocating buffer for RawInput device list.\n"); + return; + } + retrieved = GetRawInputDeviceList(rawinput_devices.get(), &device_count, sizeof(RAWINPUTDEVICELIST)); + } + while ((UINT(-1) == retrieved) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)); + if (UINT(-1) == retrieved) + { + osd_printf_error("Error listing RawInput devices.\n"); return; + } // iterate backwards through devices; new devices are added at the head - for (int devnum = device_count - 1; devnum >= 0; devnum--) - { - RAWINPUTDEVICELIST *device = &rawinput_devices[devnum]; - add_rawinput_device(machine, device); - } + for (int devnum = retrieved - 1; devnum >= 0; devnum--) + add_rawinput_device(machine, rawinput_devices[devnum]); // don't enable global inputs when debugging if (!machine.options().debug()) - { m_global_inputs_enabled = downcast(machine.options()).global_inputs(); - } // If we added no devices, no need to register for notifications - if (devicelist()->size() == 0) + if (devicelist()->empty()) return; // finally, register to receive raw input WM_INPUT messages if we found devices RAWINPUTDEVICE registration; registration.usUsagePage = usagepage(); registration.usUsage = usage(); - registration.dwFlags = m_global_inputs_enabled ? 0x00000100 : 0; + registration.dwFlags = RIDEV_DEVNOTIFY; + if (m_global_inputs_enabled) + registration.dwFlags |= RIDEV_INPUTSINK; registration.hwndTarget = std::static_pointer_cast(osd_common_t::s_window_list.front())->platform_window(); // register the device - (*register_rawinput_devices)(®istration, 1, sizeof(registration)); + RegisterRawInputDevices(®istration, 1, sizeof(registration)); } protected: - virtual void add_rawinput_device(running_machine &machine, RAWINPUTDEVICELIST *device) = 0; + virtual void add_rawinput_device(running_machine &machine, RAWINPUTDEVICELIST const &device) = 0; virtual USHORT usagepage() = 0; virtual USHORT usage() = 0; int init_internal() override { - if (!get_rawinput_device_list || !get_rawinput_data || - !get_rawinput_device_info || !register_rawinput_devices ) - { - return 1; - } - - osd_printf_verbose("RawInput: APIs detected\n"); return 0; } template - TDevice *create_rawinput_device(running_machine &machine, PRAWINPUTDEVICELIST rawinputdevice) + TDevice *create_rawinput_device(running_machine &machine, RAWINPUTDEVICELIST const &rawinputdevice) { // determine the length of the device name, allocate it, and fetch it if not nameless UINT name_length = 0; - if ((*get_rawinput_device_info)(rawinputdevice->hDevice, RIDI_DEVICENAME, nullptr, &name_length) != 0) + if (GetRawInputDeviceInfoW(rawinputdevice.hDevice, RIDI_DEVICENAME, nullptr, &name_length) != 0) return nullptr; std::unique_ptr tname = std::make_unique(name_length + 1); - if (name_length > 1 && (*get_rawinput_device_info)(rawinputdevice->hDevice, RIDI_DEVICENAME, tname.get(), &name_length) == UINT(-1)) + if (name_length > 1 && GetRawInputDeviceInfoW(rawinputdevice.hDevice, RIDI_DEVICENAME, tname.get(), &name_length) == UINT(-1)) return nullptr; // if this is an RDP name, skip it - if (_tcsstr(tname.get(), TEXT("Root#RDP_")) != nullptr) + if (wcsstr(tname.get(), L"Root#RDP_") != nullptr) return nullptr; // improve the name and then allocate a device - std::wstring name = rawinput_device_improve_name(tname.get()); - - // convert name to utf8 - std::string utf8_name = osd::text::from_wstring(name); + std::string utf8_name = osd::text::from_wstring(rawinput_device_improve_name(tname.get())); - // set device id to raw input name + // set device ID to raw input name std::string utf8_id = osd::text::from_wstring(tname.get()); + tname.reset(); + TDevice &devinfo = devicelist()->create_device(machine, std::move(utf8_name), std::move(utf8_id), *this); // Add the handle - devinfo.set_handle(rawinputdevice->hDevice); + devinfo.set_handle(rawinputdevice.hDevice); return &devinfo; } bool handle_input_event(input_event eventid, void *eventdata) override { - // Only handle raw input data - if (!input_enabled() || eventid != INPUT_EVENT_RAWINPUT) - return false; - - HRAWINPUT rawinputdevice = *static_cast(eventdata); - - BYTE small_buffer[4096]; - std::unique_ptr larger_buffer; - LPBYTE data = small_buffer; - UINT size; + switch (eventid) + { + // handle raw input data + case INPUT_EVENT_RAWINPUT: + { + // ignore if not enabled + if (!input_enabled()) + return false; + + HRAWINPUT rawinputdevice = *static_cast(eventdata); + + BYTE small_buffer[4096]; + std::unique_ptr larger_buffer; + LPBYTE data = small_buffer; + UINT size; + + // determine the size of data buffer we need + if (GetRawInputData(rawinputdevice, RID_INPUT, nullptr, &size, sizeof(RAWINPUTHEADER)) != 0) + return false; + + // if necessary, allocate a temporary buffer and fetch the data + if (size > sizeof(small_buffer)) + { + larger_buffer.reset(new (std::nothrow) BYTE [size]); + data = larger_buffer.get(); + if (!data) + return false; + } + + // fetch the data and process the appropriate message types + UINT result = GetRawInputData(rawinputdevice, RID_INPUT, data, &size, sizeof(RAWINPUTHEADER)); + if (UINT(-1) == result) + { + return false; + } + else if (result) + { + std::lock_guard scope_lock(m_module_lock); + + auto *input = reinterpret_cast(data); + if (!input->header.hDevice) + return false; + + // find the device in the list and update + auto target_device = std::find_if( + devicelist()->begin(), + devicelist()->end(), + [input] (auto const &device) + { + auto devinfo = dynamic_cast(device.get()); + return devinfo && (input->header.hDevice == devinfo->device_handle()); + }); + if (devicelist()->end() == target_device) + return false; + + static_cast(target_device->get())->queue_events(input, 1); + return true; + } + } + break; - // ignore if not enabled - if (!input_enabled()) - return false; + case INPUT_EVENT_ARRIVAL: + { + HRAWINPUT rawinputdevice = *static_cast(eventdata); + + // determine the length of the device name, allocate it, and fetch it if not nameless + UINT name_length = 0; + if (GetRawInputDeviceInfoW(rawinputdevice, RIDI_DEVICENAME, nullptr, &name_length) != 0) + return false; + + std::unique_ptr tname = std::make_unique(name_length + 1); + if (name_length > 1 && GetRawInputDeviceInfoW(rawinputdevice, RIDI_DEVICENAME, tname.get(), &name_length) == UINT(-1)) + return false; + std::string utf8_id = osd::text::from_wstring(tname.get()); + tname.reset(); + + std::lock_guard scope_lock(m_module_lock); + + // find the device in the list and update + auto target_device = std::find_if( + devicelist()->begin(), + devicelist()->end(), + [&utf8_id] (auto const &device) + { + auto devinfo = dynamic_cast(device.get()); + return devinfo && !devinfo->device_handle() && (devinfo->id() == utf8_id); + }); + if (devicelist()->end() == target_device) + return false; - // determine the size of databuffer we need - if ((*get_rawinput_data)(rawinputdevice, RID_INPUT, nullptr, &size, sizeof(RAWINPUTHEADER)) != 0) - return false; + static_cast(target_device->get())->set_handle(rawinputdevice); + return true; + } + break; - // if necessary, allocate a temporary buffer and fetch the data - if (size > sizeof(small_buffer)) - { - larger_buffer = std::make_unique(size); - data = larger_buffer.get(); - if (data == nullptr) - return false; - } + case INPUT_EVENT_REMOVAL: + { + HRAWINPUT rawinputdevice = *static_cast(eventdata); - // fetch the data and process the appropriate message types - bool result = (*get_rawinput_data)(static_cast(rawinputdevice), RID_INPUT, data, &size, sizeof(RAWINPUTHEADER)); - if (result) - { - std::lock_guard scope_lock(m_module_lock); + std::lock_guard scope_lock(m_module_lock); - auto *input = reinterpret_cast(data); + // find the device in the list and update + auto target_device = std::find_if( + devicelist()->begin(), + devicelist()->end(), + [rawinputdevice] (auto const &device) + { + auto devinfo = dynamic_cast(device.get()); + return devinfo && (rawinputdevice == devinfo->device_handle()); + }); - // find the device in the list and update - auto target_device = std::find_if( - devicelist()->begin(), - devicelist()->end(), - [input] (auto const &device) - { - auto devinfo = dynamic_cast(device.get()); - return devinfo && (input->header.hDevice == devinfo->device_handle()); - }); + if (devicelist()->end() == target_device) + return false; - if (target_device != devicelist()->end()) - { - static_cast((*target_device).get())->queue_events(input, 1); + (*target_device)->reset(); + static_cast(target_device->get())->set_handle(nullptr); return true; } + break; + + default: + break; } + // must have been unhandled return false; } }; @@ -633,10 +694,10 @@ protected: USHORT usagepage() override { return 1; } USHORT usage() override { return 6; } - void add_rawinput_device(running_machine &machine, RAWINPUTDEVICELIST *device) override + void add_rawinput_device(running_machine &machine, RAWINPUTDEVICELIST const &device) override { // make sure this is a keyboard - if (device->dwType != RIM_TYPEKEYBOARD) + if (device.dwType != RIM_TYPEKEYBOARD) return; // allocate and link in a new device @@ -679,10 +740,10 @@ protected: USHORT usagepage() override { return 1; } USHORT usage() override { return 2; } - void add_rawinput_device(running_machine &machine, RAWINPUTDEVICELIST *device) override + void add_rawinput_device(running_machine &machine, RAWINPUTDEVICELIST const &device) override { // make sure this is a mouse - if (device->dwType != RIM_TYPEMOUSE) + if (device.dwType != RIM_TYPEMOUSE) return; // allocate and link in a new device @@ -728,11 +789,11 @@ protected: USHORT usagepage() override { return 1; } USHORT usage() override { return 2; } - void add_rawinput_device(running_machine &machine, RAWINPUTDEVICELIST *device) override + void add_rawinput_device(running_machine &machine, RAWINPUTDEVICELIST const &device) override { // make sure this is a mouse - if (device->dwType != RIM_TYPEMOUSE) + if (device.dwType != RIM_TYPEMOUSE) return; // allocate and link in a new device diff --git a/src/osd/modules/input/input_windows.cpp b/src/osd/modules/input/input_windows.cpp index bbe109eb53a..4415e71f3a4 100644 --- a/src/osd/modules/input/input_windows.cpp +++ b/src/osd/modules/input/input_windows.cpp @@ -27,39 +27,39 @@ bool windows_osd_interface::should_hide_mouse() const { bool hidemouse = false; - wininput_module* mod; + wininput_module *mod; - mod = dynamic_cast(m_keyboard_input); + mod = dynamic_cast(m_keyboard_input); if (mod) hidemouse |= mod->should_hide_mouse(); - mod = dynamic_cast(m_mouse_input); + mod = dynamic_cast(m_mouse_input); if (mod) hidemouse |= mod->should_hide_mouse(); - mod = dynamic_cast(m_lightgun_input); + mod = dynamic_cast(m_lightgun_input); if (mod) hidemouse |= mod->should_hide_mouse(); - mod = dynamic_cast(m_joystick_input); + mod = dynamic_cast(m_joystick_input); if (mod) hidemouse |= mod->should_hide_mouse(); return hidemouse; } -bool windows_osd_interface::handle_input_event(input_event eventid, void* eventdata) const +bool windows_osd_interface::handle_input_event(input_event eventid, void *eventdata) const { bool handled = false; - wininput_module* mod; + wininput_module *mod; - mod = dynamic_cast(m_keyboard_input); + mod = dynamic_cast(m_keyboard_input); if (mod) handled |= mod->handle_input_event(eventid, eventdata); - mod = dynamic_cast(m_mouse_input); + mod = dynamic_cast(m_mouse_input); if (mod) handled |= mod->handle_input_event(eventid, eventdata); - mod = dynamic_cast(m_lightgun_input); + mod = dynamic_cast(m_lightgun_input); if (mod) handled |= mod->handle_input_event(eventid, eventdata); - mod = dynamic_cast(m_joystick_input); + mod = dynamic_cast(m_joystick_input); if (mod) handled |= mod->handle_input_event(eventid, eventdata); return handled; diff --git a/src/osd/modules/input/input_xinput.cpp b/src/osd/modules/input/input_xinput.cpp index dd4c418aacd..8c75240abf7 100644 --- a/src/osd/modules/input/input_xinput.cpp +++ b/src/osd/modules/input/input_xinput.cpp @@ -201,12 +201,12 @@ xinput_joystick_device * xinput_api_helper::create_xinput_device(running_machine // xinput_joystick_device //============================================================ -xinput_joystick_device::xinput_joystick_device(running_machine &machine, std::string &&name, std::string &&id, input_module &module, std::shared_ptr helper) - : device_info(machine, std::string(name), std::string(id), DEVICE_CLASS_JOYSTICK, module), - gamepad({{0}}), - xinput_state({0}), - m_xinput_helper(helper), - m_configured(false) +xinput_joystick_device::xinput_joystick_device(running_machine &machine, std::string &&name, std::string &&id, input_module &module, std::shared_ptr helper) : + device_info(machine, std::string(name), std::string(id), DEVICE_CLASS_JOYSTICK, module), + gamepad({ { 0 } }), + xinput_state({ 0 }), + m_xinput_helper(helper), + m_configured(false) { } diff --git a/src/osd/windows/window.cpp b/src/osd/windows/window.cpp index 6627be003a8..bcf89fc0267 100644 --- a/src/osd/windows/window.cpp +++ b/src/osd/windows/window.cpp @@ -8,9 +8,6 @@ #define LOG_TEMP_PAUSE 0 -// Needed for RAW Input -#define WM_INPUT 0x00FF - // standard C headers #include @@ -1112,6 +1109,21 @@ LRESULT CALLBACK win_window_info::video_window_proc(HWND wnd, UINT message, WPAR return DefWindowProc(wnd, message, wparam, lparam); break; + // input device change: handle RawInput device connection/disconnection + case WM_INPUT_DEVICE_CHANGE: + switch (wparam) + { + case GIDC_ARRIVAL: + downcast(window->machine().osd()).handle_input_event(INPUT_EVENT_ARRIVAL, &lparam); + break; + case GIDC_REMOVAL: + downcast(window->machine().osd()).handle_input_event(INPUT_EVENT_REMOVAL, &lparam); + break; + default: + return DefWindowProc(wnd, message, wparam, lparam); + } + break; + // input: handle the raw input case WM_INPUT: downcast(window->machine().osd()).handle_input_event(INPUT_EVENT_RAWINPUT, &lparam); diff --git a/src/osd/windows/winmain.h b/src/osd/windows/winmain.h index ef1cd1aff4f..7c1689cff9f 100644 --- a/src/osd/windows/winmain.h +++ b/src/osd/windows/winmain.h @@ -243,6 +243,8 @@ enum input_event INPUT_EVENT_KEYDOWN, INPUT_EVENT_KEYUP, INPUT_EVENT_RAWINPUT, + INPUT_EVENT_ARRIVAL, + INPUT_EVENT_REMOVAL, INPUT_EVENT_MOUSE_BUTTON }; -- cgit v1.2.3