Содержит правки из следующих коммитов: - WIP: all-in-one - Janko: cache on - DeZog fix - Revert "drop mlz" - emu/debug/debugcpu.cpp,sinclair/spectrum.cpp: Guarded pointer accessors - sinclair/sprinter.cpp tmkonf - dma delay under investigation - harddisks-shareable.diff - ignore - плагин и скрипты для управления MAME by Claude code (MCP) - много всего - mouse release
861 lines
23 KiB
C++
861 lines
23 KiB
C++
// license:BSD-3-Clause
|
|
// copyright-holders:Olivier Galibert, R. Belmont
|
|
|
|
#include "osdsdl.h"
|
|
|
|
#include "modules/input/input_common.h"
|
|
#include "modules/lib/osdlib.h"
|
|
#include "window.h"
|
|
|
|
#include "util/language.h"
|
|
#include "util/unicode.h"
|
|
|
|
// TODO: reduce dependence on concrete emu classes
|
|
#include "emu.h"
|
|
#include "main.h"
|
|
#include "uiinput.h"
|
|
|
|
#include "ui/uimain.h"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
|
|
|
|
namespace {
|
|
|
|
//============================================================
|
|
// defines_verbose
|
|
//============================================================
|
|
|
|
#define MAC_EXPAND_STR(_m) #_m
|
|
#define MACRO_VERBOSE(_mac) \
|
|
do { \
|
|
if (strcmp(MAC_EXPAND_STR(_mac), #_mac) != 0) \
|
|
osd_printf_verbose("%s=%s ", #_mac, MAC_EXPAND_STR(_mac)); \
|
|
} while (0)
|
|
|
|
void defines_verbose()
|
|
{
|
|
osd_printf_verbose("Build version: %s\n", emulator_info::get_build_version());
|
|
osd_printf_verbose("Build architecure: ");
|
|
MACRO_VERBOSE(SDLMAME_ARCH);
|
|
osd_printf_verbose("\n");
|
|
osd_printf_verbose("Build defines 1: ");
|
|
MACRO_VERBOSE(SDLMAME_UNIX);
|
|
MACRO_VERBOSE(SDLMAME_X11);
|
|
MACRO_VERBOSE(SDLMAME_WIN32);
|
|
MACRO_VERBOSE(SDLMAME_MACOSX);
|
|
MACRO_VERBOSE(SDLMAME_DARWIN);
|
|
MACRO_VERBOSE(SDLMAME_LINUX);
|
|
MACRO_VERBOSE(SDLMAME_SOLARIS);
|
|
MACRO_VERBOSE(SDLMAME_IRIX);
|
|
MACRO_VERBOSE(SDLMAME_BSD);
|
|
osd_printf_verbose("\n");
|
|
osd_printf_verbose("Build defines 1: ");
|
|
MACRO_VERBOSE(LSB_FIRST);
|
|
MACRO_VERBOSE(MAME_NOASM);
|
|
MACRO_VERBOSE(MAME_DEBUG);
|
|
MACRO_VERBOSE(BIGENDIAN);
|
|
MACRO_VERBOSE(CPP_COMPILE);
|
|
MACRO_VERBOSE(SYNC_IMPLEMENTATION);
|
|
osd_printf_verbose("\n");
|
|
osd_printf_verbose("SDL/OpenGL defines: ");
|
|
osd_printf_verbose("SDL_COMPILEDVERSION=%d ", SDL_COMPILEDVERSION);
|
|
MACRO_VERBOSE(USE_OPENGL);
|
|
MACRO_VERBOSE(USE_DISPATCH_GL);
|
|
osd_printf_verbose("\n");
|
|
osd_printf_verbose("Compiler defines A: ");
|
|
MACRO_VERBOSE(__GNUC__);
|
|
MACRO_VERBOSE(__GNUC_MINOR__);
|
|
MACRO_VERBOSE(__GNUC_PATCHLEVEL__);
|
|
MACRO_VERBOSE(__VERSION__);
|
|
osd_printf_verbose("\n");
|
|
osd_printf_verbose("Compiler defines B: ");
|
|
MACRO_VERBOSE(__amd64__);
|
|
MACRO_VERBOSE(__x86_64__);
|
|
MACRO_VERBOSE(__unix__);
|
|
MACRO_VERBOSE(__i386__);
|
|
MACRO_VERBOSE(__ppc__);
|
|
MACRO_VERBOSE(__ppc64__);
|
|
osd_printf_verbose("\n");
|
|
osd_printf_verbose("Compiler defines C: ");
|
|
MACRO_VERBOSE(_FORTIFY_SOURCE);
|
|
MACRO_VERBOSE(__USE_FORTIFY_LEVEL);
|
|
osd_printf_verbose("\n");
|
|
}
|
|
|
|
|
|
//============================================================
|
|
// osd_sdl_info
|
|
//============================================================
|
|
|
|
void osd_sdl_info()
|
|
{
|
|
int num = SDL_GetNumVideoDrivers();
|
|
|
|
osd_printf_verbose("Available videodrivers: ");
|
|
for (int i = 0; i < num; i++)
|
|
{
|
|
const char *name = SDL_GetVideoDriver(i);
|
|
osd_printf_verbose("%s ", name);
|
|
}
|
|
osd_printf_verbose("\n");
|
|
|
|
osd_printf_verbose("Current Videodriver: %s\n", SDL_GetCurrentVideoDriver());
|
|
num = SDL_GetNumVideoDisplays();
|
|
for (int i = 0; i < num; i++)
|
|
{
|
|
SDL_DisplayMode mode;
|
|
|
|
osd_printf_verbose("\tDisplay #%d\n", i);
|
|
if (SDL_GetDesktopDisplayMode(i, &mode) == 0)
|
|
osd_printf_verbose("\t\tDesktop Mode: %dx%d-%d@%d\n", mode.w, mode.h, SDL_BITSPERPIXEL(mode.format), mode.refresh_rate);
|
|
if (SDL_GetCurrentDisplayMode(i, &mode) == 0)
|
|
osd_printf_verbose("\t\tCurrent Display Mode: %dx%d-%d@%d\n", mode.w, mode.h, SDL_BITSPERPIXEL(mode.format), mode.refresh_rate);
|
|
|
|
osd_printf_verbose("\t\tRenderdrivers:\n");
|
|
for (int j = 0; j < SDL_GetNumRenderDrivers(); j++)
|
|
{
|
|
SDL_RendererInfo info;
|
|
SDL_GetRenderDriverInfo(j, &info);
|
|
osd_printf_verbose("\t\t\t%10s (%dx%d)\n", info.name, info.max_texture_width, info.max_texture_height);
|
|
}
|
|
}
|
|
|
|
osd_printf_verbose("Available audio drivers: \n");
|
|
num = SDL_GetNumAudioDrivers();
|
|
for (int i = 0; i < num; i++)
|
|
{
|
|
osd_printf_verbose("\t%-20s\n", SDL_GetAudioDriver(i));
|
|
}
|
|
}
|
|
|
|
|
|
sdl_window_info *window_from_id(Uint32 id)
|
|
{
|
|
SDL_Window const *const sdl_window = SDL_GetWindowFromID(id);
|
|
|
|
auto const window = std::find_if(
|
|
osd_common_t::window_list().begin(),
|
|
osd_common_t::window_list().end(),
|
|
[sdl_window] (std::unique_ptr<osd_window> const &w)
|
|
{
|
|
return dynamic_cast<sdl_window_info &>(*w).platform_window() == sdl_window;
|
|
});
|
|
|
|
if (window == osd_common_t::window_list().end())
|
|
return nullptr;
|
|
|
|
return &static_cast<sdl_window_info &>(**window);
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
//============================================================
|
|
// SDL OSD interface
|
|
//============================================================
|
|
|
|
sdl_osd_interface::sdl_osd_interface(sdl_options &options) :
|
|
osd_common_t(options),
|
|
m_options(options),
|
|
m_focus_window(nullptr),
|
|
m_mouse_over_window(0),
|
|
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_enable_touch(false),
|
|
m_next_ptrdev(0)
|
|
{
|
|
}
|
|
|
|
|
|
sdl_osd_interface::~sdl_osd_interface()
|
|
{
|
|
}
|
|
|
|
|
|
void sdl_osd_interface::init(running_machine &machine)
|
|
{
|
|
// call our parent
|
|
osd_common_t::init(machine);
|
|
|
|
const char *stemp;
|
|
|
|
// determine if we are benchmarking, and adjust options appropriately
|
|
int bench = options().bench();
|
|
if (bench > 0)
|
|
{
|
|
options().set_value(OPTION_SLEEP, false, OPTION_PRIORITY_MAXIMUM);
|
|
options().set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM);
|
|
options().set_value(OSDOPTION_SOUND, "none", OPTION_PRIORITY_MAXIMUM);
|
|
options().set_value(OSDOPTION_VIDEO, "none", OPTION_PRIORITY_MAXIMUM);
|
|
options().set_value(OPTION_SECONDS_TO_RUN, bench, OPTION_PRIORITY_MAXIMUM);
|
|
}
|
|
|
|
// Some driver options - must be before audio init!
|
|
stemp = options().audio_driver();
|
|
if (stemp != nullptr && strcmp(stemp, OSDOPTVAL_AUTO) != 0)
|
|
{
|
|
osd_printf_verbose("Setting SDL audiodriver '%s' ...\n", stemp);
|
|
osd_setenv(SDLENV_AUDIODRIVER, stemp, 1);
|
|
}
|
|
|
|
stemp = options().video_driver();
|
|
if (stemp != nullptr && strcmp(stemp, OSDOPTVAL_AUTO) != 0)
|
|
{
|
|
osd_printf_verbose("Setting SDL videodriver '%s' ...\n", stemp);
|
|
osd_setenv(SDLENV_VIDEODRIVER, stemp, 1);
|
|
}
|
|
|
|
stemp = options().render_driver();
|
|
if (stemp != nullptr)
|
|
{
|
|
if (strcmp(stemp, OSDOPTVAL_AUTO) != 0)
|
|
{
|
|
osd_printf_verbose("Setting SDL renderdriver '%s' ...\n", stemp);
|
|
//osd_setenv(SDLENV_RENDERDRIVER, stemp, 1);
|
|
SDL_SetHint(SDL_HINT_RENDER_DRIVER, stemp);
|
|
}
|
|
else
|
|
{
|
|
#if defined(SDLMAME_WIN32)
|
|
// OpenGL renderer has less issues with mode switching on windows
|
|
osd_printf_verbose("Setting SDL renderdriver '%s' ...\n", "opengl");
|
|
//osd_setenv(SDLENV_RENDERDRIVER, stemp, 1);
|
|
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* Set the SDL environment variable for drivers wanting to load the
|
|
* lib at startup.
|
|
*/
|
|
#if USE_OPENGL
|
|
/* FIXME: move lib loading code from drawogl.c here */
|
|
|
|
stemp = options().gl_lib();
|
|
if (stemp != nullptr && strcmp(stemp, OSDOPTVAL_AUTO) != 0)
|
|
{
|
|
osd_setenv("SDL_VIDEO_GL_DRIVER", stemp, 1);
|
|
osd_printf_verbose("Setting SDL_VIDEO_GL_DRIVER = '%s' ...\n", stemp);
|
|
}
|
|
#endif
|
|
|
|
/* get number of processors */
|
|
stemp = options().numprocessors();
|
|
|
|
osd_num_processors = 0;
|
|
|
|
if (strcmp(stemp, "auto") != 0)
|
|
{
|
|
osd_num_processors = atoi(stemp);
|
|
if (osd_num_processors < 1)
|
|
{
|
|
osd_printf_warning("numprocessors < 1 doesn't make much sense. Assuming auto ...\n");
|
|
osd_num_processors = 0;
|
|
}
|
|
}
|
|
|
|
/* 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
|
|
/* Initialize SDL */
|
|
|
|
if (SDL_InitSubSystem(SDL_INIT_VIDEO))
|
|
{
|
|
osd_printf_error("Could not initialize SDL %s\n", SDL_GetError());
|
|
exit(-1);
|
|
}
|
|
|
|
osd_sdl_info();
|
|
|
|
defines_verbose();
|
|
|
|
osd_common_t::init_subsystems();
|
|
|
|
if (options().oslog())
|
|
{
|
|
using namespace std::placeholders;
|
|
machine.add_logerror_callback(std::bind(&sdl_osd_interface::output_oslog, this, _1));
|
|
}
|
|
|
|
|
|
|
|
#ifdef SDLMAME_EMSCRIPTEN
|
|
SDL_EventState(SDL_TEXTINPUT, SDL_FALSE);
|
|
#else
|
|
SDL_EventState(SDL_TEXTINPUT, SDL_TRUE);
|
|
#endif
|
|
}
|
|
|
|
|
|
void sdl_osd_interface::input_update(bool relative_reset)
|
|
{
|
|
process_events_buf();
|
|
poll_input_modules(relative_reset);
|
|
}
|
|
|
|
|
|
void sdl_osd_interface::customize_input_type_list(std::vector<input_type_entry> &typelist)
|
|
{
|
|
// loop over the defaults
|
|
for (input_type_entry &entry : typelist)
|
|
{
|
|
switch (entry.type())
|
|
{
|
|
// configurable UI mode switch
|
|
case IPT_UI_TOGGLE_UI:
|
|
{
|
|
char const *const uimode = options().ui_mode_key();
|
|
input_item_id mameid_code = ITEM_ID_INVALID;
|
|
if (!uimode || !*uimode || !strcmp(uimode, "auto"))
|
|
{
|
|
#if defined(__APPLE__) && defined(__MACH__)
|
|
mameid_code = keyboard_trans_table::instance().lookup_mame_code("ITEM_ID_INSERT");
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
std::string fullmode("ITEM_ID_");
|
|
fullmode.append(uimode);
|
|
mameid_code = keyboard_trans_table::instance().lookup_mame_code(fullmode.c_str());
|
|
}
|
|
if (ITEM_ID_INVALID != mameid_code)
|
|
{
|
|
input_code const ui_code = input_code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, input_item_id(mameid_code));
|
|
entry.defseq(SEQ_TYPE_STANDARD).set(ui_code);
|
|
}
|
|
}
|
|
break;
|
|
|
|
// alt-enter for fullscreen
|
|
case IPT_OSD_1:
|
|
entry.configure_osd("TOGGLE_FULLSCREEN", N_p("input-name", "Toggle Fullscreen"));
|
|
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_ENTER, KEYCODE_LALT);
|
|
break;
|
|
|
|
// page down for fastforward (must be OSD_3 as per src/emu/ui.c)
|
|
case IPT_UI_FAST_FORWARD:
|
|
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_PGDN);
|
|
break;
|
|
|
|
// 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
|
|
// LALT/LCTRL will still press/toggle these dipswitches.
|
|
|
|
// 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_F10, KEYCODE_LALT);
|
|
break;
|
|
|
|
// 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_F8, KEYCODE_LALT);
|
|
break;
|
|
|
|
// 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;
|
|
|
|
// 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_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)
|
|
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;
|
|
|
|
// disable the config menu if the ALT key is down
|
|
// (allows ALT-TAB to switch between apps)
|
|
case IPT_UI_MENU:
|
|
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_TAB, input_seq::not_code, KEYCODE_LALT, input_seq::not_code, KEYCODE_RALT);
|
|
break;
|
|
|
|
#if defined(__APPLE__) && defined(__MACH__)
|
|
// 78-key Apple MacBook & Bluetooth keyboards have no right control key
|
|
case IPT_MAHJONG_SCORE:
|
|
if (entry.player() == 0)
|
|
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_SLASH);
|
|
break;
|
|
#endif
|
|
|
|
// leave everything else alone
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void sdl_osd_interface::release_keys()
|
|
{
|
|
auto const keybd = dynamic_cast<input_module_base *>(m_keyboard_input);
|
|
if (keybd)
|
|
keybd->reset_devices();
|
|
}
|
|
|
|
|
|
bool sdl_osd_interface::should_hide_mouse()
|
|
{
|
|
// if the user toggled the pointer free, no
|
|
if (m_pointer_released)
|
|
return false;
|
|
|
|
// if we are paused, no
|
|
if (machine().paused())
|
|
return false;
|
|
|
|
// if neither mice nor lightguns are enabled in the core, then no
|
|
if (!options().mouse() && !options().lightgun())
|
|
return false;
|
|
|
|
if (!mouse_over_window())
|
|
return false;
|
|
|
|
// otherwise, yes
|
|
return true;
|
|
}
|
|
|
|
|
|
void sdl_osd_interface::process_events_buf()
|
|
{
|
|
SDL_PumpEvents();
|
|
}
|
|
|
|
|
|
void sdl_osd_interface::process_events()
|
|
{
|
|
std::lock_guard<std::mutex> lock(subscription_mutex());
|
|
SDL_Event event;
|
|
while (SDL_PollEvent(&event))
|
|
{
|
|
// handle UI events
|
|
switch (event.type)
|
|
{
|
|
case SDL_WINDOWEVENT:
|
|
process_window_event(event);
|
|
break;
|
|
|
|
case SDL_KEYDOWN:
|
|
if (event.key.keysym.scancode == SDL_SCANCODE_LCTRL)
|
|
m_modifier_keys |= MODIFIER_KEY_LCTRL;
|
|
else if (event.key.keysym.scancode == SDL_SCANCODE_RCTRL)
|
|
m_modifier_keys |= MODIFIER_KEY_RCTRL;
|
|
else if (event.key.keysym.scancode == SDL_SCANCODE_LSHIFT)
|
|
m_modifier_keys |= MODIFIER_KEY_LSHIFT;
|
|
else if (event.key.keysym.scancode == SDL_SCANCODE_RSHIFT)
|
|
m_modifier_keys |= MODIFIER_KEY_RSHIFT;
|
|
|
|
if (event.key.keysym.sym < 0x20)
|
|
{
|
|
// push control characters - they don't arrive as text input events
|
|
machine().ui_input().push_char_event(osd_common_t::window_list().front()->target(), event.key.keysym.sym);
|
|
}
|
|
else if (m_modifier_keys & MODIFIER_KEY_CTRL)
|
|
{
|
|
// SDL filters out control characters for text input, so they are decoded here
|
|
if (event.key.keysym.sym >= 0x40 && event.key.keysym.sym < 0x7f)
|
|
{
|
|
machine().ui_input().push_char_event(osd_common_t::window_list().front()->target(), event.key.keysym.sym & 0x1f);
|
|
}
|
|
else if (m_modifier_keys & MODIFIER_KEY_SHIFT)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SDL_KEYUP:
|
|
if (event.key.keysym.scancode == SDL_SCANCODE_LCTRL)
|
|
m_modifier_keys &= ~MODIFIER_KEY_LCTRL;
|
|
else if (event.key.keysym.scancode == SDL_SCANCODE_RCTRL)
|
|
m_modifier_keys &= ~MODIFIER_KEY_RCTRL;
|
|
else if (event.key.keysym.scancode == SDL_SCANCODE_LSHIFT)
|
|
m_modifier_keys &= ~MODIFIER_KEY_LSHIFT;
|
|
else if (event.key.keysym.scancode == SDL_SCANCODE_RSHIFT)
|
|
m_modifier_keys &= ~MODIFIER_KEY_RSHIFT;
|
|
break;
|
|
|
|
case SDL_TEXTINPUT:
|
|
process_textinput_event(event);
|
|
break;
|
|
|
|
case SDL_MOUSEMOTION:
|
|
if (!m_enable_touch || (SDL_TOUCH_MOUSEID != event.motion.which))
|
|
{
|
|
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:
|
|
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:
|
|
{
|
|
auto const window = window_from_id(event.wheel.windowID);
|
|
if (window)
|
|
{
|
|
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;
|
|
}
|
|
#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
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SDL_FINGERMOTION:
|
|
case SDL_FINGERDOWN:
|
|
case SDL_FINGERUP:
|
|
if (m_enable_touch && (SDL_MOUSE_TOUCHID != event.tfinger.touchId))
|
|
{
|
|
// 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;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
// let input modules do their thing
|
|
dispatch_event(event.type, event);
|
|
}
|
|
}
|
|
|
|
|
|
void sdl_osd_interface::osd_exit()
|
|
{
|
|
osd_common_t::osd_exit();
|
|
|
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
|
}
|
|
|
|
|
|
void sdl_osd_interface::output_oslog(const char *buffer)
|
|
{
|
|
fputs(buffer, stderr);
|
|
}
|
|
|
|
|
|
void sdl_osd_interface::process_window_event(SDL_Event const &event)
|
|
{
|
|
auto const window = window_from_id(event.window.windowID);
|
|
|
|
if (!window)
|
|
{
|
|
// This condition may occur when the fullscreen toggle is used
|
|
osd_printf_verbose("Skipped window event due to missing window param from SDL\n");
|
|
return;
|
|
}
|
|
|
|
switch (event.window.event)
|
|
{
|
|
case SDL_WINDOWEVENT_MOVED:
|
|
window->notify_changed();
|
|
m_focus_window = window;
|
|
break;
|
|
|
|
case SDL_WINDOWEVENT_RESIZED:
|
|
#ifdef SDLMAME_LINUX
|
|
/* FIXME: SDL2 sends some spurious resize events on Ubuntu
|
|
* while in fullscreen mode. Ignore them for now.
|
|
*/
|
|
if (!window->fullscreen())
|
|
#endif
|
|
{
|
|
//printf("event data1,data2 %d x %d %ld\n", event.window.data1, event.window.data2, sizeof(SDL_Event));
|
|
window->resize(event.window.data1, event.window.data2);
|
|
}
|
|
break;
|
|
|
|
case SDL_WINDOWEVENT_ENTER:
|
|
{
|
|
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:
|
|
{
|
|
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:
|
|
m_focus_window = window;
|
|
machine().ui_input().push_window_focus_event(window->target());
|
|
break;
|
|
|
|
case SDL_WINDOWEVENT_FOCUS_LOST:
|
|
if (window == m_focus_window)
|
|
m_focus_window = nullptr;
|
|
machine().ui_input().push_window_defocus_event(window->target());
|
|
break;
|
|
|
|
case SDL_WINDOWEVENT_CLOSE:
|
|
machine().schedule_exit();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void sdl_osd_interface::process_textinput_event(SDL_Event const &event)
|
|
{
|
|
if (*event.text.text)
|
|
{
|
|
auto const window = focus_window(event.text);
|
|
//printf("Focus window is %p - wl %p\n", window, osd_common_t::window_list().front().get());
|
|
if (window != nullptr)
|
|
{
|
|
auto ptr = event.text.text;
|
|
auto len = std::strlen(event.text.text);
|
|
while (len)
|
|
{
|
|
char32_t ch;
|
|
auto chlen = uchar_from_utf8(&ch, ptr, len);
|
|
if (0 > chlen)
|
|
{
|
|
ch = 0x0fffd;
|
|
chlen = 1;
|
|
}
|
|
ptr += chlen;
|
|
len -= chlen;
|
|
machine().ui_input().push_char_event(window->target(), ch);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void sdl_osd_interface::check_osd_inputs()
|
|
{
|
|
// check for toggling fullscreen mode (don't do this in debug mode)
|
|
if (machine().ui_input().pressed(IPT_OSD_1) && !(machine().debug_flags & DEBUG_FLAG_OSD_ENABLED))
|
|
{
|
|
// destroy the renderers first so that the render module can bounce if it depends on having a window handle
|
|
for (auto it = osd_common_t::window_list().rbegin(); osd_common_t::window_list().rend() != it; ++it)
|
|
(*it)->renderer_reset();
|
|
for (auto const &curwin : osd_common_t::window_list())
|
|
dynamic_cast<sdl_window_info &>(*curwin).toggle_full_screen();
|
|
}
|
|
|
|
auto const &window = osd_common_t::window_list().front();
|
|
|
|
if (USE_OPENGL)
|
|
{
|
|
// FIXME: on a per window basis
|
|
if (machine().ui_input().pressed(IPT_OSD_5))
|
|
{
|
|
video_config.filter = !video_config.filter;
|
|
machine().ui().popup_time(1, "Filter %s", video_config.filter? "enabled" : "disabled");
|
|
}
|
|
}
|
|
|
|
if (machine().ui_input().pressed(IPT_OSD_6))
|
|
dynamic_cast<sdl_window_info &>(*window).modify_prescale(-1);
|
|
|
|
if (machine().ui_input().pressed(IPT_OSD_7))
|
|
dynamic_cast<sdl_window_info &>(*window).modify_prescale(1);
|
|
|
|
if (machine().ui_input().pressed(IPT_OSD_8))
|
|
window->renderer().record();
|
|
|
|
// toggle releasing the pointer back to the OS
|
|
if (machine().ui_input().pressed(IPT_UI_RELEASE_POINTER))
|
|
toggle_pointer_release();
|
|
}
|
|
|
|
|
|
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 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;
|
|
}
|