diff options
Diffstat (limited to 'src/osd/sdl')
-rw-r--r-- | src/osd/sdl/osdsdl.cpp | 307 | ||||
-rw-r--r-- | src/osd/sdl/osdsdl.h | 15 | ||||
-rw-r--r-- | src/osd/sdl/sdlopts.cpp | 4 | ||||
-rw-r--r-- | src/osd/sdl/sdlopts.h | 6 | ||||
-rw-r--r-- | src/osd/sdl/video.cpp | 1 | ||||
-rw-r--r-- | src/osd/sdl/window.cpp | 398 | ||||
-rw-r--r-- | src/osd/sdl/window.h | 73 |
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 |