diff options
Diffstat (limited to 'src/osd/modules/input/input_rawinput.cpp')
-rw-r--r-- | src/osd/modules/input/input_rawinput.cpp | 186 |
1 files changed, 139 insertions, 47 deletions
diff --git a/src/osd/modules/input/input_rawinput.cpp b/src/osd/modules/input/input_rawinput.cpp index 3ee8e2d8f7e..5b6813dcd59 100644 --- a/src/osd/modules/input/input_rawinput.cpp +++ b/src/osd/modules/input/input_rawinput.cpp @@ -25,9 +25,11 @@ #include <algorithm> #include <cassert> +#include <chrono> #include <functional> #include <mutex> #include <new> +#include <utility> // standard windows headers #include <windows.h> @@ -307,23 +309,75 @@ class rawinput_keyboard_device : public rawinput_device public: 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 } }) { } 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; + } + + virtual void poll(bool relative_reset) override + { + 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; } 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 m_keyboard.state[scancode] = (rawinput.data.keyboard.Flags & RI_KEY_BREAK) ? 0x00 : 0x80; @@ -333,13 +387,20 @@ public: { keyboard_trans_table const &table = keyboard_trans_table::instance(); - for (int keynum = 0; keynum < MAX_KEYS; keynum++) + // 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 - if (GetKeyNameTextW(((keynum & 0x7f) << 16) | ((keynum & 0x80) << 17), keyname, std::size(keyname)) == 0) + // 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); @@ -354,6 +415,8 @@ public: } private: + std::chrono::steady_clock::time_point m_pause_pressed; + uint16_t m_e1; keyboard_state m_keyboard; }; @@ -370,7 +433,8 @@ public: m_mouse({0}), m_x(0), m_y(0), - m_z(0) + m_v(0), + m_h(0) { } @@ -381,28 +445,45 @@ public: { m_mouse.lX = std::exchange(m_x, 0); m_mouse.lY = std::exchange(m_y, 0); - m_mouse.lZ = std::exchange(m_z, 0); + m_mouse.lV = std::exchange(m_v, 0); + m_mouse.lH = std::exchange(m_h, 0); } } virtual void reset() override { + rawinput_device::reset(); memset(&m_mouse, 0, sizeof(m_mouse)); - m_x = m_y = m_z = 0; + m_x = m_y = m_v = m_h = 0; } virtual void configure(input_device &device) override { // populate the axes - for (int axisnum = 0; axisnum < 3; axisnum++) - { - device.add_item( - default_axis_name[axisnum], - std::string_view(), - input_item_id(ITEM_ID_XAXIS + axisnum), - generic_axis_get_state<LONG>, - &m_mouse.lX + axisnum); - } + 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++) @@ -418,17 +499,17 @@ public: 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; - // update Z axis (vertical scroll) + // update Z/Rz axes (vertical/horizontal scroll) if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_WHEEL) - m_z += int16_t(rawinput.data.mouse.usButtonData) * input_device::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) m_mouse.rgbButtons[0] = 0x80; @@ -446,7 +527,7 @@ public: private: mouse_state m_mouse; - LONG m_x, m_y, m_z; + LONG m_x, m_y, m_v, m_h; }; @@ -460,7 +541,8 @@ public: 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_z(0) + m_v(0), + m_h(0) { } @@ -468,13 +550,18 @@ public: { rawinput_device::poll(relative_reset); if (relative_reset) - m_lightgun.lZ = std::exchange(m_z, 0); + { + m_lightgun.lV = std::exchange(m_v, 0); + m_lightgun.lH = std::exchange(m_h, 0); + } } virtual void reset() override { + rawinput_device::reset(); memset(&m_lightgun, 0, sizeof(m_lightgun)); - m_z = 0; + m_v = 0; + m_h = 0; } virtual void configure(input_device &device) override @@ -490,13 +577,19 @@ public: &m_lightgun.lX + axisnum); } - // scroll wheel is always relative if present + // scroll wheels are always relative if present device.add_item( - default_axis_name[2], + "Scroll V", std::string_view(), ITEM_ID_ADD_RELATIVE1, generic_axis_get_state<LONG>, - &m_lightgun.lZ); + &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++) @@ -515,14 +608,15 @@ public: // If this data was intended for a rawinput lightgun if (rawinput.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) { - // update the X/Y positions 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) - m_z += int16_t(rawinput.data.mouse.usButtonData) * input_device::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) m_lightgun.rgbButtons[0] = 0x80; @@ -540,12 +634,12 @@ public: private: mouse_state m_lightgun; - LONG m_z; + 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<rawinput_device> @@ -608,9 +702,7 @@ public: RAWINPUTDEVICE registration; registration.usUsagePage = usagepage(); registration.usUsage = usage(); - registration.dwFlags = RIDEV_DEVNOTIFY; - if (background_input()) - registration.dwFlags |= RIDEV_INPUTSINK; + registration.dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; registration.hwndTarget = dynamic_cast<win_window_info &>(*osd_common_t::window_list().front()).platform_window(); // register the device @@ -654,18 +746,18 @@ protected: rawinputdevice.hDevice); } - virtual bool handle_input_event(input_event eventid, void *eventdata) override + virtual bool handle_input_event(input_event eventid, void const *eventdata) override { switch (eventid) { // handle raw input data case INPUT_EVENT_RAWINPUT: { - HRAWINPUT const rawinputdevice = *static_cast<HRAWINPUT *>(eventdata); + HRAWINPUT const rawinputdevice = *reinterpret_cast<HRAWINPUT const *>(eventdata); - BYTE small_buffer[4096]; + union { RAWINPUT r; BYTE b[4096]; } small_buffer; std::unique_ptr<BYTE []> larger_buffer; - LPBYTE data = small_buffer; + LPVOID data = &small_buffer; UINT size; // determine the size of data buffer we need @@ -675,7 +767,7 @@ protected: // if necessary, allocate a temporary buffer and fetch the data if (size > sizeof(small_buffer)) { - larger_buffer.reset(new (std::nothrow) BYTE [size]); + larger_buffer.reset(new (std::align_val_t(alignof(RAWINPUT)), std::nothrow) BYTE [size]); data = larger_buffer.get(); if (!data) return false; @@ -691,7 +783,7 @@ protected: { std::lock_guard<std::mutex> scope_lock(m_module_lock); - auto *input = reinterpret_cast<RAWINPUT *>(data); + auto *const input = reinterpret_cast<RAWINPUT const *>(data); if (!input->header.hDevice) return false; @@ -714,7 +806,7 @@ protected: case INPUT_EVENT_ARRIVAL: { - HRAWINPUT const rawinputdevice = *static_cast<HRAWINPUT *>(eventdata); + 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; @@ -747,7 +839,7 @@ protected: case INPUT_EVENT_REMOVAL: { - HRAWINPUT const rawinputdevice = *static_cast<HRAWINPUT *>(eventdata); + HRAWINPUT const rawinputdevice = *reinterpret_cast<HRAWINPUT const *>(eventdata); std::lock_guard<std::mutex> scope_lock(m_module_lock); @@ -780,7 +872,7 @@ protected: //============================================================ -// keyboard_input_rawinput - rawinput keyboard module +// keyboard_input_rawinput - RawInput keyboard module //============================================================ class keyboard_input_rawinput : public rawinput_module @@ -807,7 +899,7 @@ protected: //============================================================ -// mouse_input_rawinput - rawinput mouse module +// mouse_input_rawinput - RawInput mouse module //============================================================ class mouse_input_rawinput : public rawinput_module @@ -834,7 +926,7 @@ protected: //============================================================ -// lightgun_input_rawinput - rawinput lightgun module +// lightgun_input_rawinput - RawInput lightgun module //============================================================ class lightgun_input_rawinput : public rawinput_module |