diff options
author | 2024-04-12 02:49:15 +1000 | |
---|---|---|
committer | 2024-04-12 02:49:15 +1000 | |
commit | 4ddd26fe21edba8e7df65b12d721e9bed579e6e4 (patch) | |
tree | e1452c7d52a51fcefdf83a686f585c53ce10f5c0 /src/osd/modules/input/input_win32.cpp | |
parent | 78ef444ea6b639336b174e8e47d782a016ae6ae7 (diff) |
Initial touch input support:
* Feed mouse/pen/touch pointer events through UI input manager with Win32 and SDL.
* Started migrating UI code to use new API and reworking mouse/touch interaction.
* emu/render.cpp: Support pressing multiple clickable layout items simultaneously.
* emu/render.cpp: Allow UI elements to be drawn in any window.
* emu/rendlay.cpp, luaengine_render.cpp: Added layout view events for pointer input.
* ui/ui.cpp: Allow the UI handler to control pointer display.
* ui/analogipt.cpp: Added mouse/touch and more keys for navigating field state list.
* ui/menu.cpp: Use vertical swipe to scroll and horizontal swipe to adjust.
* ui/menu.cpp: Draw after processing input - greatly improves responsiveness.
* ui/menu.cpp: Ignore keyboard/gamepad input during pointer actions.
* ui/selmenu.cpp: Made left/right info pane arrows repeat when held.
* ui/selmenu.cpp: Use middle click to move keyboard focus.
* ui/selmenu.cpp: Let filter list scroll if it's too tall, and use a bit of horizontal padding.
* ui/selmenu.cpp: Improved divider sizing.
* ui/state.cpp: Don't allow clicks to pass through the confirm deletion prompt to the menu.
* ui/simpleselgame.cpp: Fixed error message display and graphics/sound status not showing.
* ui/simpleselgame.cpp: Allow tap/click to dismiss error message.
* ui/utils.cpp: Show UI for choice filters when there are no choices - it's less confusing.
* modules/input/input_sdl.cpp: Made scaling for mouse scroll better match RawInput and DirectInput.
* modules/input/input_rawinput.cpp: Added support for horizontal scroll axis.
* modules/input/input_win32.cpp: Added support for scroll axes and more buttons to mouse/lightgun.
* modules/debugger/debugimgui.cpp: Don't fight over events with the UI manager - it breaks menus.
* osd/windows/window.cpp: Translate mouse position to window cooridinates for scroll wheel events.
* osd/sdl/window.cpp: Supply last mouse position for scroll wheel events if possible.
* scripts/build/complay.py: Made zero input mask an error - it was only being used to block clicks.
Diffstat (limited to 'src/osd/modules/input/input_win32.cpp')
-rw-r--r-- | src/osd/modules/input/input_win32.cpp | 242 |
1 files changed, 168 insertions, 74 deletions
diff --git a/src/osd/modules/input/input_win32.cpp b/src/osd/modules/input/input_win32.cpp index 3803bc2a180..49c211740c0 100644 --- a/src/osd/modules/input/input_win32.cpp +++ b/src/osd/modules/input/input_win32.cpp @@ -129,13 +129,15 @@ public: // win32_mouse_device //============================================================ -class win32_mouse_device : public event_based_device<MouseButtonEventArgs> +class win32_mouse_device : public event_based_device<MouseUpdateEventArgs> { public: win32_mouse_device(std::string &&name, std::string &&id, input_module &module) : event_based_device(std::move(name), std::move(id), module), m_mouse({0}), - m_win32_mouse({{0}}) + m_win32_mouse({{0}}), + m_vscroll(0), + m_hscroll(0) { } @@ -146,7 +148,7 @@ public: if (!relative_reset) return; - CURSORINFO cursor_info = {0}; + CURSORINFO cursor_info = { 0 }; cursor_info.cbSize = sizeof(CURSORINFO); GetCursorInfo(&cursor_info); @@ -169,23 +171,42 @@ public: SetCursorPos(m_win32_mouse.last_point.x, m_win32_mouse.last_point.y); } + + // update scroll axes + m_mouse.lV = std::exchange(m_vscroll, 0) * input_device::RELATIVE_PER_PIXEL; + m_mouse.lH = std::exchange(m_hscroll, 0) * input_device::RELATIVE_PER_PIXEL; } virtual void configure(input_device &device) override { // 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_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 < 2; butnum++) + for (int butnum = 0; butnum < 5; butnum++) { device.add_item( default_button_name(butnum), @@ -200,13 +221,25 @@ public: { memset(&m_mouse, 0, sizeof(m_mouse)); memset(&m_win32_mouse, 0, sizeof(m_win32_mouse)); + m_vscroll = m_hscroll = 0; } protected: - virtual void process_event(MouseButtonEventArgs const &args) override + virtual void process_event(MouseUpdateEventArgs const &args) override { // set the button state - m_mouse.rgbButtons[args.button] = args.keydown ? 0x80 : 0x00; + assert(!(args.pressed & args.released)); + for (unsigned i = 0; 5 > i; ++i) + { + if (BIT(args.pressed, i)) + m_mouse.rgbButtons[i] = 0x80; + else if (BIT(args.released, i)) + m_mouse.rgbButtons[i] = 0x00; + } + + // accumulate scroll delta + m_vscroll += args.vdelta; + m_hscroll += args.hdelta; } private: @@ -217,6 +250,7 @@ private: mouse_state m_mouse; win32_mouse_state m_win32_mouse; + long m_vscroll, m_hscroll; }; @@ -244,14 +278,18 @@ public: virtual bool handle_input_event(input_event eventid, void *eventdata) override { - if (!manager().class_enabled(DEVICE_CLASS_MOUSE) || eventid != INPUT_EVENT_MOUSE_BUTTON) - return false; - - auto const *const args = static_cast<MouseButtonEventArgs *>(eventdata); - devicelist().for_each_device( - [args] (auto &device) { device.queue_events(args, 1); }); + if (manager().class_enabled(DEVICE_CLASS_MOUSE)) + { + if ((eventid == INPUT_EVENT_MOUSE_BUTTON) || (eventid == INPUT_EVENT_MOUSE_WHEEL)) + { + auto const *const args = reinterpret_cast<MouseUpdateEventArgs *>(eventdata); + devicelist().for_each_device( + [args] (auto &device) { device.queue_events(args, 1); }); + return true; + } + } - return true; + return false; } }; @@ -260,7 +298,7 @@ public: // win32_lightgun_device_base //============================================================ -class win32_lightgun_device_base : public event_based_device<MouseButtonEventArgs> +class win32_lightgun_device_base : public event_based_device<MouseUpdateEventArgs> { public: virtual void reset() override @@ -268,7 +306,17 @@ public: memset(&m_mouse, 0, sizeof(m_mouse)); } - virtual void configure(input_device &device) override +protected: + win32_lightgun_device_base( + std::string &&name, + std::string &&id, + input_module &module) : + event_based_device(std::move(name), std::move(id), module), + m_mouse({ 0 }) + { + } + + void do_configure(input_device &device, unsigned buttons) { // populate the axes for (int axisnum = 0; axisnum < 2; axisnum++) @@ -282,7 +330,7 @@ public: } // populate the buttons - for (int butnum = 0; butnum < 2; butnum++) + for (int butnum = 0; butnum < buttons; butnum++) { device.add_item( default_button_name(butnum), @@ -293,16 +341,6 @@ public: } } -protected: - win32_lightgun_device_base( - std::string &&name, - std::string &&id, - input_module &module) : - event_based_device(std::move(name), std::move(id), module), - m_mouse({ 0 }) - { - } - mouse_state m_mouse; }; @@ -319,7 +357,9 @@ public: std::string &&name, std::string &&id, input_module &module) : - win32_lightgun_device_base(std::move(name), std::move(id), module) + win32_lightgun_device_base(std::move(name), std::move(id), module), + m_vscroll(0), + m_hscroll(0) { } @@ -348,14 +388,60 @@ public: // update the X/Y positions m_mouse.lX = xpos; m_mouse.lY = ypos; + + // update the scroll axes if appropriate + if (relative_reset) + { + m_mouse.lV = std::exchange(m_vscroll, 0) * input_device::RELATIVE_PER_PIXEL; + m_mouse.lH = std::exchange(m_hscroll, 0) * input_device::RELATIVE_PER_PIXEL; + } + } + + virtual void configure(input_device &device) override + { + do_configure(device, 5); + + // add scroll axes + device.add_item( + "Scroll V", + std::string_view(), + ITEM_ID_ADD_RELATIVE1, + generic_axis_get_state<LONG>, + &m_mouse.lV); + device.add_item( + "Scroll H", + std::string_view(), + ITEM_ID_ADD_RELATIVE2, + generic_axis_get_state<LONG>, + &m_mouse.lH); + } + + virtual void reset() override + { + win32_lightgun_device_base::reset(); + m_vscroll = m_hscroll = 0; } protected: - virtual void process_event(MouseButtonEventArgs const &args) override + virtual void process_event(MouseUpdateEventArgs const &args) override { // In non-shared axis mode, just update the button state - m_mouse.rgbButtons[args.button] = args.keydown ? 0x80 : 0x00; + assert(!(args.pressed & args.released)); + for (unsigned i = 0; 5 > i; ++i) + { + if (BIT(args.pressed, i)) + m_mouse.rgbButtons[i] = 0x80; + else if (BIT(args.released, i)) + m_mouse.rgbButtons[i] = 0x00; + } + + // accumulate scroll delta + m_vscroll += args.vdelta; + m_hscroll += args.hdelta; } + +private: + long m_vscroll, m_hscroll; }; @@ -376,38 +462,42 @@ public: { } -protected: - virtual void process_event(MouseButtonEventArgs const &args) override + virtual void configure(input_device &device) override { - int const button = args.button; - - if (button > 3) - return; // We only handle the first four buttons in shared axis mode - else if (button >= 2 && m_gun_index == 0) - return; // First gun doesn't handle buttons 2 and 3 - else if (button < 2 && m_gun_index == 1) - return; // Second gun doesn't handle buttons 0 and 1 - - // Adjust the button if we're the second lightgun - int const logical_button = (m_gun_index == 1) ? (button - 2) : button; + do_configure(device, 2); + } - // set the button state - m_mouse.rgbButtons[logical_button] = args.keydown ? 0x80 : 0x00; - if (args.keydown) +protected: + virtual void process_event(MouseUpdateEventArgs const &args) override + { + // We only handle the first four buttons in shared axis mode + assert(!(args.pressed & args.released)); + for (unsigned i = 0; 2 > i; ++i) { - // get the position relative to the window - HWND const hwnd = dynamic_cast<win_window_info &>(*osd_common_t::window_list().front()).platform_window(); - RECT client_rect; - GetClientRect(hwnd, &client_rect); - - POINT mousepos; - mousepos.x = args.xpos; - mousepos.y = args.ypos; - ScreenToClient(hwnd, &mousepos); - - // convert to absolute coordinates - m_mouse.lX = normalize_absolute_axis(mousepos.x, client_rect.left, client_rect.right); - m_mouse.lY = normalize_absolute_axis(mousepos.y, client_rect.top, client_rect.bottom); + // Adjust the button if we're the second lightgun + unsigned const bit = i + ((1 == m_gun_index) ? 2 : 0); + if (BIT(args.pressed, bit)) + { + m_mouse.rgbButtons[i] = 0x80; + + // get the position relative to the window + HWND const hwnd = dynamic_cast<win_window_info &>(*osd_common_t::window_list().front()).platform_window(); + RECT client_rect; + GetClientRect(hwnd, &client_rect); + + POINT mousepos; + mousepos.x = args.xpos; + mousepos.y = args.ypos; + ScreenToClient(hwnd, &mousepos); + + // convert to absolute coordinates + m_mouse.lX = normalize_absolute_axis(mousepos.x, client_rect.left, client_rect.right); + m_mouse.lY = normalize_absolute_axis(mousepos.y, client_rect.top, client_rect.bottom); + } + else if (BIT(args.released, bit)) + { + m_mouse.rgbButtons[i] = 0x00; + } } } @@ -449,14 +539,18 @@ public: virtual bool handle_input_event(input_event eventid, void *eventdata) override { - if (!manager().class_enabled(DEVICE_CLASS_LIGHTGUN) || eventid != INPUT_EVENT_MOUSE_BUTTON) - return false; - - auto const *const args = static_cast<MouseButtonEventArgs *>(eventdata); - devicelist().for_each_device( - [args] (auto &device) { device.queue_events(args, 1); }); + if (manager().class_enabled(DEVICE_CLASS_LIGHTGUN)) + { + if ((eventid == INPUT_EVENT_MOUSE_BUTTON) || (eventid == INPUT_EVENT_MOUSE_WHEEL)) + { + auto const *const args = reinterpret_cast<MouseUpdateEventArgs *>(eventdata); + devicelist().for_each_device( + [args] (auto &device) { device.queue_events(args, 1); }); + return true; + } + } - return true; + return false; } }; |