diff options
Diffstat (limited to 'src/osd/modules/input/input_rawinput.cpp')
-rw-r--r-- | src/osd/modules/input/input_rawinput.cpp | 1028 |
1 files changed, 607 insertions, 421 deletions
diff --git a/src/osd/modules/input/input_rawinput.cpp b/src/osd/modules/input/input_rawinput.cpp index 9243ec4a0f4..5b6813dcd59 100644 --- a/src/osd/modules/input/input_rawinput.cpp +++ b/src/osd/modules/input/input_rawinput.cpp @@ -6,41 +6,39 @@ // //============================================================ -#include "input_module.h" #include "modules/osdmodule.h" #if defined(OSD_WINDOWS) -// standard windows headers -#include <windows.h> -#include <tchar.h> -#undef interface +#include "input_windows.h" -#include <mutex> -#include <functional> -#include <algorithm> +#include "input_wincommon.h" -// MAME headers -#include "emu.h" -#include "strconv.h" - -// MAMEOS headers -#include "modules/lib/osdlib.h" #include "winmain.h" #include "window.h" -#include "input_common.h" -#include "input_windows.h" +#include "modules/lib/osdlib.h" +#include "strconv.h" -//============================================================ -// MACROS -//============================================================ +// MAME headers +#include "inpttype.h" + +#include <algorithm> +#include <cassert> +#include <chrono> +#include <functional> +#include <mutex> +#include <new> +#include <utility> + +// standard windows headers +#include <windows.h> +#include <tchar.h> -// 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); + +namespace osd { + +namespace { class safe_regkey { @@ -48,17 +46,24 @@ private: HKEY m_key; public: - safe_regkey() - : m_key(nullptr) - { - } + safe_regkey() : m_key(nullptr) { } + safe_regkey(safe_regkey const &) = delete; + safe_regkey(safe_regkey &&key) : m_key(key.m_key) { key.m_key = nullptr; } + explicit safe_regkey(HKEY key) : m_key(key) { } - explicit safe_regkey(HKEY key) - : m_key(key) + ~safe_regkey() { close(); } + + safe_regkey &operator=(safe_regkey const &) = delete; + + safe_regkey &operator=(safe_regkey &&key) { + close(); + m_key = key.m_key; + key.m_key = nullptr; + return *this; } - bool valid() const { return m_key != nullptr; } + explicit operator bool() const { return m_key != nullptr; } void close() { @@ -69,70 +74,68 @@ public: } } - ~safe_regkey() - { - close(); - } - operator HKEY() const { return m_key; } -}; -//============================================================ -// reg_open_key -//============================================================ - -static safe_regkey reg_open_key(HKEY basekey, const std::wstring &subkey) -{ - HKEY key; - if (RegOpenKeyEx(basekey, subkey.c_str(), 0, KEY_READ, &key) == ERROR_SUCCESS) - return safe_regkey(key); + safe_regkey open(std::wstring const &subkey) const { return open(m_key, subkey); } - return safe_regkey(); + std::wstring enum_key(int index) const + { + WCHAR keyname[256]; + DWORD namelen = std::size(keyname); + if (RegEnumKeyEx(m_key, index, keyname, &namelen, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS) + return std::wstring(keyname, namelen); + else + return std::wstring(); + } -} + std::wstring query_string(WCHAR const *path) const + { + // first query to get the length + DWORD datalen; + if (RegQueryValueExW(m_key, path, nullptr, nullptr, nullptr, &datalen) != ERROR_SUCCESS) + return std::wstring(); -//============================================================ -// reg_enum_key -//============================================================ + // allocate a buffer + auto buffer = std::make_unique<WCHAR []>((datalen + (sizeof(WCHAR) * 2) - 1) / sizeof(WCHAR)); -static std::wstring reg_enum_key(HKEY key, int index) -{ - WCHAR keyname[MAX_PATH]; - DWORD namelen; - if (RegEnumKeyEx(key, index, keyname, &namelen, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS) - return std::wstring(keyname, namelen); + // now get the actual data + if (RegQueryValueExW(m_key, path, nullptr, nullptr, reinterpret_cast<LPBYTE>(buffer.get()), &datalen) != ERROR_SUCCESS) + return std::wstring(); - return std::wstring(); -} - -//============================================================ -// reg_query_string -//============================================================ - -static std::wstring reg_query_string(HKEY key, const TCHAR *path) -{ - DWORD datalen; - LONG result; + buffer[datalen / sizeof(WCHAR)] = 0; + return std::wstring(buffer.get()); + } - // first query to get the length - result = RegQueryValueEx(key, path, nullptr, nullptr, nullptr, &datalen); - if (result != ERROR_SUCCESS) - return std::wstring(); + template <typename T> void foreach_subkey(T &&action) const + { + std::wstring name; + for (int i = 0; ; i++) + { + name = enum_key(i); + if (name.empty()) + break; - // allocate a buffer - auto buffer = std::make_unique<TCHAR[]>(datalen + sizeof(TCHAR)); - buffer[datalen / sizeof(TCHAR)] = 0; + safe_regkey const subkey = open(name); + if (!subkey) + break; - // now get the actual data - result = RegQueryValueEx(key, path, nullptr, nullptr, reinterpret_cast<LPBYTE>(buffer.get()), &datalen); - if (result == ERROR_SUCCESS) - return std::wstring(buffer.get()); + bool const shouldcontinue = action(subkey); + if (!shouldcontinue) + break; + } + } - // otherwise return an empty string - return std::wstring(); -} + static safe_regkey open(HKEY basekey, std::wstring const &subkey) + { + HKEY key(nullptr); + if (RegOpenKeyEx(basekey, subkey.c_str(), 0, KEY_READ, &key) == ERROR_SUCCESS) + return safe_regkey(key); + else + return safe_regkey(); + } +}; -static std::wstring trim_prefix(const std::wstring &devicename) +std::wstring trim_prefix(const std::wstring &devicename) { // remove anything prior to the final semicolon auto semicolon_index = devicename.find_last_of(';'); @@ -142,22 +145,22 @@ static std::wstring trim_prefix(const std::wstring &devicename) return devicename; } -static std::wstring compute_device_regpath(const std::wstring &name) +std::wstring compute_device_regpath(const std::wstring &name) { static const std::wstring basepath(L"SYSTEM\\CurrentControlSet\\Enum\\"); // allocate a temporary string and concatenate the base path plus the name - auto regpath_buffer = std::make_unique<TCHAR[]>(basepath.length() + 1 + name.length()); + auto regpath_buffer = std::make_unique<WCHAR []>(basepath.length() + 1 + name.length()); wcscpy(regpath_buffer.get(), basepath.c_str()); - WCHAR * chdst = regpath_buffer.get() + basepath.length(); + WCHAR *chdst = regpath_buffer.get() + basepath.length(); // convert all # to \ in the name for (int i = 4; i < name.length(); i++) - *chdst++ = (name[i] == '#') ? '\\' : name[i]; + *chdst++ = (name[i] == '#') ? L'\\' : name[i]; *chdst = 0; // remove the final chunk - chdst = wcsrchr(regpath_buffer.get(), '\\'); + chdst = wcsrchr(regpath_buffer.get(), L'\\'); if (chdst == nullptr) return std::wstring(); @@ -166,15 +169,15 @@ static std::wstring compute_device_regpath(const std::wstring &name) return std::wstring(regpath_buffer.get()); } -static std::wstring improve_name_from_base_path(const std::wstring ®path, bool *hid) +std::wstring improve_name_from_base_path(const std::wstring ®path, bool *hid) { // now try to open the registry key - auto device_key = reg_open_key(HKEY_LOCAL_MACHINE, regpath); - if (!device_key.valid()) + auto device_key = safe_regkey::open(HKEY_LOCAL_MACHINE, regpath); + if (!device_key) return std::wstring(); // fetch the device description; if it exists, we are finished - auto regstring = reg_query_string(device_key, L"DeviceDesc"); + auto regstring = device_key.query_string(L"DeviceDesc"); if (!regstring.empty()) return trim_prefix(regstring); @@ -183,25 +186,7 @@ static std::wstring improve_name_from_base_path(const std::wstring ®path, boo return std::wstring(); } -static void foreach_subkey(HKEY key, std::function<bool(HKEY)> action) -{ - for (int i = 0; ; i++) - { - std::wstring name = reg_enum_key(key, i); - if (name.empty()) - break; - - safe_regkey subkey = reg_open_key(key, name); - if (!subkey.valid()) - break; - - bool shouldcontinue = action(subkey); - if (!shouldcontinue) - break; - } -} - -static std::wstring improve_name_from_usb_path(const std::wstring ®path) +std::wstring improve_name_from_usb_path(const std::wstring ®path) { static const std::wstring usbbasepath(L"SYSTEM\\CurrentControlSet\\Enum\\USB"); @@ -213,40 +198,43 @@ static std::wstring improve_name_from_usb_path(const std::wstring ®path) std::wstring parentid = regpath.substr(last_slash_index + 1); // open the USB key - auto usb_key = reg_open_key(HKEY_LOCAL_MACHINE, usbbasepath); - if (!usb_key.valid()) + auto usb_key = safe_regkey::open(HKEY_LOCAL_MACHINE, usbbasepath); + if (!usb_key) return std::wstring(); std::wstring regstring; - foreach_subkey(usb_key, [®string, &parentid](HKEY subkey) - { - foreach_subkey(subkey, [®string, &parentid](HKEY endkey) - { - std::wstring endparentid = reg_query_string(endkey, L"ParentIdPrefix"); + usb_key.foreach_subkey( + [®string, &parentid] (safe_regkey const &subkey) + { + subkey.foreach_subkey( + [®string, &parentid] (safe_regkey const &endkey) + { + std::wstring endparentid = endkey.query_string(L"ParentIdPrefix"); - // This key doesn't have a ParentIdPrefix - if (endparentid.empty()) - return true; + // This key doesn't have a ParentIdPrefix + if (endparentid.empty()) + return true; - // do we have a match? - if (parentid.find(endparentid) == 0) - regstring = reg_query_string(endkey, L"DeviceDesc"); + // do we have a match? + if (parentid.find(endparentid) == 0) + regstring = endkey.query_string(L"DeviceDesc"); - return regstring.empty(); - }); + return regstring.empty(); + }); - return regstring.empty(); - }); + return regstring.empty(); + }); return trim_prefix(regstring); } + //============================================================ // rawinput_device_improve_name //============================================================ -static std::wstring rawinput_device_improve_name(const std::wstring &name) +std::wstring rawinput_device_improve_name(const std::wstring &name) { // The RAW name received is formatted as: // \??\type-id#hardware-id#instance-id#{DeviceClasses-id} @@ -282,20 +270,36 @@ static std::wstring rawinput_device_improve_name(const std::wstring &name) class rawinput_device : public event_based_device<RAWINPUT> { -private: - HANDLE m_handle; - public: - rawinput_device(running_machine& machine, const char *name, const char *id, input_device_class deviceclass, input_module& module) - : event_based_device(machine, name, id, deviceclass, module), - m_handle(nullptr) + rawinput_device(std::string &&name, std::string &&id, input_module &module, HANDLE handle) : + event_based_device(std::move(name), std::move(id), module), + m_handle(handle) { } HANDLE device_handle() const { return m_handle; } - void set_handle(HANDLE handle) { m_handle = handle; } + + bool reconnect_candidate(std::string_view i) const { return !m_handle && (id() == i); } + + void detach_device() + { + assert(m_handle); + m_handle = nullptr; + osd_printf_verbose("RawInput: %s [ID %s] disconnected\n", name(), id()); + } + + void attach_device(HANDLE handle) + { + assert(!m_handle); + m_handle = handle; + osd_printf_verbose("RawInput: %s [ID %s] reconnected\n", name(), id()); + } + +private: + HANDLE m_handle; }; + //============================================================ // rawinput_keyboard_device //============================================================ @@ -303,490 +307,672 @@ public: class rawinput_keyboard_device : public rawinput_device { public: - keyboard_state keyboard; + rawinput_keyboard_device(std::string &&name, std::string &&id, input_module &module, HANDLE handle) : + rawinput_device(std::move(name), std::move(id), module, handle), + m_pause_pressed(std::chrono::steady_clock::time_point::min()), + m_e1(0xffff), + m_keyboard({ { 0 } }) + { + } - rawinput_keyboard_device(running_machine& machine, const char *name, const char *id, input_module& module) - : rawinput_device(machine, name, id, DEVICE_CLASS_KEYBOARD, module), - keyboard({{0}}) + virtual void reset() override { + rawinput_device::reset(); + m_pause_pressed = std::chrono::steady_clock::time_point::min(); + memset(&m_keyboard, 0, sizeof(m_keyboard)); + m_e1 = 0xffff; } - void reset() override + virtual void poll(bool relative_reset) override { - memset(&keyboard, 0, sizeof(keyboard)); + rawinput_device::poll(relative_reset); + if (m_keyboard.state[0x80 | 0x45] && (std::chrono::steady_clock::now() > (m_pause_pressed + std::chrono::milliseconds(30)))) + m_keyboard.state[0x80 | 0x45] = 0x00; } - void process_event(RAWINPUT &rawinput) override + virtual void process_event(RAWINPUT const &rawinput) override { // determine the full DIK-compatible scancode - uint8_t scancode = (rawinput.data.keyboard.MakeCode & 0x7f) | ((rawinput.data.keyboard.Flags & RI_KEY_E0) ? 0x80 : 0x00); + uint8_t scancode; - // scancode 0xaa is a special shift code we need to ignore - if (scancode == 0xaa) + // the only thing that uses this is Pause + if (rawinput.data.keyboard.Flags & RI_KEY_E1) + { + m_e1 = rawinput.data.keyboard.MakeCode; return; + } + else if (0xffff != m_e1) + { + auto const e1 = std::exchange(m_e1, 0xffff); + if (!(rawinput.data.keyboard.Flags & RI_KEY_E0)) + { + if (((e1 & ~USHORT(0x80)) == 0x1d) && ((rawinput.data.keyboard.MakeCode & ~USHORT(0x80)) == 0x45)) + { + if (rawinput.data.keyboard.Flags & RI_KEY_BREAK) + return; // RawInput generates a fake break immediately after the make - ignore it + + m_pause_pressed = std::chrono::steady_clock::now(); + scancode = 0x80 | 0x45; + } + else + { + return; // no idea + } + } + else + { + return; // shouldn't happen, ignore it + } + } + else + { + // strip bit 7 of the make code to work around dodgy drivers that set it for key up events + if (rawinput.data.keyboard.MakeCode & ~USHORT(0xff)) + { + // won't fit in a byte along with the E0 flag + return; + } + scancode = (rawinput.data.keyboard.MakeCode & 0x7f) | ((rawinput.data.keyboard.Flags & RI_KEY_E0) ? 0x80 : 0x00); + + // fake shift generated with cursor control and Ins/Del for compatibility with very old DOS software + if (scancode == 0xaa) + return; + } // set or clear the key - keyboard.state[scancode] = (rawinput.data.keyboard.Flags & RI_KEY_BREAK) ? 0x00 : 0x80; + m_keyboard.state[scancode] = (rawinput.data.keyboard.Flags & RI_KEY_BREAK) ? 0x00 : 0x80; } + + virtual void configure(input_device &device) override + { + keyboard_trans_table const &table = keyboard_trans_table::instance(); + + // FIXME: GetKeyNameTextW is for scan codes from WM_KEYDOWN, which aren't quite the same as DIK_* keycodes + // in particular, NumLock and Pause are reversed for US-style keyboard systems + for (unsigned keynum = 0; keynum < MAX_KEYS; keynum++) + { + input_item_id itemid = table.map_di_scancode_to_itemid(keynum); + WCHAR keyname[100]; + + // generate the name + // FIXME: GetKeyNameText gives bogus names for media keys and various other things + // in many cases it ignores the "extended" bit and returns the key name corresponding to the scan code alone + LONG lparam = ((keynum & 0x7f) << 16) | ((keynum & 0x80) << 17); + if ((keynum & 0x7f) == 0x45) + lparam ^= 0x0100'0000; // horrid hack + if (GetKeyNameTextW(lparam, keyname, std::size(keyname)) == 0) + _snwprintf(keyname, std::size(keyname), L"Scan%03d", keynum); + std::string name = text::from_wstring(keyname); + + // add the item to the device + device.add_item( + name, + util::string_format("SCAN%03d", keynum), + itemid, + generic_button_get_state<std::uint8_t>, + &m_keyboard.state[keynum]); + } + } + +private: + std::chrono::steady_clock::time_point m_pause_pressed; + uint16_t m_e1; + keyboard_state m_keyboard; }; + //============================================================ // rawinput_mouse_device //============================================================ class rawinput_mouse_device : public rawinput_device { -private: - std::mutex m_device_lock; public: - mouse_state mouse; - - rawinput_mouse_device(running_machine& machine, const char *name, const char *id, input_module& module) - : rawinput_device(machine, name, id, DEVICE_CLASS_MOUSE, module), - mouse({0}) + rawinput_mouse_device(std::string &&name, std::string &&id, input_module &module, HANDLE handle) : + rawinput_device(std::move(name), std::move(id), module, handle), + m_mouse({0}), + m_x(0), + m_y(0), + m_v(0), + m_h(0) { } - void poll() override + virtual void poll(bool relative_reset) override { - mouse.lX = 0; - mouse.lY = 0; - mouse.lZ = 0; - - rawinput_device::poll(); + rawinput_device::poll(relative_reset); + if (relative_reset) + { + m_mouse.lX = std::exchange(m_x, 0); + m_mouse.lY = std::exchange(m_y, 0); + m_mouse.lV = std::exchange(m_v, 0); + m_mouse.lH = std::exchange(m_h, 0); + } } - void reset() override + virtual void reset() override { - memset(&mouse, 0, sizeof(mouse)); + rawinput_device::reset(); + memset(&m_mouse, 0, sizeof(m_mouse)); + m_x = m_y = m_v = m_h = 0; } - void process_event(RAWINPUT &rawinput) override + virtual void configure(input_device &device) override { + // populate the axes + device.add_item( + "X", + std::string_view(), + ITEM_ID_XAXIS, + generic_axis_get_state<LONG>, + &m_mouse.lX); + device.add_item( + "Y", + std::string_view(), + ITEM_ID_YAXIS, + generic_axis_get_state<LONG>, + &m_mouse.lY); + device.add_item( + "Scroll V", + std::string_view(), + ITEM_ID_ZAXIS, + generic_axis_get_state<LONG>, + &m_mouse.lV); + device.add_item( + "Scroll H", + std::string_view(), + ITEM_ID_RZAXIS, + generic_axis_get_state<LONG>, + &m_mouse.lH); + + // populate the buttons + for (int butnum = 0; butnum < 5; butnum++) + { + device.add_item( + default_button_name(butnum), + std::string_view(), + input_item_id(ITEM_ID_BUTTON1 + butnum), + generic_button_get_state<BYTE>, + &m_mouse.rgbButtons[butnum]); + } + } + virtual void process_event(RAWINPUT const &rawinput) override + { // If this data was intended for a rawinput mouse if (rawinput.data.mouse.usFlags == MOUSE_MOVE_RELATIVE) { + m_x += rawinput.data.mouse.lLastX * input_device::RELATIVE_PER_PIXEL; + m_y += rawinput.data.mouse.lLastY * input_device::RELATIVE_PER_PIXEL; - mouse.lX += rawinput.data.mouse.lLastX * INPUT_RELATIVE_PER_PIXEL; - mouse.lY += rawinput.data.mouse.lLastY * INPUT_RELATIVE_PER_PIXEL; - - // update zaxis + // update Z/Rz axes (vertical/horizontal scroll) if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_WHEEL) - mouse.lZ += static_cast<int16_t>(rawinput.data.mouse.usButtonData) * INPUT_RELATIVE_PER_PIXEL; + m_v += int16_t(rawinput.data.mouse.usButtonData) * input_device::RELATIVE_PER_PIXEL; + if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_HWHEEL) + m_h += int16_t(rawinput.data.mouse.usButtonData) * input_device::RELATIVE_PER_PIXEL; // update the button states; always update the corresponding mouse buttons - if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) mouse.rgbButtons[0] = 0x80; - if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_UP) mouse.rgbButtons[0] = 0x00; - if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) mouse.rgbButtons[1] = 0x80; - if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_UP) mouse.rgbButtons[1] = 0x00; - if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) mouse.rgbButtons[2] = 0x80; - if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_UP) mouse.rgbButtons[2] = 0x00; - if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) mouse.rgbButtons[3] = 0x80; - if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) mouse.rgbButtons[3] = 0x00; - if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) mouse.rgbButtons[4] = 0x80; - if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) mouse.rgbButtons[4] = 0x00; + if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) m_mouse.rgbButtons[0] = 0x80; + if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_UP) m_mouse.rgbButtons[0] = 0x00; + if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) m_mouse.rgbButtons[1] = 0x80; + if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_UP) m_mouse.rgbButtons[1] = 0x00; + if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) m_mouse.rgbButtons[2] = 0x80; + if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_UP) m_mouse.rgbButtons[2] = 0x00; + if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) m_mouse.rgbButtons[3] = 0x80; + if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) m_mouse.rgbButtons[3] = 0x00; + if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) m_mouse.rgbButtons[4] = 0x80; + if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) m_mouse.rgbButtons[4] = 0x00; } } + +private: + mouse_state m_mouse; + LONG m_x, m_y, m_v, m_h; }; + //============================================================ // rawinput_lightgun_device //============================================================ class rawinput_lightgun_device : public rawinput_device { -private: - std::mutex m_device_lock; public: - mouse_state lightgun; - - rawinput_lightgun_device(running_machine& machine, const char *name, const char *id, input_module& module) - : rawinput_device(machine, name, id, DEVICE_CLASS_LIGHTGUN, module), - lightgun({0}) + rawinput_lightgun_device(std::string &&name, std::string &&id, input_module &module, HANDLE handle) : + rawinput_device(std::move(name), std::move(id), module, handle), + m_lightgun({0}), + m_v(0), + m_h(0) { } - void poll() override + virtual void poll(bool relative_reset) override { - lightgun.lZ = 0; + rawinput_device::poll(relative_reset); + if (relative_reset) + { + m_lightgun.lV = std::exchange(m_v, 0); + m_lightgun.lH = std::exchange(m_h, 0); + } + } - rawinput_device::poll(); + virtual void reset() override + { + rawinput_device::reset(); + memset(&m_lightgun, 0, sizeof(m_lightgun)); + m_v = 0; + m_h = 0; } - void reset() override + virtual void configure(input_device &device) override { - memset(&lightgun, 0, sizeof(lightgun)); + // populate the axes + for (int axisnum = 0; axisnum < 2; axisnum++) + { + device.add_item( + default_axis_name[axisnum], + std::string_view(), + input_item_id(ITEM_ID_XAXIS + axisnum), + generic_axis_get_state<LONG>, + &m_lightgun.lX + axisnum); + } + + // scroll wheels are always relative if present + device.add_item( + "Scroll V", + std::string_view(), + ITEM_ID_ADD_RELATIVE1, + generic_axis_get_state<LONG>, + &m_lightgun.lV); + device.add_item( + "Scroll H", + std::string_view(), + ITEM_ID_ADD_RELATIVE2, + generic_axis_get_state<LONG>, + &m_lightgun.lH); + + // populate the buttons + for (int butnum = 0; butnum < 5; butnum++) + { + device.add_item( + default_button_name(butnum), + std::string_view(), + input_item_id(ITEM_ID_BUTTON1 + butnum), + generic_button_get_state<BYTE>, + &m_lightgun.rgbButtons[butnum]); + } } - void process_event(RAWINPUT &rawinput) override + virtual void process_event(RAWINPUT const &rawinput) override { // If this data was intended for a rawinput lightgun if (rawinput.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) { - // update the X/Y positions - lightgun.lX = normalize_absolute_axis(rawinput.data.mouse.lLastX, 0, INPUT_ABSOLUTE_MAX); - lightgun.lY = normalize_absolute_axis(rawinput.data.mouse.lLastY, 0, INPUT_ABSOLUTE_MAX); + m_lightgun.lX = normalize_absolute_axis(rawinput.data.mouse.lLastX, 0, input_device::ABSOLUTE_MAX); + m_lightgun.lY = normalize_absolute_axis(rawinput.data.mouse.lLastY, 0, input_device::ABSOLUTE_MAX); - // update zaxis + // update Z/Rz axes if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_WHEEL) - lightgun.lZ += static_cast<int16_t>(rawinput.data.mouse.usButtonData) * INPUT_RELATIVE_PER_PIXEL; + m_v += int16_t(rawinput.data.mouse.usButtonData) * input_device::RELATIVE_PER_PIXEL; + if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_HWHEEL) + m_h += int16_t(rawinput.data.mouse.usButtonData) * input_device::RELATIVE_PER_PIXEL; // update the button states; always update the corresponding mouse buttons - if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) lightgun.rgbButtons[0] = 0x80; - if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_UP) lightgun.rgbButtons[0] = 0x00; - if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) lightgun.rgbButtons[1] = 0x80; - if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_UP) lightgun.rgbButtons[1] = 0x00; - if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) lightgun.rgbButtons[2] = 0x80; - if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_UP) lightgun.rgbButtons[2] = 0x00; - if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) lightgun.rgbButtons[3] = 0x80; - if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) lightgun.rgbButtons[3] = 0x00; - if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) lightgun.rgbButtons[4] = 0x80; - if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) lightgun.rgbButtons[4] = 0x00; + if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) m_lightgun.rgbButtons[0] = 0x80; + if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_UP) m_lightgun.rgbButtons[0] = 0x00; + if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) m_lightgun.rgbButtons[1] = 0x80; + if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_UP) m_lightgun.rgbButtons[1] = 0x00; + if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) m_lightgun.rgbButtons[2] = 0x80; + if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_UP) m_lightgun.rgbButtons[2] = 0x00; + if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) m_lightgun.rgbButtons[3] = 0x80; + if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) m_lightgun.rgbButtons[3] = 0x00; + if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) m_lightgun.rgbButtons[4] = 0x80; + if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) m_lightgun.rgbButtons[4] = 0x00; } } + +private: + mouse_state m_lightgun; + LONG m_v, m_h; }; + //============================================================ -// rawinput_module - base class for rawinput modules +// rawinput_module - base class for RawInput modules //============================================================ -class rawinput_module : public wininput_module +class rawinput_module : public wininput_module<rawinput_device> { private: - osd::dynamic_module::ptr m_user32_dll; - get_rawinput_device_list_ptr get_rawinput_device_list; - get_rawinput_data_ptr get_rawinput_data; - get_rawinput_device_info_ptr get_rawinput_device_info; - register_rawinput_devices_ptr register_rawinput_devices; - std::mutex m_module_lock; + std::mutex m_module_lock; public: - rawinput_module(const char *type, const char* name) - : wininput_module(type, name), - get_rawinput_device_list(nullptr), - get_rawinput_data(nullptr), - get_rawinput_device_info(nullptr), - register_rawinput_devices(nullptr) + rawinput_module(const char *type, const char *name) : wininput_module<rawinput_device>(type, name) { } - bool probe() override + virtual bool probe() override { - m_user32_dll = osd::dynamic_module::open({ "user32.dll" }); - - get_rawinput_device_list = m_user32_dll->bind<get_rawinput_device_list_ptr>("GetRawInputDeviceList"); - get_rawinput_data = m_user32_dll->bind<get_rawinput_data_ptr>("GetRawInputData"); - get_rawinput_device_info = m_user32_dll->bind<get_rawinput_device_info_ptr>("GetRawInputDeviceInfoW"); - register_rawinput_devices = m_user32_dll->bind<register_rawinput_devices_ptr>("RegisterRawInputDevices"); - - if (!get_rawinput_device_list || !get_rawinput_data || - !get_rawinput_device_info || !register_rawinput_devices ) - { - return false; - } - return true; } - void input_init(running_machine &machine) override + virtual void input_init(running_machine &machine) override { - // get the number of devices, allocate a device list, and fetch it - UINT device_count = 0; - if ((*get_rawinput_device_list)(nullptr, &device_count, sizeof(RAWINPUTDEVICELIST)) != 0) - return; + wininput_module<rawinput_device>::input_init(machine); - if (device_count == 0) + // get initial number of devices + UINT device_count = 0; + if (GetRawInputDeviceList(nullptr, &device_count, sizeof(RAWINPUTDEVICELIST)) != 0) + { + osd_printf_error("Error getting initial number of RawInput devices.\n"); return; - - auto rawinput_devices = std::make_unique<RAWINPUTDEVICELIST[]>(device_count); - if ((*get_rawinput_device_list)(rawinput_devices.get(), &device_count, sizeof(RAWINPUTDEVICELIST)) == -1) + } + if (!device_count) return; - // iterate backwards through devices; new devices are added at the head - for (int devnum = device_count - 1; devnum >= 0; devnum--) + std::unique_ptr<RAWINPUTDEVICELIST []> rawinput_devices; + UINT retrieved; + do { - RAWINPUTDEVICELIST *device = &rawinput_devices[devnum]; - add_rawinput_device(machine, device); + 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)); } - - // don't enable global inputs when debugging - if (!machine.options().debug()) + while ((UINT(-1) == retrieved) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)); + if (UINT(-1) == retrieved) { - m_global_inputs_enabled = downcast<windows_options &>(machine.options()).global_inputs(); + osd_printf_error("Error listing RawInput devices.\n"); + return; } + // iterate backwards through devices; new devices are added at the head + for (int devnum = retrieved - 1; devnum >= 0; devnum--) + add_rawinput_device(rawinput_devices[devnum]); + // 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.hwndTarget = std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window(); + registration.dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; + registration.hwndTarget = dynamic_cast<win_window_info &>(*osd_common_t::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(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<class TDevice> - TDevice* create_rawinput_device(running_machine &machine, PRAWINPUTDEVICELIST rawinputdevice) + TDevice *create_rawinput_device(input_device_class deviceclass, RAWINPUTDEVICELIST const &rawinputdevice) { - TDevice* devinfo; - UINT name_length = 0; // determine the length of the device name, allocate it, and fetch it if not nameless - if ((*get_rawinput_device_info)(rawinputdevice->hDevice, RIDI_DEVICENAME, nullptr, &name_length) != 0) + UINT name_length = 0; + if (GetRawInputDeviceInfoW(rawinputdevice.hDevice, RIDI_DEVICENAME, nullptr, &name_length) != 0) return nullptr; - std::unique_ptr<TCHAR[]> tname = std::make_unique<TCHAR[]>(name_length + 1); - if (name_length > 1 && (*get_rawinput_device_info)(rawinputdevice->hDevice, RIDI_DEVICENAME, tname.get(), &name_length) == -1) + std::unique_ptr<WCHAR []> tname = std::make_unique<WCHAR []>(name_length + 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.c_str()); - - // set device id to raw input name - std::string utf8_id = osd::text::from_wstring(tname.get()); + // improve the name + std::string utf8_name = text::from_wstring(rawinput_device_improve_name(tname.get())); - devinfo = devicelist()->create_device<TDevice>(machine, utf8_name.c_str(), utf8_id.c_str(), *this); + // set device ID to raw input name + std::string utf8_id = text::from_wstring(tname.get()); - // Add the handle - devinfo->set_handle(rawinputdevice->hDevice); + tname.reset(); - return devinfo; + // allocate a device + return &create_device<TDevice>( + deviceclass, + std::move(utf8_name), + std::move(utf8_id), + rawinputdevice.hDevice); } - bool handle_input_event(input_event eventid, void* eventdata) override + virtual bool handle_input_event(input_event eventid, void const *eventdata) override { - // Only handle raw input data - if (!input_enabled() || eventid != INPUT_EVENT_RAWINPUT) - return false; - - HRAWINPUT rawinputdevice = *static_cast<HRAWINPUT*>(eventdata); - - BYTE small_buffer[4096]; - std::unique_ptr<BYTE[]> larger_buffer; - LPBYTE data = small_buffer; - UINT size; - - // ignore if not enabled - if (!input_enabled()) - return false; + switch (eventid) + { + // handle raw input data + case INPUT_EVENT_RAWINPUT: + { + HRAWINPUT const rawinputdevice = *reinterpret_cast<HRAWINPUT const *>(eventdata); + + union { RAWINPUT r; BYTE b[4096]; } small_buffer; + std::unique_ptr<BYTE []> larger_buffer; + LPVOID 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::align_val_t(alignof(RAWINPUT)), 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<std::mutex> scope_lock(m_module_lock); + + auto *const input = reinterpret_cast<RAWINPUT const *>(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) + { + return input->header.hDevice == device->device_handle(); + }); + if (devicelist().end() == target_device) + return false; + + (*target_device)->queue_events(input, 1); + return true; + } + } + break; - // determine the size of databuffer we need - if ((*get_rawinput_data)(rawinputdevice, RID_INPUT, nullptr, &size, sizeof(RAWINPUTHEADER)) != 0) - return false; + case INPUT_EVENT_ARRIVAL: + { + HRAWINPUT const rawinputdevice = *reinterpret_cast<HRAWINPUT const *>(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<WCHAR []> tname = std::make_unique<WCHAR []>(name_length + 1); + if (name_length > 1 && GetRawInputDeviceInfoW(rawinputdevice, RIDI_DEVICENAME, tname.get(), &name_length) == UINT(-1)) + return false; + std::string utf8_id = text::from_wstring(tname.get()); + tname.reset(); + + std::lock_guard<std::mutex> 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) + { + return device->reconnect_candidate(utf8_id); + }); + if (devicelist().end() == target_device) + return false; + + (*target_device)->attach_device(rawinputdevice); + return true; + } + break; - // if necessary, allocate a temporary buffer and fetch the data - if (size > sizeof(small_buffer)) - { - larger_buffer = std::make_unique<BYTE[]>(size); - data = larger_buffer.get(); - if (data == nullptr) - return false; - } + case INPUT_EVENT_REMOVAL: + { + HRAWINPUT const rawinputdevice = *reinterpret_cast<HRAWINPUT const *>(eventdata); - // fetch the data and process the appropriate message types - bool result = (*get_rawinput_data)(static_cast<HRAWINPUT>(rawinputdevice), RID_INPUT, data, &size, sizeof(RAWINPUTHEADER)); - if (result) - { - std::lock_guard<std::mutex> scope_lock(m_module_lock); + std::lock_guard<std::mutex> scope_lock(m_module_lock); - RAWINPUT *input = reinterpret_cast<RAWINPUT*>(data); + // find the device in the list and update + auto target_device = std::find_if( + devicelist().begin(), + devicelist().end(), + [rawinputdevice] (auto const &device) + { + return rawinputdevice == device->device_handle(); + }); - // find the device in the list and update - auto target_device = std::find_if(devicelist()->begin(), devicelist()->end(), [input](auto &device) - { - auto devinfo = dynamic_cast<rawinput_device*>(device.get()); - return devinfo != nullptr && input->header.hDevice == devinfo->device_handle(); - }); + if (devicelist().end() == target_device) + return false; - if (target_device != devicelist()->end()) - { - static_cast<rawinput_device*>((*target_device).get())->queue_events(input, 1); + (*target_device)->reset(); + (*target_device)->detach_device(); return true; } + break; + + default: + break; } + // must have been unhandled return false; } }; + //============================================================ -// keyboard_input_rawinput - rawinput keyboard module +// keyboard_input_rawinput - RawInput keyboard module //============================================================ class keyboard_input_rawinput : public rawinput_module { public: - keyboard_input_rawinput() - : rawinput_module(OSD_KEYBOARDINPUT_PROVIDER, "rawinput") + keyboard_input_rawinput() : rawinput_module(OSD_KEYBOARDINPUT_PROVIDER, "rawinput") { } protected: - USHORT usagepage() override { return 1; } - USHORT usage() override { return 6; } - void add_rawinput_device(running_machine& machine, RAWINPUTDEVICELIST * device) override + virtual USHORT usagepage() override { return 1; } + virtual USHORT usage() override { return 6; } + + virtual void add_rawinput_device(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 - rawinput_keyboard_device *devinfo = create_rawinput_device<rawinput_keyboard_device>(machine, device); - if (devinfo == nullptr) - return; - - keyboard_trans_table &table = keyboard_trans_table::instance(); - - // populate it - for (int keynum = 0; keynum < MAX_KEYS; keynum++) - { - input_item_id itemid = table.map_di_scancode_to_itemid(keynum); - TCHAR keyname[100]; - - // generate the name - if (GetKeyNameText(((keynum & 0x7f) << 16) | ((keynum & 0x80) << 17), keyname, ARRAY_LENGTH(keyname)) == 0) - _sntprintf(keyname, ARRAY_LENGTH(keyname), TEXT("Scan%03d"), keynum); - std::string name = osd::text::from_tstring(keyname); - - // add the item to the device - devinfo->device()->add_item(name.c_str(), itemid, generic_button_get_state<std::uint8_t>, &devinfo->keyboard.state[keynum]); - } + create_rawinput_device<rawinput_keyboard_device>(DEVICE_CLASS_KEYBOARD, device); } }; + //============================================================ -// mouse_input_rawinput - rawinput mouse module +// mouse_input_rawinput - RawInput mouse module //============================================================ class mouse_input_rawinput : public rawinput_module { public: - mouse_input_rawinput() - : rawinput_module(OSD_MOUSEINPUT_PROVIDER, "rawinput") + mouse_input_rawinput() : rawinput_module(OSD_MOUSEINPUT_PROVIDER, "rawinput") { } protected: - USHORT usagepage() override { return 1; } - USHORT usage() override { return 2; } - void add_rawinput_device(running_machine& machine, RAWINPUTDEVICELIST * device) override + virtual USHORT usagepage() override { return 1; } + virtual USHORT usage() override { return 2; } + + virtual void add_rawinput_device(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 - rawinput_mouse_device *devinfo = create_rawinput_device<rawinput_mouse_device>(machine, device); - if (devinfo == nullptr) - return; - - // populate the axes - for (int axisnum = 0; axisnum < 3; axisnum++) - { - devinfo->device()->add_item( - default_axis_name[axisnum], - static_cast<input_item_id>(ITEM_ID_XAXIS + axisnum), - generic_axis_get_state<LONG>, - &devinfo->mouse.lX + axisnum); - } - - // populate the buttons - for (int butnum = 0; butnum < 5; butnum++) - { - devinfo->device()->add_item( - default_button_name(butnum), - static_cast<input_item_id>(ITEM_ID_BUTTON1 + butnum), - generic_button_get_state<BYTE>, - &devinfo->mouse.rgbButtons[butnum]); - } + create_rawinput_device<rawinput_mouse_device>(DEVICE_CLASS_MOUSE, device); } }; + //============================================================ -// lightgun_input_rawinput - rawinput lightgun module +// lightgun_input_rawinput - RawInput lightgun module //============================================================ class lightgun_input_rawinput : public rawinput_module { public: - lightgun_input_rawinput() - : rawinput_module(OSD_LIGHTGUNINPUT_PROVIDER, "rawinput") + lightgun_input_rawinput() : rawinput_module(OSD_LIGHTGUNINPUT_PROVIDER, "rawinput") { } protected: - USHORT usagepage() override { return 1; } - USHORT usage() override { return 2; } - void add_rawinput_device(running_machine& machine, RAWINPUTDEVICELIST * device) override - { + virtual USHORT usagepage() override { return 1; } + virtual USHORT usage() override { return 2; } + virtual void add_rawinput_device(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 - rawinput_lightgun_device *devinfo = create_rawinput_device<rawinput_lightgun_device>(machine, device); - if (devinfo == nullptr) - return; - - // populate the axes - for (int axisnum = 0; axisnum < 3; axisnum++) - { - devinfo->device()->add_item( - default_axis_name[axisnum], - static_cast<input_item_id>(ITEM_ID_XAXIS + axisnum), - generic_axis_get_state<LONG>, - &devinfo->lightgun.lX + axisnum); - } - - // populate the buttons - for (int butnum = 0; butnum < 5; butnum++) - { - devinfo->device()->add_item( - default_button_name(butnum), - static_cast<input_item_id>(ITEM_ID_BUTTON1 + butnum), - generic_button_get_state<BYTE>, - &devinfo->lightgun.rgbButtons[butnum]); - } + create_rawinput_device<rawinput_lightgun_device>(DEVICE_CLASS_LIGHTGUN, device); } }; -#else +} // anonymous namespace + +} // namespace osd + +#else // defined(OSD_WINDOWS) + +#include "input_module.h" + +namespace osd { + +namespace { + MODULE_NOT_SUPPORTED(keyboard_input_rawinput, OSD_KEYBOARDINPUT_PROVIDER, "rawinput") MODULE_NOT_SUPPORTED(mouse_input_rawinput, OSD_MOUSEINPUT_PROVIDER, "rawinput") MODULE_NOT_SUPPORTED(lightgun_input_rawinput, OSD_LIGHTGUNINPUT_PROVIDER, "rawinput") -#endif -MODULE_DEFINITION(KEYBOARDINPUT_RAWINPUT, keyboard_input_rawinput) -MODULE_DEFINITION(MOUSEINPUT_RAWINPUT, mouse_input_rawinput) -MODULE_DEFINITION(LIGHTGUNINPUT_RAWINPUT, lightgun_input_rawinput) +} // anonymous namespace + +} // namespace osd + +#endif // defined(OSD_WINDOWS) + +MODULE_DEFINITION(KEYBOARDINPUT_RAWINPUT, osd::keyboard_input_rawinput) +MODULE_DEFINITION(MOUSEINPUT_RAWINPUT, osd::mouse_input_rawinput) +MODULE_DEFINITION(LIGHTGUNINPUT_RAWINPUT, osd::lightgun_input_rawinput) |