summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/sdl
diff options
context:
space:
mode:
Diffstat (limited to 'src/osd/sdl')
-rw-r--r--src/osd/sdl/osdsdl.cpp307
-rw-r--r--src/osd/sdl/osdsdl.h15
-rw-r--r--src/osd/sdl/sdlopts.cpp4
-rw-r--r--src/osd/sdl/sdlopts.h6
-rw-r--r--src/osd/sdl/video.cpp1
-rw-r--r--src/osd/sdl/window.cpp398
-rw-r--r--src/osd/sdl/window.h73
7 files changed, 634 insertions, 170 deletions
diff --git a/src/osd/sdl/osdsdl.cpp b/src/osd/sdl/osdsdl.cpp
index 6c5aef9f08c..d9268869729 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>
@@ -55,7 +55,6 @@ void defines_verbose()
osd_printf_verbose("\n");
osd_printf_verbose("Build defines 1: ");
MACRO_VERBOSE(LSB_FIRST);
- MACRO_VERBOSE(PTR64);
MACRO_VERBOSE(MAME_NOASM);
MACRO_VERBOSE(MAME_DEBUG);
MACRO_VERBOSE(BIGENDIAN);
@@ -168,7 +167,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 +261,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
@@ -343,60 +372,50 @@ void sdl_osd_interface::customize_input_type_list(std::vector<input_type_entry>
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_PGDN);
break;
- // OSD hotkeys use LCTRL and start at F3, they start at
- // F3 because F1-F2 are hardcoded into many drivers to
+ // OSD hotkeys use LALT/LCTRL and start at F3, they start
+ // at F3 because F1-F2 are hardcoded into many drivers to
// various dipswitches, and pressing them together with
- // LCTRL will still press/toggle these dipswitches.
-
- // add a Not lcrtl condition to the reset key
- case IPT_UI_SOFT_RESET:
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F3, input_seq::not_code, KEYCODE_LCONTROL, input_seq::not_code, KEYCODE_LSHIFT);
- break;
-
- // add a Not lcrtl condition to the show gfx key
- case IPT_UI_SHOW_GFX:
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F4, input_seq::not_code, KEYCODE_LCONTROL);
- break;
+ // LALT/LCTRL will still press/toggle these dipswitches.
- // LCTRL-F5 to toggle OpenGL filtering
+ // LALT-F10 to toggle OpenGL filtering
case IPT_OSD_5:
entry.configure_osd("TOGGLE_FILTER", N_p("input-name", "Toggle Filter"));
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F5, KEYCODE_LCONTROL);
+ entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F10, KEYCODE_LALT);
break;
- // LCTRL-F6 to decrease OpenGL prescaling
+ // add a Not LALT condition to the throttle key
+ case IPT_UI_THROTTLE:
+ entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F10, input_seq::not_code, KEYCODE_LALT);
+ break;
+
+ // LALT-F8 to decrease OpenGL prescaling
case IPT_OSD_6:
entry.configure_osd("DECREASE_PRESCALE", N_p("input-name", "Decrease Prescaling"));
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F6, KEYCODE_LCONTROL);
+ entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F8, KEYCODE_LALT);
break;
- // add a Not lcrtl condition to the toggle cheat key
- case IPT_UI_TOGGLE_CHEAT:
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F6, input_seq::not_code, KEYCODE_LCONTROL);
+ // add a Not LALT condition to the frameskip dec key
+ case IPT_UI_FRAMESKIP_DEC:
+ entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F8, input_seq::not_code, KEYCODE_LALT, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT);
break;
- // LCTRL-F7 to increase OpenGL prescaling
+ // LALT-F9 to increase OpenGL prescaling
case IPT_OSD_7:
entry.configure_osd("INCREASE_PRESCALE", N_p("input-name", "Increase Prescaling"));
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F7, KEYCODE_LCONTROL);
+ entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F9, KEYCODE_LALT);
+ break;
+
+ // add a Not LALT condition to the load state key
+ case IPT_UI_FRAMESKIP_INC:
+ entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F9, input_seq::not_code, KEYCODE_LALT);
break;
- // lshift-lalt-F12 for fullscreen video (BGFX)
+ // LSHIFT-LALT-F12 for fullscreen video (BGFX)
case IPT_OSD_8:
entry.configure_osd("RENDER_AVI", N_p("input-name", "Record Rendered Video"));
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, KEYCODE_LSHIFT, KEYCODE_LALT);
break;
- // add a Not lcrtl condition to the load state key
- case IPT_UI_LOAD_STATE:
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F7, input_seq::not_code, KEYCODE_LCONTROL, input_seq::not_code, KEYCODE_LSHIFT);
- break;
-
- // add a Not lcrtl condition to the throttle key
- case IPT_UI_THROTTLE:
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F10, input_seq::not_code, KEYCODE_LCONTROL);
- break;
-
// disable the config menu if the ALT key is down
// (allows ALT-TAB to switch between apps)
case IPT_UI_MENU:
@@ -488,7 +507,9 @@ void sdl_osd_interface::process_events()
}
else if (m_modifier_keys & MODIFIER_KEY_SHIFT)
{
- if (event.key.keysym.sym == SDLK_6) // Ctrl-^ (RS)
+ if (event.key.keysym.sym == SDLK_2) // Ctrl-@ (NUL)
+ machine().ui_input().push_char_event(osd_common_t::window_list().front()->target(), 0x00);
+ else if (event.key.keysym.sym == SDLK_6) // Ctrl-^ (RS)
machine().ui_input().push_char_event(osd_common_t::window_list().front()->target(), 0x1e);
else if (event.key.keysym.sym == SDLK_MINUS) // Ctrl-_ (US)
machine().ui_input().push_char_event(osd_common_t::window_list().front()->target(), 0x1f);
@@ -512,74 +533,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))
{
- 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.button.windowID);
+ if (!window)
+ break;
+
+ unsigned device;
+ try
{
- 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)))
+ 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:
+ {
+ auto const window = window_from_id(event.wheel.windowID);
+ if (window)
+ {
+ 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)
- {
- 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)
+ case SDL_FINGERMOTION:
+ case SDL_FINGERDOWN:
+ case SDL_FINGERUP:
+ if (m_enable_touch && (SDL_MOUSE_TOUCHID != event.tfinger.touchId))
{
- 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;
}
@@ -636,12 +709,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:
@@ -705,7 +803,7 @@ void sdl_osd_interface::check_osd_inputs()
if (USE_OPENGL)
{
- //FIXME: on a per window basis
+ // FIXME: on a per window basis
if (machine().ui_input().pressed(IPT_OSD_5))
{
video_config.filter = !video_config.filter;
@@ -727,9 +825,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..74730f69df5 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>;
@@ -167,10 +168,6 @@ public:
virtual void process_events() override;
-protected:
- virtual void build_slider_list() override;
- virtual void update_slider_list() override;
-
private:
enum
{
@@ -194,6 +191,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 +201,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..3953a47b7f8 100644
--- a/src/osd/sdl/sdlopts.cpp
+++ b/src/osd/sdl/sdlopts.cpp
@@ -66,8 +66,10 @@ 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" },
+ { SDLOPTION_DUAL_LIGHTGUN ";dual", "0", core_options::option_type::BOOLEAN, "enable dual lightgun input" },
#if (USE_XINPUT)
// lightgun mapping
diff --git a/src/osd/sdl/sdlopts.h b/src/osd/sdl/sdlopts.h
index d754a0e8619..f6338fe1db6 100644
--- a/src/osd/sdl/sdlopts.h
+++ b/src/osd/sdl/sdlopts.h
@@ -26,7 +26,9 @@
#define SDLOPTION_KEYMAP "keymap"
#define SDLOPTION_KEYMAP_FILE "keymap_file"
+#define SDLOPTION_ENABLE_TOUCH "enable_touch"
#define SDLOPTION_SIXAXIS "sixaxis"
+#define SDLOPTION_DUAL_LIGHTGUN "dual_lightgun"
#if defined(USE_XINPUT) && USE_XINPUT
#define SDLOPTION_LIGHTGUNINDEX "lightgun_index"
#endif
@@ -82,8 +84,10 @@ 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); }
+ bool dual_lightgun() const { return bool_value(SDLOPTION_DUAL_LIGHTGUN); }
const char *video_driver() const { return value(SDLOPTION_VIDEODRIVER); }
const char *render_driver() const { return value(SDLOPTION_RENDERDRIVER); }
diff --git a/src/osd/sdl/video.cpp b/src/osd/sdl/video.cpp
index dddc4ef80e6..8fe836aabf2 100644
--- a/src/osd/sdl/video.cpp
+++ b/src/osd/sdl/video.cpp
@@ -62,7 +62,6 @@ bool sdl_osd_interface::video_init()
for (index = 0; index < video_config.numscreens; index++)
{
osd_window_config conf;
- memset(&conf, 0, sizeof(conf));
get_resolution(options().resolution(), options().resolution(index), &conf, true);
// create window ...
diff --git a/src/osd/sdl/window.cpp b/src/osd/sdl/window.cpp
index 41f0c5af2be..59be82238d0 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;
-};
//============================================================
@@ -113,30 +111,6 @@ bool sdl_osd_interface::window_init()
}
-void sdl_osd_interface::update_slider_list()
-{
- for (auto const &window : osd_common_t::window_list())
- {
- // check if any window has dirty sliders
- if (window->renderer().sliders_dirty())
- {
- build_slider_list();
- return;
- }
- }
-}
-
-void sdl_osd_interface::build_slider_list()
-{
- m_sliders.clear();
-
- for (auto const &window : osd_common_t::window_list())
- {
- std::vector<ui::menu_item> window_sliders = window->renderer().get_slider_list();
- m_sliders.insert(m_sliders.end(), window_sliders.begin(), window_sliders.end());
- }
-}
-
//============================================================
// sdlwindow_exit
// (main thread)
@@ -248,9 +222,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);
@@ -266,7 +240,7 @@ void sdl_window_info::modify_prescale(int dir)
{
int new_prescale = prescale();
- if (dir > 0 && prescale() < 3)
+ if (dir > 0 && prescale() < 20)
new_prescale = prescale() + 1;
if (dir < 0 && prescale() > 1)
new_prescale = prescale() - 1;
@@ -286,8 +260,8 @@ void sdl_window_info::modify_prescale(int dir)
m_prescale = new_prescale;
notify_changed();
}
- machine().ui().popup_time(1, "Prescale %d", prescale());
}
+ machine().ui().popup_time(1, "Prescale %d", prescale());
}
//============================================================
@@ -334,6 +308,291 @@ 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) && (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 +632,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 +943,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 +1280,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 +1345,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