summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/sdl
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2024-04-12 02:49:15 +1000
committer Vas Crabb <vas@vastheman.com>2024-04-12 02:49:15 +1000
commit4ddd26fe21edba8e7df65b12d721e9bed579e6e4 (patch)
treee1452c7d52a51fcefdf83a686f585c53ce10f5c0 /src/osd/sdl
parent78ef444ea6b639336b174e8e47d782a016ae6ae7 (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/sdl')
-rw-r--r--src/osd/sdl/osdsdl.cpp244
-rw-r--r--src/osd/sdl/osdsdl.h11
-rw-r--r--src/osd/sdl/sdlopts.cpp3
-rw-r--r--src/osd/sdl/sdlopts.h4
-rw-r--r--src/osd/sdl/window.cpp372
-rw-r--r--src/osd/sdl/window.h73
6 files changed, 604 insertions, 103 deletions
diff --git a/src/osd/sdl/osdsdl.cpp b/src/osd/sdl/osdsdl.cpp
index 2d3e5e4f02c..87af652733e 100644
--- a/src/osd/sdl/osdsdl.cpp
+++ b/src/osd/sdl/osdsdl.cpp
@@ -17,8 +17,8 @@
#include "ui/uimain.h"
-#include <SDL2/SDL.h>
-
+#include <algorithm>
+#include <cmath>
#include <cstdio>
#include <cstring>
@@ -168,7 +168,9 @@ sdl_osd_interface::sdl_osd_interface(sdl_options &options) :
m_modifier_keys(0),
m_last_click_time(std::chrono::steady_clock::time_point::min()),
m_last_click_x(0),
- m_last_click_y(0)
+ m_last_click_y(0),
+ m_enable_touch(false),
+ m_next_ptrdev(0)
{
}
@@ -260,6 +262,34 @@ void sdl_osd_interface::init(running_machine &machine)
}
}
+ /* do we want touch support or will we use mouse emulation? */
+ m_enable_touch = options().enable_touch();
+ try
+ {
+ if (m_enable_touch)
+ {
+ int const count(SDL_GetNumTouchDevices());
+ m_ptrdev_map.reserve(std::max<int>(count + 1, 8));
+ map_pointer_device(SDL_MOUSE_TOUCHID);
+ for (int i = 0; count > i; ++i)
+ {
+ SDL_TouchID const device(SDL_GetTouchDevice(i));
+ if (device)
+ map_pointer_device(device);
+ }
+ }
+ else
+ {
+ m_ptrdev_map.reserve(1);
+ map_pointer_device(SDL_MOUSE_TOUCHID);
+ }
+ }
+ catch (std::bad_alloc const &)
+ {
+ osd_printf_error("sdl_osd_interface: error allocating pointer data\n");
+ // survivable - it will still attempt to allocate mappings when it first sees devices
+ }
+
#if defined(SDLMAME_ANDROID)
SDL_SetHint(SDL_HINT_VIDEO_EXTERNAL_CONTEXT, "1");
#endif
@@ -502,74 +532,126 @@ void sdl_osd_interface::process_events()
break;
case SDL_MOUSEMOTION:
+ if (!m_enable_touch || (SDL_TOUCH_MOUSEID != event.motion.which))
{
- int cx, cy;
- auto const window = focus_window(event.motion);
- if (window && window->xy_to_render_target(event.motion.x, event.motion.y, &cx, &cy))
- machine().ui_input().push_mouse_move_event(window->target(), cx, cy);
+ auto const window = window_from_id(event.motion.windowID);
+ if (!window)
+ break;
+
+ unsigned device;
+ try
+ {
+ device = map_pointer_device(SDL_MOUSE_TOUCHID);
+ }
+ catch (std::bad_alloc const &)
+ {
+ osd_printf_error("sdl_osd_interface: error allocating pointer data\n");
+ break;
+ }
+
+ int x, y;
+ window->xy_to_render_target(event.motion.x, event.motion.y, &x, &y);
+ window->mouse_moved(device, x, y);
}
break;
case SDL_MOUSEBUTTONDOWN:
- //printf("But down %d %d %d %d %s\n", event.button.which, event.button.button, event.button.x, event.button.y, devinfo->name.c_str());
- if (event.button.button == 1)
+ case SDL_MOUSEBUTTONUP:
+ if (!m_enable_touch || (SDL_TOUCH_MOUSEID != event.button.which))
+ {
+ auto const window = window_from_id(event.button.windowID);
+ if (!window)
+ break;
+
+ unsigned device;
+ try
+ {
+ device = map_pointer_device(SDL_MOUSE_TOUCHID);
+ }
+ catch (std::bad_alloc const &)
+ {
+ osd_printf_error("sdl_osd_interface: error allocating pointer data\n");
+ break;
+ }
+
+ int x, y;
+ window->xy_to_render_target(event.button.x, event.button.y, &x, &y);
+ unsigned button(event.button.button - 1);
+ if ((1 == button) || (2 == button))
+ button ^= 3;
+ if (SDL_PRESSED == event.button.state)
+ window->mouse_down(device, x, y, button);
+ else
+ window->mouse_up(device, x, y, button);
+ }
+ break;
+
+ case SDL_MOUSEWHEEL:
{
- int cx, cy;
- auto const window = focus_window(event.button);
- if (window && window->xy_to_render_target(event.button.x, event.button.y, &cx, &cy))
+ auto const window = window_from_id(event.wheel.windowID);
+ if (window)
{
- auto const double_click_speed = std::chrono::milliseconds(250);
- auto const click = std::chrono::steady_clock::now();
- machine().ui_input().push_mouse_down_event(window->target(), cx, cy);
-
- // avoid overflow with std::chrono::time_point::min() by adding rather than subtracting
- if (click < (m_last_click_time + double_click_speed)
- && (cx >= (m_last_click_x - 4) && cx <= (m_last_click_x + 4))
- && (cy >= (m_last_click_y - 4) && cy <= (m_last_click_y + 4)))
+ unsigned device;
+ try
{
- m_last_click_time = std::chrono::time_point<std::chrono::steady_clock>::min();
- machine().ui_input().push_mouse_double_click_event(window->target(), cx, cy);
+ device = map_pointer_device(SDL_MOUSE_TOUCHID);
}
- else
+ catch (std::bad_alloc const &)
{
- m_last_click_time = click;
- m_last_click_x = cx;
- m_last_click_y = cy;
+ osd_printf_error("sdl_osd_interface: error allocating pointer data\n");
+ break;
}
+#if SDL_VERSION_ATLEAST(2, 0, 18)
+ window->mouse_wheel(device, std::lround(event.wheel.preciseY * 120));
+#else
+ window->mouse_wheel(device, event.wheel.y);
+#endif
}
}
- else if (event.button.button == 3)
- {
- int cx, cy;
- auto const window = focus_window(event.button);
- if (window != nullptr && window->xy_to_render_target(event.button.x, event.button.y, &cx, &cy))
- machine().ui_input().push_mouse_rdown_event(window->target(), cx, cy);
- }
break;
- case SDL_MOUSEBUTTONUP:
- //printf("But up %d %d %d %d\n", event.button.which, event.button.button, event.button.x, event.button.y);
- if (event.button.button == 1)
+ case SDL_FINGERMOTION:
+ case SDL_FINGERDOWN:
+ case SDL_FINGERUP:
+ if (m_enable_touch && (SDL_MOUSE_TOUCHID != event.tfinger.touchId))
{
- int cx, cy;
- auto const window = focus_window(event.button);
- if (window && window->xy_to_render_target(event.button.x, event.button.y, &cx, &cy))
- machine().ui_input().push_mouse_up_event(window->target(), cx, cy);
- }
- else if (event.button.button == 3)
- {
- int cx, cy;
- auto window = focus_window(event.button);
- if (window && window->xy_to_render_target(event.button.x, event.button.y, &cx, &cy))
- machine().ui_input().push_mouse_rup_event(window->target(), cx, cy);
- }
- break;
+ // ignore if it doesn't map to a window we own
+ auto const window = window_from_id(event.tfinger.windowID);
+ if (!window)
+ break;
+
+ // map SDL touch device ID to a zero-based device number
+ unsigned device;
+ try
+ {
+ device = map_pointer_device(event.tfinger.touchId);
+ }
+ catch (std::bad_alloc const &)
+ {
+ osd_printf_error("sdl_osd_interface: error allocating pointer data\n");
+ break;
+ }
- case SDL_MOUSEWHEEL:
- {
- auto const window = focus_window(event.wheel);
- if (window)
- machine().ui_input().push_mouse_wheel_event(window->target(), 0, 0, event.wheel.y, 3);
+ // convert normalised coordinates to what MAME wants
+ auto const size = window->get_size();
+ int const winx = std::lround(event.tfinger.x * size.width());
+ int const winy = std::lround(event.tfinger.y * size.height());
+ int x, y;
+ window->xy_to_render_target(winx, winy, &x, &y);
+
+ // call appropriate window method
+ switch (event.type)
+ {
+ case SDL_FINGERMOTION:
+ window->finger_moved(event.tfinger.fingerId, device, x, y);
+ break;
+ case SDL_FINGERDOWN:
+ window->finger_down(event.tfinger.fingerId, device, x, y);
+ break;
+ case SDL_FINGERUP:
+ window->finger_up(event.tfinger.fingerId, device, x, y);
+ break;
+ }
}
break;
}
@@ -626,12 +708,37 @@ void sdl_osd_interface::process_window_event(SDL_Event const &event)
break;
case SDL_WINDOWEVENT_ENTER:
- m_mouse_over_window = 1;
+ {
+ m_mouse_over_window = 1;
+ unsigned device;
+ try
+ {
+ device = map_pointer_device(SDL_MOUSE_TOUCHID);
+ }
+ catch (std::bad_alloc const &)
+ {
+ osd_printf_error("sdl_osd_interface: error allocating pointer data\n");
+ break;
+ }
+ window->mouse_entered(device);
+ }
break;
case SDL_WINDOWEVENT_LEAVE:
- machine().ui_input().push_mouse_leave_event(window->target());
- m_mouse_over_window = 0;
+ {
+ m_mouse_over_window = 0;
+ unsigned device;
+ try
+ {
+ device = map_pointer_device(SDL_MOUSE_TOUCHID);
+ }
+ catch (std::bad_alloc const &)
+ {
+ osd_printf_error("sdl_osd_interface: error allocating pointer data\n");
+ break;
+ }
+ window->mouse_left(device);
+ }
break;
case SDL_WINDOWEVENT_FOCUS_GAINED:
@@ -717,9 +824,28 @@ void sdl_osd_interface::check_osd_inputs()
template <typename T>
sdl_window_info *sdl_osd_interface::focus_window(T const &event) const
{
- // FIXME: SDL does not properly report the window for certain OS.
- if (false)
+ // FIXME: SDL does not properly report the window for certain versions of Ubuntu - is this still relevant?
+ if (m_enable_touch)
return window_from_id(event.windowID);
else
return m_focus_window;
}
+
+
+unsigned sdl_osd_interface::map_pointer_device(SDL_TouchID device)
+{
+ auto devpos(std::lower_bound(
+ m_ptrdev_map.begin(),
+ m_ptrdev_map.end(),
+ device,
+ [] (std::pair<SDL_TouchID, unsigned> const &mapping, SDL_TouchID id)
+ {
+ return mapping.first < id;
+ }));
+ if ((m_ptrdev_map.end() == devpos) || (device != devpos->first))
+ {
+ devpos = m_ptrdev_map.emplace(devpos, device, m_next_ptrdev);
+ ++m_next_ptrdev;
+ }
+ return devpos->second;
+}
diff --git a/src/osd/sdl/osdsdl.h b/src/osd/sdl/osdsdl.h
index c8ce167d699..e1d472d9e45 100644
--- a/src/osd/sdl/osdsdl.h
+++ b/src/osd/sdl/osdsdl.h
@@ -10,11 +10,14 @@
#include "modules/lib/osdobj_common.h"
#include "modules/osdmodule.h"
+#include <SDL2/SDL.h>
+
#include <cassert>
#include <chrono>
#include <memory>
#include <mutex>
#include <unordered_map>
+#include <utility>
#include <string>
#include <vector>
@@ -128,8 +131,6 @@ public:
};
-union SDL_Event;
-
using sdl_event_manager = event_subscription_manager<SDL_Event, uint32_t>;
@@ -194,6 +195,8 @@ private:
bool mouse_over_window() const { return m_mouse_over_window > 0; }
template <typename T> sdl_window_info *focus_window(T const &event) const;
+ unsigned map_pointer_device(SDL_TouchID device);
+
sdl_options &m_options;
sdl_window_info *m_focus_window;
int m_mouse_over_window;
@@ -202,6 +205,10 @@ private:
std::chrono::steady_clock::time_point m_last_click_time;
int m_last_click_x;
int m_last_click_y;
+
+ bool m_enable_touch;
+ unsigned m_next_ptrdev;
+ std::vector<std::pair<SDL_TouchID, unsigned> > m_ptrdev_map;
};
//============================================================
diff --git a/src/osd/sdl/sdlopts.cpp b/src/osd/sdl/sdlopts.cpp
index 8e922cb7a4e..f08dc41f963 100644
--- a/src/osd/sdl/sdlopts.cpp
+++ b/src/osd/sdl/sdlopts.cpp
@@ -66,7 +66,8 @@ const options_entry f_sdl_option_entries[] =
{ SDLOPTION_KEYMAP_FILE, "keymap.dat", core_options::option_type::PATH, "keymap filename" },
// joystick mapping
- { nullptr, nullptr, core_options::option_type::HEADER, "SDL JOYSTICK MAPPING" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "SDL INPUT OPTIONS" },
+ { SDLOPTION_ENABLE_TOUCH, "0", core_options::option_type::BOOLEAN, "enable touch input support" },
{ SDLOPTION_SIXAXIS, "0", core_options::option_type::BOOLEAN, "use special handling for PS3 Sixaxis controllers" },
#if (USE_XINPUT)
diff --git a/src/osd/sdl/sdlopts.h b/src/osd/sdl/sdlopts.h
index d754a0e8619..fe75e097407 100644
--- a/src/osd/sdl/sdlopts.h
+++ b/src/osd/sdl/sdlopts.h
@@ -26,6 +26,7 @@
#define SDLOPTION_KEYMAP "keymap"
#define SDLOPTION_KEYMAP_FILE "keymap_file"
+#define SDLOPTION_ENABLE_TOUCH "enable_touch"
#define SDLOPTION_SIXAXIS "sixaxis"
#if defined(USE_XINPUT) && USE_XINPUT
#define SDLOPTION_LIGHTGUNINDEX "lightgun_index"
@@ -82,7 +83,8 @@ public:
bool keymap() const { return bool_value(SDLOPTION_KEYMAP); }
const char *keymap_file() const { return value(SDLOPTION_KEYMAP_FILE); }
- // joystick mapping
+ // input options
+ bool enable_touch() const { return bool_value(SDLOPTION_ENABLE_TOUCH); }
bool sixaxis() const { return bool_value(SDLOPTION_SIXAXIS); }
const char *video_driver() const { return value(SDLOPTION_VIDEODRIVER); }
diff --git a/src/osd/sdl/window.cpp b/src/osd/sdl/window.cpp
index 4bb8531df2a..1e6318f57a9 100644
--- a/src/osd/sdl/window.cpp
+++ b/src/osd/sdl/window.cpp
@@ -13,24 +13,27 @@
#include "emuopts.h"
#include "render.h"
#include "screen.h"
+#include "uiinput.h"
#include "ui/uimain.h"
// OSD headers
-#include "window.h"
-#include "osdsdl.h"
#include "modules/monitor/monitor_common.h"
+#include "osdsdl.h"
+#include "window.h"
// standard SDL headers
-#include <SDL2/SDL.h>
#include <SDL2/SDL_syswm.h>
// standard C headers
+#include <algorithm>
+#include <cassert>
#include <cmath>
+#include <list>
+#include <memory>
+
#ifndef _MSC_VER
#include <unistd.h>
#endif
-#include <list>
-#include <memory>
#ifdef SDLMAME_WIN32
#include <windows.h>
@@ -61,11 +64,6 @@
#define SDL_VERSION_EQUALS(v1, vnum2) (SDL_VERSIONNUM(v1.major, v1.minor, v1.patch) == vnum2)
-class SDL_DM_Wrapper
-{
-public:
- SDL_DisplayMode mode;
-};
//============================================================
@@ -248,9 +246,9 @@ void sdl_window_info::toggle_full_screen()
#endif
if (fullscreen() && (video_config.switchres || is_osx))
{
- SDL_SetWindowFullscreen(platform_window(), 0); // Try to set mode
- SDL_SetWindowDisplayMode(platform_window(), &m_original_mode->mode); // Try to set mode
- SDL_SetWindowFullscreen(platform_window(), SDL_WINDOW_FULLSCREEN); // Try to set mode
+ SDL_SetWindowFullscreen(platform_window(), 0);
+ SDL_SetWindowDisplayMode(platform_window(), &m_original_mode);
+ SDL_SetWindowFullscreen(platform_window(), SDL_WINDOW_FULLSCREEN);
}
SDL_DestroyWindow(platform_window());
set_platform_window(nullptr);
@@ -334,6 +332,293 @@ int sdl_window_info::xy_to_render_target(int x, int y, int *xt, int *yt)
return renderer().xy_to_render_target(x, y, xt, yt);
}
+void sdl_window_info::mouse_entered(unsigned device)
+{
+ m_mouse_inside = true;
+}
+
+void sdl_window_info::mouse_left(unsigned device)
+{
+ m_mouse_inside = false;
+
+ auto info(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), SDL_FingerID(-1), &sdl_pointer_info::compare));
+ if ((m_active_pointers.end() == info) || (info->finger != SDL_FingerID(-1)))
+ return;
+
+ // leaving implicitly releases buttons, so check hold/drag if necessary
+ if (BIT(info->buttons, 0))
+ {
+ assert(0 <= info->clickcnt);
+
+ auto const now(std::chrono::steady_clock::now());
+ auto const exp(std::chrono::milliseconds(250) + info->pressed);
+ int const dx(info->x - info->pressedx);
+ int const dy(info->y - info->pressedy);
+ int const distance((dx * dx) + (dy * dy));
+ if ((exp < now) || (CLICK_DISTANCE < distance))
+ info->clickcnt = -info->clickcnt;
+ }
+
+ // push to UI manager
+ machine().ui_input().push_pointer_leave(
+ target(),
+ osd::ui_event_handler::pointer::MOUSE,
+ info->index,
+ device,
+ info->x, info->y,
+ info->buttons, info->clickcnt);
+
+ // dump pointer data
+ m_pointer_mask &= ~(decltype(m_pointer_mask)(1) << info->index);
+ if (info->index < m_next_pointer)
+ m_next_pointer = info->index;
+ m_active_pointers.erase(info);
+}
+
+void sdl_window_info::mouse_down(unsigned device, int x, int y, unsigned button)
+{
+ if (!m_mouse_inside)
+ return;
+
+ auto const info(map_pointer(SDL_FingerID(-1), device));
+ if (m_active_pointers.end() == info)
+ return;
+
+ if ((x == info->x) && (y == info->y) && BIT(info->buttons, button))
+ return;
+
+ // detect multi-click actions
+ if (0 == button)
+ {
+ info->primary_down(
+ x,
+ y,
+ std::chrono::milliseconds(250),
+ CLICK_DISTANCE,
+ false,
+ m_ptrdev_info);
+ }
+
+ // update info and push to UI manager
+ auto const pressed(decltype(info->buttons)(1) << button);
+ info->x = x;
+ info->y = y;
+ info->buttons |= pressed;
+ machine().ui_input().push_pointer_update(
+ target(),
+ osd::ui_event_handler::pointer::MOUSE,
+ info->index,
+ device,
+ x, y,
+ info->buttons, pressed, 0, info->clickcnt);
+}
+
+void sdl_window_info::mouse_up(unsigned device, int x, int y, unsigned button)
+{
+ if (!m_mouse_inside)
+ return;
+
+ auto const info(map_pointer(SDL_FingerID(-1), device));
+ if (m_active_pointers.end() == info)
+ return;
+
+ if ((x == info->x) && (y == info->y) && !BIT(info->buttons, button))
+ return;
+
+ // detect multi-click actions
+ if (0 == button)
+ {
+ info->check_primary_hold_drag(
+ x,
+ y,
+ std::chrono::milliseconds(250),
+ CLICK_DISTANCE);
+ }
+
+ // update info and push to UI manager
+ auto const released(decltype(info->buttons)(1) << button);
+ info->x = x;
+ info->y = y;
+ info->buttons &= ~released;
+ machine().ui_input().push_pointer_update(
+ target(),
+ osd::ui_event_handler::pointer::MOUSE,
+ info->index,
+ device,
+ x, y,
+ info->buttons, 0, released, info->clickcnt);
+}
+
+void sdl_window_info::mouse_moved(unsigned device, int x, int y)
+{
+ if (!m_mouse_inside)
+ return;
+
+ auto const info(map_pointer(SDL_FingerID(-1), device));
+ if (m_active_pointers.end() == info)
+ return;
+
+ // detect multi-click actions
+ if (BIT(info->buttons, 0))
+ {
+ info->check_primary_hold_drag(
+ x,
+ y,
+ std::chrono::milliseconds(250),
+ CLICK_DISTANCE);
+ }
+
+ // update info and push to UI manager
+ info->x = x;
+ info->y = y;
+ machine().ui_input().push_pointer_update(
+ target(),
+ osd::ui_event_handler::pointer::MOUSE,
+ info->index,
+ device,
+ x, y,
+ info->buttons, 0, 0, info->clickcnt);
+}
+
+void sdl_window_info::mouse_wheel(unsigned device, int y)
+{
+ if (!m_mouse_inside)
+ return;
+
+ auto const info(map_pointer(SDL_FingerID(-1), device));
+ if (m_active_pointers.end() == info)
+ return;
+
+ // push to UI manager
+ machine().ui_input().push_mouse_wheel_event(target(), info->x, info->y, y, 3);
+}
+
+void sdl_window_info::finger_down(SDL_FingerID finger, unsigned device, int x, int y)
+{
+ auto const info(map_pointer(finger, device));
+ if (m_active_pointers.end() == info)
+ return;
+
+ assert(!info->buttons);
+
+ // detect multi-click actions
+ info->primary_down(
+ x,
+ y,
+ std::chrono::milliseconds(250),
+ TAP_DISTANCE,
+ true,
+ m_ptrdev_info);
+
+ // update info and push to UI manager
+ info->x = x;
+ info->y = y;
+ info->buttons = 1;
+ machine().ui_input().push_pointer_update(
+ target(),
+ osd::ui_event_handler::pointer::TOUCH,
+ info->index,
+ device,
+ x, y,
+ 1, 1, 0, info->clickcnt);
+}
+
+void sdl_window_info::finger_up(SDL_FingerID finger, unsigned device, int x, int y)
+{
+ auto info(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), finger, &sdl_pointer_info::compare));
+ if ((m_active_pointers.end() == info) || (info->finger != finger))
+ return;
+
+ assert(1 == info->buttons);
+
+ // check for conversion to a (multi-)click-and-hold/drag
+ info->check_primary_hold_drag(
+ x,
+ y,
+ std::chrono::milliseconds(250),
+ TAP_DISTANCE);
+
+ // need to remember touches to recognise multi-tap gestures
+ if (0 < info->clickcnt)
+ {
+ auto const now(std::chrono::steady_clock::now());
+ auto const time = std::chrono::milliseconds(250);
+ if ((time + info->pressed) >= now)
+ {
+ try
+ {
+ unsigned i(0);
+ if (m_ptrdev_info.size() > device)
+ i = m_ptrdev_info[device].clear_expired_touches(now, time);
+ else
+ m_ptrdev_info.resize(device + 1);
+
+ if (std::size(m_ptrdev_info[device].touches) > i)
+ {
+ m_ptrdev_info[device].touches[i].when = info->pressed;
+ m_ptrdev_info[device].touches[i].x = info->pressedx;
+ m_ptrdev_info[device].touches[i].y = info->pressedy;
+ m_ptrdev_info[device].touches[i].cnt = info->clickcnt;
+ }
+ }
+ catch (std::bad_alloc const &)
+ {
+ osd_printf_error("win_window_info: error allocating pointer data\n");
+ }
+ }
+ }
+
+ // push to UI manager
+ machine().ui_input().push_pointer_update(
+ target(),
+ osd::ui_event_handler::pointer::TOUCH,
+ info->index,
+ device,
+ x, y,
+ 0, 0, 1, info->clickcnt);
+ machine().ui_input().push_pointer_leave(
+ target(),
+ osd::ui_event_handler::pointer::TOUCH,
+ info->index,
+ device,
+ x, y,
+ 0, info->clickcnt);
+
+ // dump pointer data
+ m_pointer_mask &= ~(decltype(m_pointer_mask)(1) << info->index);
+ if (info->index < m_next_pointer)
+ m_next_pointer = info->index;
+ m_active_pointers.erase(info);
+}
+
+void sdl_window_info::finger_moved(SDL_FingerID finger, unsigned device, int x, int y)
+{
+ auto info(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), finger, &sdl_pointer_info::compare));
+ if ((m_active_pointers.end() == info) || (info->finger != finger))
+
+ assert(1 == info->buttons);
+
+ if ((x != info->x) || (y != info->y))
+ {
+ info->check_primary_hold_drag(
+ x,
+ y,
+ std::chrono::milliseconds(250),
+ TAP_DISTANCE);
+
+ // update info and push to UI manager
+ info->x = x;
+ info->y = y;
+ machine().ui_input().push_pointer_update(
+ target(),
+ osd::ui_event_handler::pointer::TOUCH,
+ info->index,
+ device,
+ x, y,
+ 1, 0, 0, info->clickcnt);
+ }
+}
+
//============================================================
// sdlwindow_video_window_create
// (main thread)
@@ -373,9 +658,9 @@ void sdl_window_info::complete_destroy()
if (fullscreen() && video_config.switchres)
{
- SDL_SetWindowFullscreen(platform_window(), 0); // Try to set mode
- SDL_SetWindowDisplayMode(platform_window(), &m_original_mode->mode); // Try to set mode
- SDL_SetWindowFullscreen(platform_window(), SDL_WINDOW_FULLSCREEN); // Try to set mode
+ SDL_SetWindowFullscreen(platform_window(), 0);
+ SDL_SetWindowDisplayMode(platform_window(), &m_original_mode);
+ SDL_SetWindowFullscreen(platform_window(), SDL_WINDOW_FULLSCREEN);
}
renderer_reset();
@@ -684,7 +969,7 @@ int sdl_window_info::complete_create()
SDL_DisplayMode mode;
//SDL_GetCurrentDisplayMode(window().monitor()->handle, &mode);
SDL_GetWindowDisplayMode(platform_window(), &mode);
- m_original_mode->mode = mode;
+ m_original_mode = mode;
mode.w = temp.width();
mode.h = temp.height();
if (m_win_config.refresh)
@@ -1021,6 +1306,52 @@ osd_dim sdl_window_info::get_max_bounds(int constrain)
return maximum.dim();
}
+
+std::vector<sdl_window_info::sdl_pointer_info>::iterator sdl_window_info::map_pointer(SDL_FingerID finger, unsigned device)
+{
+ auto found(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), finger, &sdl_pointer_info::compare));
+ if ((m_active_pointers.end() != found) && (found->finger == finger))
+ return found;
+
+ if ((sizeof(m_next_pointer) * 8) <= m_next_pointer)
+ {
+ assert(~decltype(m_pointer_mask)(0) == m_pointer_mask);
+ osd_printf_warning("sdl_window_info: exceeded maximum number of active pointers\n");
+ return m_active_pointers.end();
+ }
+ assert(!BIT(m_pointer_mask, m_next_pointer));
+
+ try
+ {
+ found = m_active_pointers.emplace(
+ found,
+ sdl_pointer_info(finger, m_next_pointer, device));
+ m_pointer_mask |= decltype(m_pointer_mask)(1) << m_next_pointer;
+ do
+ {
+ ++m_next_pointer;
+ }
+ while (((sizeof(m_next_pointer) * 8) > m_next_pointer) && BIT(m_pointer_mask, m_next_pointer));
+
+ return found;
+ }
+ catch (std::bad_alloc const &)
+ {
+ osd_printf_error("sdl_window_info: error allocating pointer data\n");
+ return m_active_pointers.end();
+ }
+}
+
+
+inline sdl_window_info::sdl_pointer_info::sdl_pointer_info(SDL_FingerID f, unsigned i, unsigned d)
+ : pointer_info(i, d)
+ , finger(f)
+{
+}
+
+
+
+
//============================================================
// construction and destruction
//============================================================
@@ -1040,13 +1371,18 @@ sdl_window_info::sdl_window_info(
, m_extra_flags(0)
, m_mouse_captured(false)
, m_mouse_hidden(false)
+ , m_pointer_mask(0)
+ , m_next_pointer(0)
+ , m_mouse_inside(false)
{
//FIXME: these should be per_window in config-> or even better a bit set
m_fullscreen = !video_config.windowed;
m_prescale = video_config.prescale;
m_windowed_dim = osd_dim(config->width, config->height);
- m_original_mode = std::make_unique<SDL_DM_Wrapper>();
+
+ m_ptrdev_info.reserve(1);
+ m_active_pointers.reserve(16);
}
sdl_window_info::~sdl_window_info()
diff --git a/src/osd/sdl/window.h b/src/osd/sdl/window.h
index 77477176b51..49fe452192f 100644
--- a/src/osd/sdl/window.h
+++ b/src/osd/sdl/window.h
@@ -14,22 +14,20 @@
#include "modules/osdwindow.h"
#include "osdsync.h"
+#include <SDL2/SDL.h>
+
+#include <chrono>
#include <cstdint>
#include <memory>
+#include <vector>
//============================================================
// TYPE DEFINITIONS
//============================================================
-struct SDL_Window;
-
class render_target;
-// forward of SDL_DisplayMode not possible (typedef struct) - define wrapper
-
-class SDL_DM_Wrapper;
-
typedef uintptr_t HashT;
#define OSDWORK_CALLBACK(name) void *name(void *param, int threadid)
@@ -65,26 +63,34 @@ public:
int xy_to_render_target(int x, int y, int *xt, int *yt);
-private:
- // window handle and info
- int m_startmaximized;
+ void mouse_entered(unsigned device);
+ void mouse_left(unsigned device);
+ void mouse_down(unsigned device, int x, int y, unsigned button);
+ void mouse_up(unsigned device, int x, int y, unsigned button);
+ void mouse_moved(unsigned device, int x, int y);
+ void mouse_wheel(unsigned device, int y);
+ void finger_down(SDL_FingerID finger, unsigned device, int x, int y);
+ void finger_up(SDL_FingerID finger, unsigned device, int x, int y);
+ void finger_moved(SDL_FingerID finger, unsigned device, int x, int y);
- // dimensions
- osd_dim m_minimum_dim;
- osd_dim m_windowed_dim;
+private:
+ struct sdl_pointer_info : public pointer_info
+ {
+ static constexpr bool compare(sdl_pointer_info const &info, SDL_FingerID finger) { return info.finger < finger; }
- // rendering info
- osd_event m_rendered_event;
+ sdl_pointer_info(sdl_pointer_info const &) = default;
+ sdl_pointer_info(sdl_pointer_info &&) = default;
+ sdl_pointer_info &operator=(sdl_pointer_info const &) = default;
+ sdl_pointer_info &operator=(sdl_pointer_info &&) = default;
- // Original display_mode
- std::unique_ptr<SDL_DM_Wrapper> m_original_mode;
+ sdl_pointer_info(SDL_FingerID, unsigned i, unsigned d);
- int m_extra_flags;
+ SDL_FingerID finger;
+ };
// returns 0 on success, else 1
int complete_create();
-private:
int wnd_extra_width();
int wnd_extra_height();
osd_rect constrain_to_aspect_ratio(const osd_rect &rect, int adjustment);
@@ -94,12 +100,35 @@ private:
osd_dim pick_best_mode();
void set_fullscreen(int afullscreen) { m_fullscreen = afullscreen; }
- // monitor info
- bool m_mouse_captured;
- bool m_mouse_hidden;
-
void measure_fps(int update);
+ std::vector<sdl_pointer_info>::iterator map_pointer(SDL_FingerID finger, unsigned device);
+
+ // window handle and info
+ int m_startmaximized;
+
+ // dimensions
+ osd_dim m_minimum_dim;
+ osd_dim m_windowed_dim;
+
+ // rendering info
+ osd_event m_rendered_event;
+
+ // Original display_mode
+ SDL_DisplayMode m_original_mode;
+
+ int m_extra_flags;
+
+ // monitor info
+ bool m_mouse_captured;
+ bool m_mouse_hidden;
+
+ // info on currently active pointers - 64 pointers ought to be enough for anyone
+ uint64_t m_pointer_mask;
+ unsigned m_next_pointer;
+ bool m_mouse_inside;
+ std::vector<pointer_dev_info> m_ptrdev_info;
+ std::vector<sdl_pointer_info> m_active_pointers;
};
#endif // MAME_OSD_SDL_WINDOW_H