diff options
Diffstat (limited to 'src/osd/windows')
-rw-r--r-- | src/osd/windows/ledutil.cpp | 6 | ||||
-rw-r--r-- | src/osd/windows/main.cpp | 34 | ||||
-rw-r--r-- | src/osd/windows/video.cpp | 129 | ||||
-rw-r--r-- | src/osd/windows/window.cpp | 1555 | ||||
-rw-r--r-- | src/osd/windows/window.h | 169 | ||||
-rw-r--r-- | src/osd/windows/winmain.cpp | 423 | ||||
-rw-r--r-- | src/osd/windows/winmain.h | 309 | ||||
-rw-r--r-- | src/osd/windows/winmenu.cpp | 33 | ||||
-rw-r--r-- | src/osd/windows/winopts.cpp | 157 | ||||
-rw-r--r-- | src/osd/windows/winopts.h | 232 | ||||
-rw-r--r-- | src/osd/windows/winutf8.cpp | 44 | ||||
-rw-r--r-- | src/osd/windows/winutil.cpp | 117 | ||||
-rw-r--r-- | src/osd/windows/winutil.h | 21 |
13 files changed, 1719 insertions, 1510 deletions
diff --git a/src/osd/windows/ledutil.cpp b/src/osd/windows/ledutil.cpp index 8f2a781b427..f1976cd41bc 100644 --- a/src/osd/windows/ledutil.cpp +++ b/src/osd/windows/ledutil.cpp @@ -34,9 +34,9 @@ // standard C headers #include <conio.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> +#include <cstdio> +#include <cstdlib> +#include <cstring> // MAME output header file typedef int running_machine; diff --git a/src/osd/windows/main.cpp b/src/osd/windows/main.cpp deleted file mode 100644 index 6d81d824f02..00000000000 --- a/src/osd/windows/main.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles -//============================================================ -// -// main.cpp - Win32 main program -// -//============================================================ - -// standard windows headers -#ifdef OSD_SDL -#define _WIN32_WINNT 0x0501 -#endif -#include <windows.h> -#include <tchar.h> -#include <stdlib.h> -#include <vector> -#include <string> - -#include "strconv.h" - -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - -#include "winmain.h" - -// The main function is only used to initialize our IFrameworkView class. -[Platform::MTAThread] -int main(Platform::Array<Platform::String^>^) -{ - auto app_source = ref new MameViewSource(); - Windows::ApplicationModel::Core::CoreApplication::Run(app_source); - return 0; -} - -#endif diff --git a/src/osd/windows/video.cpp b/src/osd/windows/video.cpp index 889e76caa6b..439f0019f69 100644 --- a/src/osd/windows/video.cpp +++ b/src/osd/windows/video.cpp @@ -6,12 +6,14 @@ // //============================================================ -// standard windows headers -#include <windows.h> +#include "modules/osdwindow.h" +#include "modules/monitor/monitor_module.h" +#include "modules/render/render_module.h" // MAME headers #include "emu.h" #include "emuopts.h" +#include "main.h" #include "render.h" #include "uiinput.h" @@ -20,7 +22,8 @@ #include "window.h" #include "strconv.h" -#include "modules/osdwindow.h" +// standard windows headers +#include <windows.h> //============================================================ // CONSTANTS @@ -57,14 +60,20 @@ bool windows_osd_interface::video_init() window_init(); // create the windows - windows_options &options = downcast<windows_options &>(machine().options()); + auto &options = downcast<windows_options &>(machine().options()); for (int index = 0; index < video_config.numscreens; index++) { - win_window_info::create(machine(), index, m_monitor_module->pick_monitor(options, index), &windows[index]); + auto window = win_window_info::create( + machine(), + *m_render, + index, + m_monitor_module->pick_monitor(options, index), + &windows[index]); + s_window_list.emplace_back(std::move(window)); } - if (video_config.mode != VIDEO_MODE_NONE) - SetForegroundWindow(std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window()); + if (m_render->is_interactive()) + SetForegroundWindow(dynamic_cast<win_window_info &>(*osd_common_t::s_window_list.front()).platform_window()); return true; } @@ -90,15 +99,11 @@ void windows_osd_interface::update(bool skip_redraw) if (!skip_redraw) { // profiler_mark(PROFILER_BLIT); - for (auto window : osd_common_t::s_window_list) + for (const auto &window : osd_common_t::s_window_list) window->update(); // profiler_mark(PROFILER_END); } - // poll the joystick values here - winwindow_process_events(machine(), true, false); - poll_input(machine()); - check_osd_inputs(); // if we're running, disable some parts of the debugger if ((machine().debug_flags & DEBUG_FLAG_OSD_ENABLED) != 0) debugger_update(); @@ -106,6 +111,17 @@ void windows_osd_interface::update(bool skip_redraw) //============================================================ +// input_update +//============================================================ + +void windows_osd_interface::input_update(bool relative_reset) +{ + // poll the joystick values here + process_events(true, false); + poll_input_modules(relative_reset); +} + +//============================================================ // check_osd_inputs //============================================================ @@ -136,13 +152,10 @@ void windows_osd_interface::check_osd_inputs() void windows_osd_interface::extract_video_config() { - const char *stemp; - // global options: extract the data video_config.windowed = options().window(); video_config.prescale = options().prescale(); video_config.filter = options().filter(); - video_config.keepaspect = options().keep_aspect(); video_config.numscreens = options().numscreens(); // if we are in debug mode, never go full screen @@ -156,100 +169,16 @@ void windows_osd_interface::extract_video_config() get_resolution(default_resolution, options().resolution(2), &windows[2], TRUE); get_resolution(default_resolution, options().resolution(3), &windows[3], TRUE); - // video options: extract the data - stemp = options().video(); - if (strcmp(stemp, "d3d") == 0) - video_config.mode = VIDEO_MODE_D3D; - else if (strcmp(stemp, "auto") == 0) - video_config.mode = VIDEO_MODE_D3D; - else if (strcmp(stemp, "gdi") == 0) - video_config.mode = VIDEO_MODE_GDI; - else if (strcmp(stemp, "bgfx") == 0) - video_config.mode = VIDEO_MODE_BGFX; - else if (strcmp(stemp, "none") == 0) - { - video_config.mode = VIDEO_MODE_NONE; - if (!emulator_info::standalone() && options().seconds_to_run() == 0) - osd_printf_warning("Warning: -video none doesn't make much sense without -seconds_to_run\n"); - } -#if (USE_OPENGL) - else if (strcmp(stemp, "opengl") == 0) - video_config.mode = VIDEO_MODE_OPENGL; -#endif - else - { - osd_printf_warning("Invalid video value %s; reverting to gdi\n", stemp); - video_config.mode = VIDEO_MODE_GDI; - } video_config.waitvsync = options().wait_vsync(); video_config.syncrefresh = options().sync_refresh(); video_config.triplebuf = options().triple_buffer(); video_config.switchres = options().switch_res(); - if (video_config.prescale < 1 || video_config.prescale > 3) + if (video_config.prescale < 1 || video_config.prescale > 20) { osd_printf_warning("Invalid prescale option, reverting to '1'\n"); video_config.prescale = 1; } - #if (USE_OPENGL) - // default to working video please - video_config.forcepow2texture = options().gl_force_pow2_texture(); - video_config.allowtexturerect = !(options().gl_no_texture_rect()); - video_config.vbo = options().gl_vbo(); - video_config.pbo = options().gl_pbo(); - video_config.glsl = options().gl_glsl(); - if ( video_config.glsl ) - { - int i; - - video_config.glsl_filter = options().glsl_filter(); - - video_config.glsl_shader_mamebm_num=0; - - for(i=0; i<GLSL_SHADER_MAX; i++) - { - stemp = options().shader_mame(i); - if (stemp && strcmp(stemp, OSDOPTVAL_NONE) != 0 && strlen(stemp)>0) - { - video_config.glsl_shader_mamebm[i] = (char *) malloc(strlen(stemp)+1); - strcpy(video_config.glsl_shader_mamebm[i], stemp); - video_config.glsl_shader_mamebm_num++; - } else { - video_config.glsl_shader_mamebm[i] = nullptr; - } - } - - video_config.glsl_shader_scrn_num=0; - - for(i=0; i<GLSL_SHADER_MAX; i++) - { - stemp = options().shader_screen(i); - if (stemp && strcmp(stemp, OSDOPTVAL_NONE) != 0 && strlen(stemp)>0) - { - video_config.glsl_shader_scrn[i] = (char *) malloc(strlen(stemp)+1); - strcpy(video_config.glsl_shader_scrn[i], stemp); - video_config.glsl_shader_scrn_num++; - } else { - video_config.glsl_shader_scrn[i] = nullptr; - } - } - } else { - int i; - video_config.glsl_filter = 0; - video_config.glsl_shader_mamebm_num=0; - for(i=0; i<GLSL_SHADER_MAX; i++) - { - video_config.glsl_shader_mamebm[i] = nullptr; - } - video_config.glsl_shader_scrn_num=0; - for(i=0; i<GLSL_SHADER_MAX; i++) - { - video_config.glsl_shader_scrn[i] = nullptr; - } - } - - #endif /* USE_OPENGL */ - } diff --git a/src/osd/windows/window.cpp b/src/osd/windows/window.cpp index 3794e79cd14..2759b32227f 100644 --- a/src/osd/windows/window.cpp +++ b/src/osd/windows/window.cpp @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Aaron Giles +// copyright-holders:Aaron Giles, Vas Crabb //============================================================ // // window.cpp - Win32 window handling @@ -8,17 +8,12 @@ #define LOG_TEMP_PAUSE 0 -// Needed for RAW Input -#define WM_INPUT 0x00FF - // standard C headers #include <process.h> +#include <algorithm> #include <atomic> #include <cstring> -#include <chrono> -#include <list> -#include <memory> // MAME headers #include "emu.h" @@ -36,23 +31,10 @@ #include "modules/monitor/monitor_common.h" -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#include <agile.h> -using namespace Windows::UI::Core; -#endif - -#include "modules/render/drawbgfx.h" -#include "modules/render/drawnone.h" -#include "modules/render/drawd3d.h" -#include "modules/render/drawgdi.h" -#if (USE_OPENGL) -#include "modules/render/drawogl.h" -#endif - -#define NOT_ALREADY_DOWN(x) (x & 0x40000000) == 0 +#define NOT_ALREADY_DOWN(x) ((x & 0x40000000) == 0) #define SCAN_CODE(x) ((x >> 16) & 0xff) -#define IS_EXTENDED(x) (0x01000000 & x) -#define MAKE_DI_SCAN(scan, isextended) (scan & 0x7f) | (isextended ? 0x80 : 0x00) +#define IS_EXTENDED(x) ((x >> 24) & 0x01) +#define MAKE_DI_SCAN(scan, isextended) ((scan & 0x7f) | (isextended ? 0x80 : 0x00)) #define WINOSD(machine) downcast<windows_osd_interface*>(&machine.osd()) //============================================================ @@ -72,7 +54,8 @@ using namespace Windows::UI::Core; #define FULLSCREEN_STYLE_EX WS_EX_TOPMOST // minimum window dimension -#define MIN_WINDOW_DIM 200 +#define MIN_WINDOW_DIMX 200 +#define MIN_WINDOW_DIMY 50 // custom window messages #define WM_USER_REDRAW (WM_USER + 2) @@ -81,6 +64,34 @@ using namespace Windows::UI::Core; #define WM_USER_SET_MINSIZE (WM_USER + 5) +namespace { + +// If legacy mouse to pointer event translation is enabled, translated +// WM_POINTER* events have pointer ID zero. Assume this will never be +// seen for "real" pointer events. +constexpr WORD MOUSE_POINTER_ID = 0; + +constexpr unsigned get_pointer_buttons(WPARAM wparam) +{ + return + (IS_POINTER_FIRSTBUTTON_WPARAM(wparam) ? 0x01 : 0x00) | + (IS_POINTER_SECONDBUTTON_WPARAM(wparam) ? 0x02 : 0x00) | + (IS_POINTER_THIRDBUTTON_WPARAM(wparam) ? 0x04 : 0x00) | + (IS_POINTER_FOURTHBUTTON_WPARAM(wparam) ? 0x08 : 0x00) | + (IS_POINTER_FIFTHBUTTON_WPARAM(wparam) ? 0x10 : 0x00); +} + +constexpr osd::ui_event_handler::pointer convert_pointer_type(POINTER_INPUT_TYPE type) +{ + // PT_POINTER isn't a real type, and we'll leave PT_TOUCHPAD as unknown for now + return + (PT_TOUCH == type) ? osd::ui_event_handler::pointer::TOUCH : + (PT_PEN == type) ? osd::ui_event_handler::pointer::PEN : + (PT_MOUSE == type) ? osd::ui_event_handler::pointer::MOUSE : + osd::ui_event_handler::pointer::UNKNOWN; +} + +} // anonymous namespace //============================================================ // GLOBAL VARIABLES @@ -95,8 +106,6 @@ static DWORD main_threadid; //============================================================ // event handling -static std::chrono::system_clock::time_point last_event_check; - static int ui_temp_pause; static int ui_temp_was_paused; @@ -116,7 +125,7 @@ static bool s_aggressive_focus; //============================================================ -static void create_window_class(void); +static void create_window_class(); //============================================================ // window_init @@ -139,111 +148,23 @@ bool windows_osd_interface::window_init() window_thread = GetCurrentThread(); window_threadid = main_threadid; - const int fallbacks[VIDEO_MODE_COUNT] = { - -1, // NONE -> no fallback - VIDEO_MODE_NONE, // GDI -> NONE - VIDEO_MODE_D3D, // BGFX -> D3D -#if (USE_OPENGL) - VIDEO_MODE_GDI, // OPENGL -> GDI -#endif - -1, // No SDL2ACCEL on Windows OSD -#if (USE_OPENGL) - VIDEO_MODE_OPENGL, // D3D -> OPENGL -#else - VIDEO_MODE_GDI, // D3D -> GDI -#endif - -1 // No SOFT on Windows OSD - }; - - int current_mode = video_config.mode; - while (current_mode != VIDEO_MODE_NONE) - { - bool error = false; - switch(current_mode) - { - case VIDEO_MODE_NONE: - error = renderer_none::init(machine()); - break; - case VIDEO_MODE_GDI: - error = renderer_gdi::init(machine()); - break; - case VIDEO_MODE_BGFX: - error = renderer_bgfx::init(machine()); - break; -#if (USE_OPENGL) - case VIDEO_MODE_OPENGL: - renderer_ogl::init(machine()); - break; -#endif - case VIDEO_MODE_SDL2ACCEL: - fatalerror("SDL2-Accel renderer unavailable on Windows OSD."); - break; - case VIDEO_MODE_D3D: - error = renderer_d3d9::init(machine()); - break; - case VIDEO_MODE_SOFT: - fatalerror("SDL1 renderer unavailable on Windows OSD."); - break; - default: - fatalerror("Unknown video mode."); - break; - } - if (error) - { - current_mode = fallbacks[current_mode]; - } - else - { - break; - } - } - video_config.mode = current_mode; - return true; } -void windows_osd_interface::update_slider_list() -{ - for (auto window : osd_common_t::s_window_list) - { - // check if any window has dirty sliders - if (window->has_renderer() && window->renderer().sliders_dirty()) - { - build_slider_list(); - return; - } - } -} int windows_osd_interface::window_count() { - return osd_common_t::s_window_list.size(); -} - -void windows_osd_interface::build_slider_list() -{ - m_sliders.clear(); - - for (auto window : osd_common_t::s_window_list) - { - if (window->has_renderer()) - { - // take the sliders of the first window - std::vector<ui::menu_item> window_sliders = window->renderer().get_slider_list(); - m_sliders.insert(m_sliders.end(), window_sliders.begin(), window_sliders.end()); - } - } + return osd_common_t::window_list().size(); } void windows_osd_interface::add_audio_to_recording(const int16_t *buffer, int samples_this_frame) { - auto window = osd_common_t::s_window_list.front(); // We only record on the first window - if (window != nullptr) - { + auto const &window = osd_common_t::window_list().front(); // We only record on the first window + if (window) window->renderer().add_audio_to_recording(buffer, samples_this_frame); - } } + //============================================================ // winwindow_exit // (main thread) @@ -260,76 +181,71 @@ void windows_osd_interface::window_exit() // free all the windows while (!osd_common_t::s_window_list.empty()) { - auto window = osd_common_t::s_window_list.front(); - - // Destroy removes it from the list also + auto window = std::move(osd_common_t::s_window_list.back()); + s_window_list.pop_back(); window->destroy(); } - switch(video_config.mode) - { - case VIDEO_MODE_NONE: - renderer_none::exit(); - break; - case VIDEO_MODE_GDI: - renderer_gdi::exit(); - break; - case VIDEO_MODE_BGFX: - renderer_bgfx::exit(); - break; -#if (USE_OPENGL) - case VIDEO_MODE_OPENGL: - renderer_ogl::exit(); - break; -#endif - case VIDEO_MODE_D3D: - renderer_d3d9::exit(); - break; - default: - break; - } - // kill the UI pause event if (ui_pause_event) CloseHandle(ui_pause_event); } + +inline win_window_info::win_pointer_info::win_pointer_info(WORD p, POINTER_INPUT_TYPE t, unsigned i, unsigned d) + : pointer_info(i, d) + , ptrid(p) + , type(t) +{ +} + + win_window_info::win_window_info( - running_machine &machine, - int index, - std::shared_ptr<osd_monitor_info> monitor, - const osd_window_config *config) : osd_window_t(*config), - m_next(nullptr), - m_init_state(0), - m_startmaximized(0), - m_isminimized(0), - m_ismaximized(0), - m_monitor(monitor), - m_fullscreen(!video_config.windowed), - m_fullscreen_safe(0), - m_aspect(0), - m_target(nullptr), - m_targetview(0), - m_targetorient(0), - m_lastclicktime(std::chrono::system_clock::time_point::min()), - m_lastclickx(0), - m_lastclicky(0), - m_machine(machine), - m_attached_mode(false) + running_machine &machine, + render_module &renderprovider, + int index, + const std::shared_ptr<osd_monitor_info> &monitor, + const osd_window_config *config) + : osd_window_t(machine, renderprovider, index, std::move(monitor), *config) + , m_init_state(0) + , m_startmaximized(0) + , m_isminimized(0) + , m_ismaximized(0) + , m_fullscreen_safe(0) + , m_aspect(0) + , m_targetview(0) + , m_targetorient(0) + , m_targetvismask(0) + , m_targetscalemode(0) + , m_targetkeepaspect(machine.options().keep_aspect()) + , m_lastclicktime(std::chrono::steady_clock::time_point::min()) + , m_lastclickx(0) + , m_lastclicky(0) + , m_last_surrogate(0) + , m_dc(nullptr) + , m_resize_state(RESIZE_STATE_NORMAL) + , m_main(nullptr) + , m_attached_mode(false) + , m_pointer_mask(0) + , m_next_pointer(0) + , m_next_ptrdev(0) + , m_tracking_mouse(false) { - memset(m_title,0,sizeof(m_title)); m_non_fullscreen_bounds.left = 0; m_non_fullscreen_bounds.top = 0; m_non_fullscreen_bounds.right = 0; m_non_fullscreen_bounds.bottom = 0; + + m_fullscreen = !video_config.windowed; m_prescale = video_config.prescale; - m_index = index; + + m_ptrdev_map.reserve(8); + m_ptrdev_info.reserve(1); + m_active_pointers.reserve(16); } POINT win_window_info::s_saved_cursor_pos = { -1, -1 }; -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - void win_window_info::capture_pointer() { RECT bounds; @@ -348,7 +264,7 @@ void win_window_info::hide_pointer() { GetCursorPos(&s_saved_cursor_pos); - while (ShowCursor(FALSE) >= -1) {}; + while (ShowCursor(FALSE) >= -1) { } ShowCursor(TRUE); } @@ -360,95 +276,104 @@ void win_window_info::show_pointer() s_saved_cursor_pos.x = s_saved_cursor_pos.y = -1; } - while (ShowCursor(TRUE) < 1) {}; + while (ShowCursor(TRUE) < 1) { } ShowCursor(FALSE); } -#else -CoreCursor^ win_window_info::s_cursor = nullptr; - -void win_window_info::capture_pointer() +bool windows_osd_interface::has_focus() const { - platform_window<Platform::Agile<CoreWindow^>>()->SetPointerCapture(); + return winwindow_has_focus(); } -void win_window_info::release_pointer() -{ - platform_window<Platform::Agile<CoreWindow^>>()->ReleasePointerCapture(); -} - -void win_window_info::hide_pointer() -{ - auto window = platform_window<Platform::Agile<CoreWindow^>>(); - win_window_info::s_cursor = window->PointerCursor; - window->PointerCursor = nullptr; -} - -void win_window_info::show_pointer() -{ - auto window = platform_window<Platform::Agile<CoreWindow^>>(); - window->PointerCursor = win_window_info::s_cursor; -} - -#endif //============================================================ // winwindow_process_events_periodic // (main thread) //============================================================ -void winwindow_process_events_periodic(running_machine &machine) +void windows_osd_interface::process_events() { - auto currticks = std::chrono::system_clock::now(); - assert(GetCurrentThreadId() == main_threadid); + auto const currticks = std::chrono::steady_clock::now(); + // update once every 1/8th of a second - if (currticks - last_event_check < std::chrono::milliseconds(1000 / 8)) + if (currticks < (m_last_event_check + std::chrono::milliseconds(1000 / 8))) return; - winwindow_process_events(machine, true, false); + + process_events(true, false); } //============================================================ +// winwindow_video_window_proc_ui +// (window thread) +//============================================================ + +static LRESULT CALLBACK winwindow_video_window_proc_ui(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam) +{ + return win_window_info::video_window_proc(wnd, message, wparam, lparam); +} + +//============================================================ // is_mame_window //============================================================ -static bool is_mame_window(HWND hwnd) +inline bool is_mame_window(HWND hwnd) { - for (auto window : osd_common_t::s_window_list) - if (std::static_pointer_cast<win_window_info>(window)->platform_window() == hwnd) + for (const auto &window : osd_common_t::window_list()) + if (dynamic_cast<win_window_info &>(*window).platform_window() == hwnd) return true; return false; } -inline static BOOL handle_mouse_button(windows_osd_interface *osd, int button, int down, int x, int y) +inline BOOL handle_mouse_button(windows_osd_interface &osd, int button, int down, LPARAM lparam) { - MouseButtonEventArgs args; - args.button = button; - args.keydown = down; - args.xpos = x; - args.ypos = y; + MouseUpdateEventArgs args; + args.pressed = (down ? 1 : 0) << button; + args.released = (down ? 0 : 1) << button; + args.vdelta = 0; + args.hdelta = 0; + args.xpos = GET_X_LPARAM(lparam); + args.ypos = GET_Y_LPARAM(lparam); - bool handled = osd->handle_input_event(INPUT_EVENT_MOUSE_BUTTON, &args); + bool const handled = osd.handle_input_event(INPUT_EVENT_MOUSE_BUTTON, &args); // When in lightgun mode or mouse mode, the mouse click may be routed to the input system // because the mouse interactions in the UI are routed from the video_window_proc below // we need to make sure they aren't suppressed in these cases. - return handled && !osd->options().lightgun() && !osd->options().mouse(); + return handled && !osd.options().lightgun() && !osd.options().mouse(); } -inline static BOOL handle_keypress(windows_osd_interface *osd, int vkey, int down, int scancode, BOOL extended_key) +inline BOOL handle_mouse_wheel(windows_osd_interface &osd, int v, int h, LPARAM lparam) +{ + MouseUpdateEventArgs args; + args.pressed = 0; + args.released = 0; + args.vdelta = v; + args.hdelta = h; + args.xpos = GET_X_LPARAM(lparam); + args.ypos = GET_Y_LPARAM(lparam); + + bool const handled = osd.handle_input_event(INPUT_EVENT_MOUSE_WHEEL, &args); + + // When in lightgun mode or mouse mode, the mouse wheel may be routed to the input system + // because the mouse interactions in the UI are routed from the video_window_proc below + // we need to make sure they aren't suppressed in these cases. + return handled && !osd.options().lightgun() && !osd.options().mouse(); +} + +inline BOOL handle_keypress(windows_osd_interface &osd, int vkey, int down, LPARAM lparam) { KeyPressEventArgs args; args.event_id = down ? INPUT_EVENT_KEYDOWN : INPUT_EVENT_KEYUP; - args.scancode = MAKE_DI_SCAN(scancode, extended_key); + args.scancode = MAKE_DI_SCAN(SCAN_CODE(lparam), IS_EXTENDED(lparam)); args.vkey = vkey; - return osd->handle_input_event(args.event_id, &args); + return osd.handle_input_event(args.event_id, &args); } //============================================================ @@ -456,14 +381,12 @@ inline static BOOL handle_keypress(windows_osd_interface *osd, int vkey, int dow // (main thread) //============================================================ -void winwindow_process_events(running_machine &machine, bool ingame, bool nodispatch) +void windows_osd_interface::process_events(bool ingame, bool nodispatch) { - MSG message; - assert(GetCurrentThreadId() == main_threadid); // remember the last time we did this - last_event_check = std::chrono::system_clock::now(); + m_last_event_check = std::chrono::steady_clock::now(); do { @@ -472,75 +395,87 @@ void winwindow_process_events(running_machine &machine, bool ingame, bool nodisp WaitMessage(); // loop over all messages in the queue + MSG message; while (PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) { // prevent debugger windows from getting messages during reset - int dispatch = TRUE && !nodispatch; + bool dispatch = !nodispatch; - if (message.hwnd == nullptr || is_mame_window(message.hwnd)) + if (!message.hwnd || is_mame_window(message.hwnd)) { - dispatch = TRUE; + dispatch = true; switch (message.message) { // ignore keyboard messages case WM_SYSKEYUP: case WM_SYSKEYDOWN: - dispatch = FALSE; + dispatch = false; break; // forward mouse button downs to the input system case WM_LBUTTONDOWN: - dispatch = !handle_mouse_button(WINOSD(machine), 0, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam)); + dispatch = !handle_mouse_button(*this, 0, TRUE, message.lParam); break; case WM_RBUTTONDOWN: - dispatch = !handle_mouse_button(WINOSD(machine), 1, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam)); + dispatch = !handle_mouse_button(*this, 1, TRUE, message.lParam); break; case WM_MBUTTONDOWN: - dispatch = !handle_mouse_button(WINOSD(machine), 2, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam)); + dispatch = !handle_mouse_button(*this, 2, TRUE, message.lParam); break; case WM_XBUTTONDOWN: - dispatch = !handle_mouse_button(WINOSD(machine), 3, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam)); + dispatch = !handle_mouse_button(*this, (GET_XBUTTON_WPARAM(message.wParam) == XBUTTON1) ? 3 : 4, TRUE, message.lParam); break; // forward mouse button ups to the input system case WM_LBUTTONUP: - dispatch = !handle_mouse_button(WINOSD(machine), 0, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam)); + dispatch = !handle_mouse_button(*this, 0, FALSE, message.lParam); break; case WM_RBUTTONUP: - dispatch = !handle_mouse_button(WINOSD(machine), 1, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam)); + dispatch = !handle_mouse_button(*this, 1, FALSE, message.lParam); break; case WM_MBUTTONUP: - dispatch = !handle_mouse_button(WINOSD(machine), 2, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam)); + dispatch = !handle_mouse_button(*this, 2, FALSE, message.lParam); break; case WM_XBUTTONUP: - dispatch = !handle_mouse_button(WINOSD(machine), 3, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam)); + dispatch = !handle_mouse_button(*this, (GET_XBUTTON_WPARAM(message.wParam) == XBUTTON1) ? 3 : 4, FALSE, message.lParam); + break; + + // forward mouse wheel movement to the input system + case WM_MOUSEWHEEL: + dispatch = !handle_mouse_wheel(*this, GET_WHEEL_DELTA_WPARAM(message.wParam), 0, message.lParam); break; + case WM_MOUSEHWHEEL: + dispatch = !handle_mouse_wheel(*this, 0, GET_WHEEL_DELTA_WPARAM(message.wParam), message.lParam); + break; + + // forward keystrokes to the input system case WM_KEYDOWN: if (NOT_ALREADY_DOWN(message.lParam)) - dispatch = !handle_keypress(WINOSD(machine), message.wParam, TRUE, SCAN_CODE(message.lParam), IS_EXTENDED(message.lParam)); + dispatch = !handle_keypress(*this, message.wParam, TRUE, message.lParam); break; case WM_KEYUP: - dispatch = !handle_keypress(WINOSD(machine), message.wParam, FALSE, SCAN_CODE(message.lParam), IS_EXTENDED(message.lParam)); + dispatch = !handle_keypress(*this, message.wParam, FALSE, message.lParam); break; } } // dispatch if necessary if (dispatch) - winwindow_dispatch_message(machine, &message); + winwindow_dispatch_message(machine(), message); } - } while (ui_temp_pause > 0); + } + while (ui_temp_pause > 0); // update the cursor state after processing events - winwindow_update_cursor_state(machine); + winwindow_update_cursor_state(machine()); } @@ -550,12 +485,12 @@ void winwindow_process_events(running_machine &machine, bool ingame, bool nodisp // (main thread) //============================================================ -void winwindow_dispatch_message(running_machine &machine, MSG *message) +void winwindow_dispatch_message(running_machine &machine, MSG const &message) { assert(GetCurrentThreadId() == main_threadid); // dispatch our special communication messages - switch (message->message) + switch (message.message) { // special case for quit case WM_QUIT: @@ -564,8 +499,8 @@ void winwindow_dispatch_message(running_machine &machine, MSG *message) // everything else dispatches normally default: - TranslateMessage(message); - DispatchMessage(message); + TranslateMessage(&message); + DispatchMessage(&message); break; } } @@ -577,15 +512,13 @@ void winwindow_dispatch_message(running_machine &machine, MSG *message) // (main thread) //============================================================ -void winwindow_take_snap(void) +void winwindow_take_snap() { assert(GetCurrentThreadId() == main_threadid); // iterate over windows and request a snap - for (auto window : osd_common_t::s_window_list) - { + for (const auto &window : osd_common_t::window_list()) window->renderer().save(); - } } @@ -595,15 +528,13 @@ void winwindow_take_snap(void) // (main thread) //============================================================ -void winwindow_toggle_fsfx(void) +void winwindow_toggle_fsfx() { assert(GetCurrentThreadId() == main_threadid); // iterate over windows and request a snap - for (auto window : osd_common_t::s_window_list) - { + for (const auto &window : osd_common_t::window_list()) window->renderer().toggle_fsfx(); - } } @@ -613,15 +544,13 @@ void winwindow_toggle_fsfx(void) // (main thread) //============================================================ -void winwindow_take_video(void) +void winwindow_take_video() { assert(GetCurrentThreadId() == main_threadid); // iterate over windows and request a snap - for (auto window : osd_common_t::s_window_list) - { + for (const auto &window : osd_common_t::window_list()) window->renderer().record(); - } } @@ -631,24 +560,36 @@ void winwindow_take_video(void) // (main thread) //============================================================ -void winwindow_toggle_full_screen(void) +void winwindow_toggle_full_screen() { assert(GetCurrentThreadId() == main_threadid); // if we are in debug mode, never go full screen - for (auto window : osd_common_t::s_window_list) + for (const auto &window : osd_common_t::window_list()) + { if (window->machine().debug_flags & DEBUG_FLAG_OSD_ENABLED) return; + } // toggle the window mode video_config.windowed = !video_config.windowed; + // 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(); + // iterate over windows and toggle their fullscreen state - for (auto window : osd_common_t::s_window_list) - SendMessage(std::static_pointer_cast<win_window_info>(window)->platform_window(), WM_USER_SET_FULLSCREEN, !video_config.windowed, 0); + for (const auto &window : osd_common_t::window_list()) + { + SendMessage( + dynamic_cast<win_window_info &>(*window).platform_window(), + WM_USER_SET_FULLSCREEN, + !video_config.windowed, + 0); + } // Set the first window as foreground - SetForegroundWindow(std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window()); + SetForegroundWindow(dynamic_cast<win_window_info &>(*osd_common_t::window_list().front()).platform_window()); } @@ -658,12 +599,12 @@ void winwindow_toggle_full_screen(void) // (main or window thread) //============================================================ -bool winwindow_has_focus(void) +bool winwindow_has_focus() { // see if one of the video windows has focus - for (auto window : osd_common_t::s_window_list) + for (const auto &window : osd_common_t::window_list()) { - switch (std::static_pointer_cast<win_window_info>(window)->focus()) + switch (dynamic_cast<win_window_info &>(*window).focus()) { case win_window_focus::NONE: break; @@ -704,34 +645,34 @@ void winwindow_update_cursor_state(running_machine &machine) assert(GetCurrentThreadId() == main_threadid); // If no windows, just return - if (osd_common_t::s_window_list.empty()) + if (osd_common_t::window_list().empty()) return; - auto window = osd_common_t::s_window_list.front(); + auto &window = static_cast<win_window_info &>(*osd_common_t::window_list().front()); // if we should hide the mouse cursor, then do it // rules are: // 1. we must have focus before hiding the cursor - // 2. we also hide the cursor in full screen mode and when tshe window doesn't have a menu + // 2. we also hide the cursor in full screen mode and when the window doesn't have a menu // 3. we also hide the cursor in windowed mode if we're not paused and // the input system requests it if (winwindow_has_focus() && ( - (window->fullscreen() && !window->win_has_menu()) + (window.fullscreen() && !GetMenu(window.platform_window())) || (!machine.paused() && WINOSD(machine)->should_hide_mouse()))) { // hide cursor - window->hide_pointer(); + window.hide_pointer(); // clip pointer to game video window - window->capture_pointer(); + window.capture_pointer(); } else { // show cursor - window->show_pointer(); + window.show_pointer(); // allow cursor to move freely - window->release_pointer(); + window.release_pointer(); } } @@ -742,21 +683,26 @@ void winwindow_update_cursor_state(running_machine &machine) // (main thread) //============================================================ -void win_window_info::create(running_machine &machine, int index, std::shared_ptr<osd_monitor_info> monitor, const osd_window_config *config) +std::unique_ptr<win_window_info> win_window_info::create( + running_machine &machine, + render_module &renderprovider, + int index, + const std::shared_ptr<osd_monitor_info> &monitor, + const osd_window_config *config) { assert(GetCurrentThreadId() == main_threadid); // allocate a new window object - auto window = std::make_shared<win_window_info>(machine, index, monitor, config); + auto window = std::make_unique<win_window_info>(machine, renderprovider, index, monitor, config); // set main window - if (window->m_index > 0) + if (window->index() > 0) { - for (auto w : osd_common_t::s_window_list) + for (const auto &w : osd_common_t::window_list()) { - if (w->m_index == 0) + if (w->index() == 0) { - window->set_main_window(std::static_pointer_cast<osd_window>(w)); + window->set_main_window(dynamic_cast<win_window_info &>(*w)); break; } } @@ -764,69 +710,33 @@ void win_window_info::create(running_machine &machine, int index, std::shared_pt else { // We must be the main window - window->set_main_window(window); + window->set_main_window(*window); } // see if we are safe for fullscreen window->m_fullscreen_safe = TRUE; - for (auto win : osd_common_t::s_window_list) + for (const auto &win : osd_common_t::window_list()) if (win->monitor() == monitor.get()) window->m_fullscreen_safe = FALSE; - // add us to the list - osd_common_t::s_window_list.push_back(window); - - // load the layout - window->m_target = machine.render().target_alloc(); - - // set the specific view - windows_options &options = downcast<windows_options &>(machine.options()); - - const char *defview = options.view(); - window->set_starting_view(index, defview, options.view(index)); + window->create_target(); // remember the current values in case they change - window->m_targetview = window->m_target->view(); - window->m_targetorient = window->m_target->orientation(); - window->m_targetlayerconfig = window->m_target->layer_config(); - - // make the window title - if (video_config.numscreens == 1) - sprintf(window->m_title, "%s: %s [%s]", emulator_info::get_appname(), machine.system().type.fullname(), machine.system().name); - else - sprintf(window->m_title, "%s: %s [%s] - Screen %d", emulator_info::get_appname(), machine.system().type.fullname(), machine.system().name, index); + window->m_targetview = window->target()->view(); + window->m_targetorient = window->target()->orientation(); + window->m_targetlayerconfig = window->target()->layer_config(); + window->m_targetvismask = window->target()->visibility_mask(); // set the initial maximized state - window->m_startmaximized = options.maximize(); + window->m_startmaximized = downcast<windows_options &>(machine.options()).maximize(); window->m_init_state = window->complete_create() ? -1 : 1; // handle error conditions if (window->m_init_state == -1) fatalerror("Unable to complete window creation\n"); -} - -std::shared_ptr<osd_monitor_info> win_window_info::monitor_from_rect(const osd_rect* proposed) const -{ - std::shared_ptr<osd_monitor_info> monitor; - // in window mode, find the nearest - if (!fullscreen()) - { - if (proposed != nullptr) - { - monitor = m_monitor->module().monitor_from_rect(*proposed); - } - else - monitor = m_monitor->module().monitor_from_window(*this); - } - else - { - // in full screen, just use the configured monitor - monitor = m_monitor; - } - - return monitor; + return window; } //============================================================ @@ -834,19 +744,13 @@ std::shared_ptr<osd_monitor_info> win_window_info::monitor_from_rect(const osd_r // (main thread) //============================================================ -void win_window_info::destroy() +void win_window_info::complete_destroy() { assert(GetCurrentThreadId() == main_threadid); - // remove us from the list - osd_common_t::s_window_list.remove(shared_from_this()); - // destroy the window if (platform_window() != nullptr) DestroyWindow(platform_window()); - - // free the render target - machine().render().target_free(m_target); } @@ -858,20 +762,24 @@ void win_window_info::destroy() void win_window_info::update() { - int targetview, targetorient; - render_layer_config targetlayerconfig; - assert(GetCurrentThreadId() == main_threadid); // see if the target has changed significantly in window mode - targetview = m_target->view(); - targetorient = m_target->orientation(); - targetlayerconfig = m_target->layer_config(); - if (targetview != m_targetview || targetorient != m_targetorient || targetlayerconfig != m_targetlayerconfig) + unsigned const targetview = target()->view(); + int const targetorient = target()->orientation(); + render_layer_config const targetlayerconfig = target()->layer_config(); + u32 const targetvismask = target()->visibility_mask(); + int const targetscalemode = target()->scale_mode(); + bool const targetkeepaspect = target()->keepaspect(); + if (targetview != m_targetview || targetorient != m_targetorient || targetlayerconfig != m_targetlayerconfig || targetvismask != m_targetvismask || + targetscalemode != m_targetscalemode || targetkeepaspect != m_targetkeepaspect) { m_targetview = targetview; m_targetorient = targetorient; m_targetlayerconfig = targetlayerconfig; + m_targetvismask = targetvismask; + m_targetscalemode = targetscalemode; + m_targetkeepaspect = targetkeepaspect; // in window mode, reminimize/maximize if (!fullscreen()) @@ -884,7 +792,7 @@ void win_window_info::update() } // if we're visible and running and not in the middle of a resize, draw - if (platform_window() != nullptr && m_target != nullptr && has_renderer()) + if (platform_window() != nullptr && target() != nullptr && has_renderer()) { bool got_lock = true; @@ -930,7 +838,7 @@ void win_window_info::update() // (main thread) //============================================================ -static void create_window_class(void) +static void create_window_class() { static int classes_created = FALSE; @@ -959,29 +867,6 @@ static void create_window_class(void) //============================================================ -// set_starting_view -// (main thread) -//============================================================ - -void win_window_info::set_starting_view(int index, const char *defview, const char *view) -{ - int viewindex; - - assert(GetCurrentThreadId() == main_threadid); - - // choose non-auto over auto - if (strcmp(view, "auto") == 0 && strcmp(defview, "auto") != 0) - view = defview; - - // query the video system to help us pick a view - viewindex = target()->configured_view(view, index, video_config.numscreens); - - // set the view - target()->set_view(viewindex); -} - - -//============================================================ // winwindow_ui_pause // (main thread) //============================================================ @@ -992,9 +877,10 @@ void winwindow_ui_pause(running_machine &machine, int pause) assert(GetCurrentThreadId() == main_threadid); - // if we're pausing, increment the pause counter if (pause) { + // if we're pausing, increment the pause counter + // if we're the first to pause, we have to actually initiate it if (ui_temp_pause++ == 0) { @@ -1006,10 +892,10 @@ void winwindow_ui_pause(running_machine &machine, int pause) SetEvent(ui_pause_event); } } - - // if we're resuming, decrement the pause counter else { + // if we're resuming, decrement the pause counter + // if we're the last to resume, unpause MAME if (--ui_temp_pause == 0) { @@ -1048,7 +934,7 @@ int win_window_info::wnd_extra_width() RECT temprect = { 100, 100, 200, 200 }; if (fullscreen()) return 0; - AdjustWindowRectEx(&temprect, WINDOW_STYLE, win_has_menu(), WINDOW_STYLE_EX); + AdjustWindowRectEx(&temprect, WINDOW_STYLE, GetMenu(platform_window()) ? true : false, WINDOW_STYLE_EX); return rect_width(&temprect) - 100; } @@ -1064,7 +950,7 @@ int win_window_info::wnd_extra_height() RECT temprect = { 100, 100, 200, 200 }; if (fullscreen()) return 0; - AdjustWindowRectEx(&temprect, WINDOW_STYLE, win_has_menu(), WINDOW_STYLE_EX); + AdjustWindowRectEx(&temprect, WINDOW_STYLE, GetMenu(platform_window()) ? true : false, WINDOW_STYLE_EX); return rect_height(&temprect) - 100; } @@ -1078,20 +964,12 @@ int win_window_info::complete_create() { RECT client; int tempwidth, tempheight; - HMENU menu = nullptr; HDC dc; assert(GetCurrentThreadId() == window_threadid); // get the monitor bounds - osd_rect monitorbounds = m_monitor->position_size(); - - // create the window menu if needed - if (downcast<windows_options &>(machine().options()).menu()) - { - if (win_create_menu(machine(), &menu)) - return 1; - } + osd_rect monitorbounds = monitor()->position_size(); // are we in worker UI mode? HWND hwnd; @@ -1108,16 +986,16 @@ int win_window_info::complete_create() { // create the window, but don't show it yet hwnd = win_create_window_ex_utf8( - fullscreen() ? FULLSCREEN_STYLE_EX : WINDOW_STYLE_EX, - "MAME", - m_title, - fullscreen() ? FULLSCREEN_STYLE : WINDOW_STYLE, - monitorbounds.left() + 20, monitorbounds.top() + 20, - monitorbounds.left() + 100, monitorbounds.top() + 100, - nullptr,//(osd_common_t::s_window_list != nullptr) ? osd_common_t::s_window_list->m_hwnd : nullptr, - menu, - GetModuleHandleUni(), - nullptr); + fullscreen() ? FULLSCREEN_STYLE_EX : WINDOW_STYLE_EX, + "MAME", + title().c_str(), + fullscreen() ? FULLSCREEN_STYLE : WINDOW_STYLE, + monitorbounds.left() + 20, monitorbounds.top() + 20, + monitorbounds.left() + 100, monitorbounds.top() + 100, + nullptr,//(osd_common_t::s_window_list != nullptr) ? osd_common_t::s_window_list->m_hwnd : nullptr, + nullptr, + GetModuleHandleUni(), + nullptr); } if (hwnd == nullptr) @@ -1130,10 +1008,11 @@ int win_window_info::complete_create() SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this); // skip the positioning stuff for '-video none' or '-attach_window' - if (video_config.mode == VIDEO_MODE_NONE || attached_mode()) + if (!renderer_interactive() || attached_mode()) { - set_renderer(osd_renderer::make_for_type(video_config.mode, shared_from_this())); - renderer().create(); + renderer_create(); + if (renderer().create()) + return 1; return 0; } @@ -1155,7 +1034,7 @@ int win_window_info::complete_create() // show the window if (!fullscreen() || m_fullscreen_safe) { - set_renderer(osd_renderer::make_for_type(video_config.mode, shared_from_this())); + renderer_create(); if (renderer().create()) return 1; @@ -1180,10 +1059,10 @@ int win_window_info::complete_create() LRESULT CALLBACK win_window_info::video_window_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam) { LONG_PTR ptr = GetWindowLongPtr(wnd, GWLP_USERDATA); - win_window_info *window = (win_window_info *)ptr; + auto *window = (win_window_info *)ptr; // we may get called before SetWindowLongPtr is called - if (window != nullptr) + if (window) { assert(GetCurrentThreadId() == window_threadid); window->update_minmax_state(); @@ -1192,118 +1071,178 @@ LRESULT CALLBACK win_window_info::video_window_proc(HWND wnd, UINT message, WPAR // handle a few messages switch (message) { - // paint: redraw the last bitmap - case WM_PAINT: + // paint: redraw the last bitmap + case WM_PAINT: { PAINTSTRUCT pstruct; HDC hdc = BeginPaint(wnd, &pstruct); window->draw_video_contents(hdc, true); - if (window->win_has_menu()) + if (GetMenu(window->platform_window())) DrawMenuBar(window->platform_window()); EndPaint(wnd, &pstruct); - break; } + break; - // non-client paint: punt if full screen - case WM_NCPAINT: - if (!window->fullscreen() || window->win_has_menu()) - return DefWindowProc(wnd, message, wparam, lparam); - break; + // non-client paint: punt if full screen + case WM_NCPAINT: + if (!window->fullscreen() || GetMenu(window->platform_window())) + return DefWindowProc(wnd, message, wparam, lparam); + break; - // input: handle the raw input - case WM_INPUT: - downcast<windows_osd_interface&>(window->machine().osd()).handle_input_event(INPUT_EVENT_RAWINPUT, &lparam); + // input device change: handle RawInput device connection/disconnection + case WM_INPUT_DEVICE_CHANGE: + switch (wparam) + { + case GIDC_ARRIVAL: + downcast<windows_osd_interface&>(window->machine().osd()).handle_input_event(INPUT_EVENT_ARRIVAL, &lparam); break; - - // syskeys - ignore - case WM_SYSKEYUP: - case WM_SYSKEYDOWN: + case GIDC_REMOVAL: + downcast<windows_osd_interface&>(window->machine().osd()).handle_input_event(INPUT_EVENT_REMOVAL, &lparam); break; + default: + return DefWindowProc(wnd, message, wparam, lparam); + } + break; - // input events - case WM_MOUSEMOVE: - window->machine().ui_input().push_mouse_move_event(window->m_target, GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam)); - break; + // input: handle the raw input + case WM_INPUT: + downcast<windows_osd_interface&>(window->machine().osd()).handle_input_event(INPUT_EVENT_RAWINPUT, &lparam); + break; - case WM_MOUSELEAVE: - window->machine().ui_input().push_mouse_leave_event(window->m_target); - break; + // syskeys - ignore + case WM_SYSKEYUP: + case WM_SYSKEYDOWN: + break; - case WM_LBUTTONDOWN: + // text input events + case WM_CHAR: { - auto ticks = std::chrono::system_clock::now(); - window->machine().ui_input().push_mouse_down_event(window->m_target, GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam)); - - // check for a double-click - if (ticks - window->m_lastclicktime < std::chrono::milliseconds(GetDoubleClickTime()) && - GET_X_LPARAM(lparam) >= window->m_lastclickx - 4 && GET_X_LPARAM(lparam) <= window->m_lastclickx + 4 && - GET_Y_LPARAM(lparam) >= window->m_lastclicky - 4 && GET_Y_LPARAM(lparam) <= window->m_lastclicky + 4) + char16_t const ch = char16_t(wparam); + if ((0xd800 <= ch) && (0xdbff >= ch)) { - window->m_lastclicktime = std::chrono::system_clock::time_point::min(); - window->machine().ui_input().push_mouse_double_click_event(window->m_target, GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam)); + window->m_last_surrogate = ch; + } + else if ((0xdc00 <= ch) && (0xdfff >= ch)) + { + if (window->m_last_surrogate) + { + char32_t const uch = 0x10000 + ((ch & 0x03ff) | ((window->m_last_surrogate & 0x03ff) << 10)); + window->machine().ui_input().push_char_event(window->target(), uch); + } + window->m_last_surrogate = 0; } else { - window->m_lastclicktime = ticks; - window->m_lastclickx = GET_X_LPARAM(lparam); - window->m_lastclicky = GET_Y_LPARAM(lparam); + window->machine().ui_input().push_char_event(window->target(), char32_t(ch)); + window->m_last_surrogate = 0; } - break; } + break; - case WM_LBUTTONUP: - window->machine().ui_input().push_mouse_up_event(window->m_target, GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam)); - break; - - case WM_RBUTTONDOWN: - window->machine().ui_input().push_mouse_rdown_event(window->m_target, GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam)); - break; - - case WM_RBUTTONUP: - window->machine().ui_input().push_mouse_rup_event(window->m_target, GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam)); - break; - - case WM_CHAR: - window->machine().ui_input().push_char_event(window->m_target, (char32_t) wparam); - break; - - case WM_MOUSEWHEEL: + case WM_UNICHAR: + if (UNICODE_NOCHAR == wparam) + return TRUE; + else + window->machine().ui_input().push_char_event(window->target(), char32_t(wparam)); + break; + + // legacy mouse events + case WM_MOUSEMOVE: + window->mouse_updated(wparam, lparam); + break; + + case WM_MOUSELEAVE: + window->mouse_left(wparam, lparam); + break; + + case WM_LBUTTONDOWN: + window->mouse_updated(wparam, lparam); + break; + + case WM_LBUTTONUP: + window->mouse_updated(wparam, lparam); + break; + + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + window->mouse_updated(wparam, lparam); + break; + + case WM_XBUTTONDOWN: + case WM_XBUTTONUP: + window->mouse_updated(wparam, lparam); + return TRUE; + + case WM_MOUSEWHEEL: { + POINT where{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) }; + ScreenToClient(wnd, &where); UINT ucNumLines = 3; // default SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &ucNumLines, 0); - window->machine().ui_input().push_mouse_wheel_event(window->m_target, GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam), GET_WHEEL_DELTA_WPARAM(wparam), ucNumLines); - break; + window->machine().ui_input().push_mouse_wheel_event(window->target(), where.x, where.y, GET_WHEEL_DELTA_WPARAM(wparam), ucNumLines); } - - // pause the system when we start a menu or resize - case WM_ENTERSIZEMOVE: - window->m_resize_state = RESIZE_STATE_RESIZING; - case WM_ENTERMENULOOP: - winwindow_ui_pause(window->machine(), TRUE); - break; - - // unpause the system when we stop a menu or resize and force a redraw - case WM_EXITSIZEMOVE: - window->m_resize_state = RESIZE_STATE_PENDING; - case WM_EXITMENULOOP: - winwindow_ui_pause(window->machine(), FALSE); - InvalidateRect(wnd, nullptr, FALSE); - break; - - // get min/max info: set the minimum window size - case WM_GETMINMAXINFO: + break; + + // new-style pointer handling (mouse/pen/touch) + case WM_POINTERENTER: + window->pointer_entered(wparam, lparam); + break; + case WM_POINTERLEAVE: + window->pointer_left(wparam, lparam); + break; + case WM_POINTERDOWN: + case WM_POINTERUP: + case WM_POINTERUPDATE: + window->pointer_updated(wparam, lparam); + break; + case WM_POINTERCAPTURECHANGED: + window->pointer_capture_changed(wparam, lparam); + break; + // TODO: other pointer events? + //case WM_POINTERACTIVATE: + //case WM_POINTERDEVICECHANGE: + //case WM_POINTERDEVICEINRANGE: + //case WM_POINTERDEVICEOUTOFRANGE: + //case WM_POINTERROUTEDAWAY: + //case WM_POINTERROUTEDRELEASED: + //case WM_POINTERROUTEDTO: + //case WM_POINTERWHEEL: + //case WM_POINTERHWHEEL: + + // pause the system when we start a menu or resize + case WM_ENTERSIZEMOVE: + window->m_resize_state = RESIZE_STATE_RESIZING; + [[fallthrough]]; + case WM_ENTERMENULOOP: + winwindow_ui_pause(window->machine(), TRUE); + break; + + // unpause the system when we stop a menu or resize and force a redraw + case WM_EXITSIZEMOVE: + window->m_resize_state = RESIZE_STATE_PENDING; + [[fallthrough]]; + case WM_EXITMENULOOP: + winwindow_ui_pause(window->machine(), FALSE); + InvalidateRect(wnd, nullptr, FALSE); + break; + + // get min/max info: set the minimum window size + case WM_GETMINMAXINFO: { - MINMAXINFO *minmax = (MINMAXINFO *)lparam; - minmax->ptMinTrackSize.x = MIN_WINDOW_DIM; - minmax->ptMinTrackSize.y = MIN_WINDOW_DIM; + auto *minmax = (MINMAXINFO *)lparam; + minmax->ptMinTrackSize.x = MIN_WINDOW_DIMX; + minmax->ptMinTrackSize.y = MIN_WINDOW_DIMY; break; } + break; - // sizing: constrain to the aspect ratio unless control key is held down - case WM_SIZING: + // sizing: constrain to the aspect ratio unless control key is held down + case WM_SIZING: { RECT *rect = (RECT *)lparam; - if (video_config.keepaspect && !(GetAsyncKeyState(VK_CONTROL) & 0x8000)) + if (window->keepaspect() && (window->target()->scale_mode() == SCALE_FRACTIONAL) && !(GetAsyncKeyState(VK_CONTROL) & 0x8000)) { osd_rect r = window->constrain_to_aspect_ratio(RECT_to_osd_rect(*rect), wparam); rect->top = r.top(); @@ -1312,11 +1251,11 @@ LRESULT CALLBACK win_window_info::video_window_proc(HWND wnd, UINT message, WPAR rect->right = r.right(); } InvalidateRect(wnd, nullptr, FALSE); - break; } + break; - // syscommands: catch win_start_maximized - case WM_SYSCOMMAND: + // syscommands: catch win_start_maximized + case WM_SYSCOMMAND: { uint16_t cmd = wparam & 0xfff0; @@ -1337,22 +1276,46 @@ LRESULT CALLBACK win_window_info::video_window_proc(HWND wnd, UINT message, WPAR window->maximize_window(); break; } - return DefWindowProc(wnd, message, wparam, lparam); } + return DefWindowProc(wnd, message, wparam, lparam); - // close: cause MAME to exit - case WM_CLOSE: - window->machine().schedule_exit(); - break; + case WM_ACTIVATE: + if (window->has_renderer()) + { + if (window->fullscreen()) + { + if ((wparam == WA_ACTIVE) || (wparam == WA_CLICKACTIVE)) + { + for (const auto &w : osd_common_t::window_list()) + ShowWindow(dynamic_cast<win_window_info &>(*w).platform_window(), SW_RESTORE); + } + else if ((wparam == WA_INACTIVE) && !is_mame_window(HWND(lparam))) + { + for (const auto &w : osd_common_t::window_list()) + ShowWindow(dynamic_cast<win_window_info &>(*w).platform_window(), SW_MINIMIZE); + } + } - // destroy: clean up all attached rendering bits and nullptr out our hwnd - case WM_DESTROY: - window->renderer_reset(); - window->set_platform_window(nullptr); - return DefWindowProc(wnd, message, wparam, lparam); + if ((wparam == WA_ACTIVE) || (wparam == WA_CLICKACTIVE)) + window->machine().ui_input().push_window_focus_event(window->target()); + else if (wparam == WA_INACTIVE) + window->machine().ui_input().push_window_defocus_event(window->target()); + } + return DefWindowProc(wnd, message, wparam, lparam); + + // close: cause MAME to exit + case WM_CLOSE: + window->machine().schedule_exit(); + break; - // self redraw: draw ourself in a non-painty way - case WM_USER_REDRAW: + // destroy: clean up all attached rendering bits and nullptr out our hwnd + case WM_DESTROY: + window->renderer_reset(); + window->set_platform_window(nullptr); + return DefWindowProc(wnd, message, wparam, lparam); + + // self redraw: draw ourself in a non-painty way + case WM_USER_REDRAW: { HDC hdc = GetDC(wnd); @@ -1360,46 +1323,46 @@ LRESULT CALLBACK win_window_info::video_window_proc(HWND wnd, UINT message, WPAR window->draw_video_contents(hdc, false); ReleaseDC(wnd, hdc); - break; } - - // fullscreen set - case WM_USER_SET_FULLSCREEN: - window->set_fullscreen(wparam); - break; - - // minimum size set - case WM_USER_SET_MINSIZE: - window->minimize_window(); - break; - - // maximum size set - case WM_USER_SET_MAXSIZE: - window->maximize_window(); - break; - - // maximum size set - case WM_DISPLAYCHANGE: - /* FIXME: The current codebase has an issue with setting aspect - * ratios correctly after display change. set_aspect should - * be set_forced_aspect and on a refresh this forced aspect should - * be preserved if set. If not, the standard aspect calculation - * should be used. - */ - window->m_monitor->refresh(); - window->m_monitor->update_resolution(LOWORD(lparam), HIWORD(lparam)); - break; - - // set focus: if we're not the primary window, switch back - // commented out ATM because this prevents us from resizing secondary windows -// case WM_SETFOCUS: -// if (window != osd_common_t::s_window_list && osd_common_t::s_window_list != nullptr) -// SetFocus(osd_common_t::s_window_list->m_hwnd); -// break; - - // everything else: defaults - default: - return DefWindowProc(wnd, message, wparam, lparam); + break; + + // fullscreen set + case WM_USER_SET_FULLSCREEN: + window->set_fullscreen(wparam); + break; + + // minimum size set + case WM_USER_SET_MINSIZE: + window->minimize_window(); + break; + + // maximum size set + case WM_USER_SET_MAXSIZE: + window->maximize_window(); + break; + + // maximum size set + case WM_DISPLAYCHANGE: + /* FIXME: The current codebase has an issue with setting aspect + * ratios correctly after display change. set_aspect should + * be set_forced_aspect and on a refresh this forced aspect should + * be preserved if set. If not, the standard aspect calculation + * should be used. + */ + window->monitor()->refresh(); + window->monitor()->update_resolution(LOWORD(lparam), HIWORD(lparam)); + break; + + // set focus: if we're not the primary window, switch back + // commented out ATM because this prevents us from resizing secondary windows +// case WM_SETFOCUS: +// if (window != osd_common_t::s_window_list && osd_common_t::s_window_list != nullptr) +// SetFocus(osd_common_t::s_window_list->m_hwnd); +// break; + + // everything else: defaults + default: + return DefWindowProc(wnd, message, wparam, lparam); } return 0; @@ -1434,7 +1397,10 @@ void win_window_info::draw_video_contents(HDC dc, bool update) { // update DC m_dc = dc; - renderer().draw(update); + if (has_renderer()) + { + renderer().draw(update); + } } } } @@ -1465,10 +1431,6 @@ osd_rect win_window_info::constrain_to_aspect_ratio(const osd_rect &rect, int ad if (monitor == nullptr) return rect; - // do not constrain aspect ratio for integer scaled views - if (m_target->scale_mode() != SCALE_FRACTIONAL) - return rect; - // get the pixel aspect ratio for the target monitor pixel_aspect = monitor->pixel_aspect(); @@ -1482,29 +1444,21 @@ osd_rect win_window_info::constrain_to_aspect_ratio(const osd_rect &rect, int ad { case WMSZ_BOTTOM: case WMSZ_TOP: - m_target->compute_visible_area(10000, propheight, pixel_aspect, m_target->orientation(), propwidth, propheight); + target()->compute_visible_area(10000, propheight, pixel_aspect, target()->orientation(), propwidth, propheight); break; case WMSZ_LEFT: case WMSZ_RIGHT: - m_target->compute_visible_area(propwidth, 10000, pixel_aspect, m_target->orientation(), propwidth, propheight); + target()->compute_visible_area(propwidth, 10000, pixel_aspect, target()->orientation(), propwidth, propheight); break; default: - m_target->compute_visible_area(propwidth, propheight, pixel_aspect, m_target->orientation(), propwidth, propheight); + target()->compute_visible_area(propwidth, propheight, pixel_aspect, target()->orientation(), propwidth, propheight); break; } // get the minimum width/height for the current layout - m_target->compute_minimum_size(minwidth, minheight); - - // clamp against the absolute minimum - propwidth = std::max(propwidth, MIN_WINDOW_DIM); - propheight = std::max(propheight, MIN_WINDOW_DIM); - - // clamp against the minimum width and height - propwidth = std::max(propwidth, minwidth); - propheight = std::max(propheight, minheight); + target()->compute_minimum_size(minwidth, minheight); // clamp against the maximum (fit on one screen for full screen mode) if (fullscreen()) @@ -1517,19 +1471,35 @@ osd_rect win_window_info::constrain_to_aspect_ratio(const osd_rect &rect, int ad maxwidth = monitor->usuable_position_size().width() - extrawidth; maxheight = monitor->usuable_position_size().height() - extraheight; - // further clamp to the maximum width/height in the window + // clamp minimum against half of maximum to allow resizing very large targets (eg. SVG screen) + minwidth = std::min(minwidth, maxwidth / 2); + minheight = std::min(minheight, maxheight / 2); + + // clamp maximum to the maximum width/height in the window if (m_win_config.width != 0) maxwidth = std::min(maxwidth, m_win_config.width + extrawidth); if (m_win_config.height != 0) maxheight = std::min(maxheight, m_win_config.height + extraheight); } + // clamp against the absolute minimum + propwidth = std::max(propwidth, MIN_WINDOW_DIMX); + propheight = std::max(propheight, MIN_WINDOW_DIMY); + + // clamp against the minimum width and height + propwidth = std::max(propwidth, minwidth); + propheight = std::max(propheight, minheight); + // clamp to the maximum propwidth = std::min(propwidth, maxwidth); propheight = std::min(propheight, maxheight); // compute the visible area based on the proposed rectangle - m_target->compute_visible_area(propwidth, propheight, pixel_aspect, m_target->orientation(), viswidth, visheight); + target()->compute_visible_area(propwidth, propheight, pixel_aspect, target()->orientation(), viswidth, visheight); + + // clamp visable area to the proposed rectangle + viswidth = std::min(viswidth, propwidth); + visheight = std::min(visheight, propheight); // compute the adjustments we need to make adjwidth = (viswidth + extrawidth) - rect.width(); @@ -1577,20 +1547,26 @@ osd_dim win_window_info::get_min_bounds(int constrain) //assert(GetCurrentThreadId() == window_threadid); // get the minimum target size - m_target->compute_minimum_size(minwidth, minheight); + target()->compute_minimum_size(minwidth, minheight); + + // check if visible area is bigger + int32_t viswidth, visheight; + target()->compute_visible_area(minwidth, minheight, monitor()->aspect(), target()->orientation(), viswidth, visheight); + minwidth = std::max(viswidth, minwidth); + minheight = std::max(visheight, minheight); // expand to our minimum dimensions - if (minwidth < MIN_WINDOW_DIM) - minwidth = MIN_WINDOW_DIM; - if (minheight < MIN_WINDOW_DIM) - minheight = MIN_WINDOW_DIM; + if (minwidth < MIN_WINDOW_DIMX) + minwidth = MIN_WINDOW_DIMX; + if (minheight < MIN_WINDOW_DIMY) + minheight = MIN_WINDOW_DIMY; // account for extra window stuff minwidth += wnd_extra_width(); minheight += wnd_extra_height(); // if we want it constrained, figure out which one is larger - if (constrain && m_target->scale_mode() == SCALE_FRACTIONAL) + if (constrain) { // first constrain with no height limit osd_rect test1(0,0,minwidth,10000); @@ -1628,8 +1604,8 @@ osd_dim win_window_info::get_max_bounds(int constrain) //assert(GetCurrentThreadId() == window_threadid); // compute the maximum client area - //m_monitor->refresh(); - osd_rect maximum = m_monitor->usuable_position_size(); + //monitor()->refresh(); + osd_rect maximum = monitor()->usuable_position_size(); // clamp to the window's max int tempw = maximum.width(); @@ -1650,7 +1626,7 @@ osd_dim win_window_info::get_max_bounds(int constrain) maximum = maximum.resize(tempw, temph); // constrain to fit - if (constrain && m_target->scale_mode() == SCALE_FRACTIONAL) + if (constrain) maximum = constrain_to_aspect_ratio(maximum, WMSZ_BOTTOMRIGHT); return maximum.dim(); @@ -1672,8 +1648,9 @@ void win_window_info::update_minmax_state() RECT bounds; // compare the maximum bounds versus the current bounds - osd_dim minbounds = get_min_bounds(video_config.keepaspect); - osd_dim maxbounds = get_max_bounds(video_config.keepaspect); + const bool keep_aspect = keepaspect(); + osd_dim minbounds = get_min_bounds(keep_aspect); + osd_dim maxbounds = get_max_bounds(keep_aspect); GetWindowRect(platform_window(), &bounds); // if either the width or height matches, we were maximized @@ -1681,6 +1658,10 @@ void win_window_info::update_minmax_state() (rect_height(&bounds) == minbounds.height()); m_ismaximized = (rect_width(&bounds) == maxbounds.width()) || (rect_height(&bounds) == maxbounds.height()); + + // We can't be maximized and minimized simultaneously + if (m_ismaximized) + m_isminimized = FALSE; } else { @@ -1700,7 +1681,7 @@ void win_window_info::minimize_window() { assert(GetCurrentThreadId() == window_threadid); - osd_dim newsize = get_min_bounds(video_config.keepaspect); + osd_dim newsize = get_min_bounds(keepaspect()); // get the window rect RECT bounds; @@ -1723,10 +1704,10 @@ void win_window_info::maximize_window() { assert(GetCurrentThreadId() == window_threadid); - osd_dim newsize = get_max_bounds(video_config.keepaspect); + osd_dim newsize = get_max_bounds(keepaspect()); // center within the work area - osd_rect work = m_monitor->usuable_position_size(); + osd_rect work = monitor()->usuable_position_size(); osd_rect newrect = osd_rect(work.left() + (work.width() - newsize.width()) / 2, work.top() + (work.height() - newsize.height()) / 2, newsize); @@ -1755,8 +1736,28 @@ void win_window_info::adjust_window_position_after_major_change() if (!fullscreen()) { // constrain the existing size to the aspect ratio - if (video_config.keepaspect) + if (keepaspect()) newrect = constrain_to_aspect_ratio(newrect, WMSZ_BOTTOMRIGHT); + + // restrict the window to one monitor and avoid toolbars if possible + HMONITOR const nearest_monitor = MonitorFromWindow(platform_window(), MONITOR_DEFAULTTONEAREST); + if (NULL != nearest_monitor) + { + MONITORINFO info; + std::memset(&info, 0, sizeof(info)); + info.cbSize = sizeof(info); + if (GetMonitorInfo(nearest_monitor, &info)) + { + if (newrect.right() > info.rcWork.right) + newrect = newrect.move_by(info.rcWork.right - newrect.right(), 0); + if (newrect.bottom() > info.rcWork.bottom) + newrect = newrect.move_by(0, info.rcWork.bottom - newrect.bottom()); + if (newrect.left() < info.rcWork.left) + newrect = newrect.move_by(info.rcWork.left - newrect.left(), 0); + if (newrect.top() < info.rcWork.top) + newrect = newrect.move_by(0, info.rcWork.top - newrect.top()); + } + } } else { @@ -1765,26 +1766,6 @@ void win_window_info::adjust_window_position_after_major_change() newrect = monitor->position_size(); } - // restrict the window to one monitor and avoid toolbars if possible - HMONITOR const nearest_monitor = MonitorFromWindow(platform_window(), MONITOR_DEFAULTTONEAREST); - if (NULL != nearest_monitor) - { - MONITORINFO info; - std::memset(&info, 0, sizeof(info)); - info.cbSize = sizeof(info); - if (GetMonitorInfo(nearest_monitor, &info)) - { - if (newrect.right() > info.rcWork.right) - newrect = newrect.move_by(info.rcWork.right - newrect.right(), 0); - if (newrect.bottom() > info.rcWork.bottom) - newrect = newrect.move_by(0, info.rcWork.bottom - newrect.bottom()); - if (newrect.left() < info.rcWork.left) - newrect = newrect.move_by(info.rcWork.left - newrect.left(), 0); - if (newrect.top() < info.rcWork.top) - newrect = newrect.move_by(0, info.rcWork.top - newrect.top()); - } - } - // adjust the position if different if (RECT_to_osd_rect(oldrect) != newrect) SetWindowPos(platform_window(), fullscreen() ? HWND_TOPMOST : HWND_TOP, @@ -1792,7 +1773,7 @@ void win_window_info::adjust_window_position_after_major_change() newrect.width(), newrect.height(), 0); // take note of physical window size (used for lightgun coordinate calculation) - if (m_index == 0) + if (index() == 0) osd_printf_verbose("Physical width %d, height %d\n", newrect.width(), newrect.height()); } @@ -1811,18 +1792,16 @@ void win_window_info::set_fullscreen(int fullscreen) return; m_fullscreen = fullscreen; - // reset UI to main menu - machine().ui().menu_reset(); - - // kill off the drawers + // kill off the renderer renderer_reset(); // hide ourself ShowWindow(platform_window(), SW_HIDE); - // configure the window if non-fullscreen if (!fullscreen) { + // configure the window if non-fullscreen + // adjust the style SetWindowLong(platform_window(), GWL_STYLE, WINDOW_STYLE); SetWindowLong(platform_window(), GWL_EXSTYLE, WINDOW_STYLE_EX); @@ -1843,14 +1822,14 @@ void win_window_info::set_fullscreen(int fullscreen) // otherwise, set a small size and maximize from there else { - SetWindowPos(platform_window(), HWND_TOP, 0, 0, MIN_WINDOW_DIM, MIN_WINDOW_DIM, SWP_NOZORDER); + SetWindowPos(platform_window(), HWND_TOP, 0, 0, MIN_WINDOW_DIMX, MIN_WINDOW_DIMY, SWP_NOZORDER); maximize_window(); } } - - // configure the window if fullscreen else { + // configure the window if fullscreen + // save the bounds GetWindowRect(platform_window(), &m_non_fullscreen_bounds); @@ -1869,12 +1848,12 @@ void win_window_info::set_fullscreen(int fullscreen) // show ourself if (!this->fullscreen() || m_fullscreen_safe) { - if (video_config.mode != VIDEO_MODE_NONE) + if (renderer_interactive()) ShowWindow(platform_window(), SW_SHOW); - set_renderer(osd_renderer::make_for_type(video_config.mode, shared_from_this())); + renderer_create(); if (renderer().create()) - exit(1); + exit(1); // FIXME: better error handling than just silently exiting on failure } // ensure we're still adjusted correctly @@ -1918,24 +1897,412 @@ win_window_focus win_window_info::focus() const } +void win_window_info::pointer_entered(WPARAM wparam, LPARAM lparam) +{ + assert(!IS_POINTER_CANCELED_WPARAM(wparam)); + auto const info(map_pointer(wparam)); + if (m_active_pointers.end() != info) + { + POINT where{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) }; + ScreenToClient(platform_window(), &where); + info->x = where.x; + info->y = where.y; + machine().ui_input().push_pointer_update( + target(), + convert_pointer_type(info->type), + info->index, + info->device, + where.x, where.y, + 0U, 0U, 0U, 0U); + } +} + +void win_window_info::pointer_left(WPARAM wparam, LPARAM lparam) +{ + auto const info(find_pointer(wparam)); + if (m_active_pointers.end() != info) + { + bool const canceled(IS_POINTER_CANCELED_WPARAM(wparam)); + POINT where{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) }; + ScreenToClient(platform_window(), &where); + expire_pointer(info, where, canceled); + } +} + +void win_window_info::pointer_updated(WPARAM wparam, LPARAM lparam) +{ + bool const canceled(IS_POINTER_CANCELED_WPARAM(wparam)); + auto const info(canceled ? find_pointer(wparam) : map_pointer(wparam)); + if (m_active_pointers.end() != info) + { + POINT where{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) }; + ScreenToClient(platform_window(), &where); + unsigned const buttons(canceled ? 0 : get_pointer_buttons(wparam)); + update_pointer(*info, where, buttons, canceled); + } +} + +void win_window_info::pointer_capture_changed(WPARAM wparam, LPARAM lparam) +{ + auto const info(find_pointer(wparam)); + if (m_active_pointers.end() != info) + { + // treat this as the pointer being stolen - fail any gestures + if (BIT(info->buttons, 0) && (0 < info->clickcnt)) + info->clickcnt = -info->clickcnt; + + // push to UI manager and dump pointer data + machine().ui_input().push_pointer_abort( + target(), + convert_pointer_type(info->type), + info->index, + info->device, + info->x, info->y, + info->buttons, info->clickcnt); + 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 win_window_info::mouse_left(WPARAM wparam, LPARAM lparam) +{ + m_tracking_mouse = false; + auto const info(find_mouse_pointer()); + if (m_active_pointers.end() != info) + { + POINT where{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) }; + expire_pointer(info, where, false); + } +} + +void win_window_info::mouse_updated(WPARAM wparam, LPARAM lparam) +{ + auto const info(map_mouse_pointer()); + if (m_active_pointers.end() == info) + return; + + POINT const where{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) }; + unsigned const buttons( + ((MK_LBUTTON & wparam) ? 0x01 : 0x00) | + ((MK_RBUTTON & wparam) ? 0x02 : 0x00) | + ((MK_MBUTTON & wparam) ? 0x04 : 0x00) | + ((MK_XBUTTON1 & wparam) ? 0x08 : 0x00) | + ((MK_XBUTTON2 & wparam) ? 0x10 : 0x00)); + + // continue to track the mouse outside the window if buttons are down + if (buttons && !info->buttons) + { + SetCapture(platform_window()); + + TRACKMOUSEEVENT tm; + std::memset(&tm, 0, sizeof(tm)); + tm.cbSize = sizeof(tm); + tm.dwFlags = TME_CANCEL | TME_LEAVE; + tm.hwndTrack = platform_window(); + TrackMouseEvent(&tm); + m_tracking_mouse = false; + } + else + { + if (!buttons && info->buttons) + { + if (GetCapture() == platform_window()) + ReleaseCapture(); + } + + if (!m_tracking_mouse) + { + TRACKMOUSEEVENT tm; + std::memset(&tm, 0, sizeof(tm)); + tm.cbSize = sizeof(tm); + tm.dwFlags = TME_LEAVE; + tm.hwndTrack = platform_window(); + TrackMouseEvent(&tm); + m_tracking_mouse = true; + } + } + + update_pointer(*info, where, buttons, false); +} + +void win_window_info::expire_pointer(std::vector<win_pointer_info>::iterator info, POINT const &where, bool canceled) +{ + // leaving implicitly releases buttons, so check hold/drag if necessary + if (BIT(info->buttons, 0) && (0 < info->clickcnt)) + { + if (!canceled) + { + auto const now(std::chrono::steady_clock::now()); + auto const exp(std::chrono::milliseconds(GetDoubleClickTime()) + info->pressed); + int const dx(where.x - info->pressedx); + int const dy(where.y - info->pressedy); + int const distance((dx * dx) + (dy * dy)); + int const tolerance((PT_TOUCH == info->type) ? TAP_DISTANCE : CLICK_DISTANCE); + if ((exp < now) || (tolerance < distance)) + info->clickcnt = -info->clickcnt; + } + else + { + info->clickcnt = -info->clickcnt; + } + } + + // need to remember touches to recognise multi-tap gestures + if (!canceled && (PT_TOUCH == info->type) && (0 < info->clickcnt)) + { + auto const now(std::chrono::steady_clock::now()); + auto const time = std::chrono::milliseconds(GetDoubleClickTime()); + if ((time + info->pressed) >= now) + { + try + { + unsigned i(0); + if (m_ptrdev_info.size() > info->device) + i = m_ptrdev_info[info->device].clear_expired_touches(now, time); + else + m_ptrdev_info.resize(info->device + 1); + + if (std::size(m_ptrdev_info[info->device].touches) > i) + { + m_ptrdev_info[info->device].touches[i].when = info->pressed; + m_ptrdev_info[info->device].touches[i].x = info->pressedx; + m_ptrdev_info[info->device].touches[i].y = info->pressedy; + m_ptrdev_info[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 and dump pointer data + if (!canceled) + { + machine().ui_input().push_pointer_leave( + target(), + convert_pointer_type(info->type), + info->index, + info->device, + where.x, where.y, + info->buttons, info->clickcnt); + } + else + { + machine().ui_input().push_pointer_abort( + target(), + convert_pointer_type(info->type), + info->index, + info->device, + where.x, where.y, + info->buttons, info->clickcnt); + } + 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 win_window_info::update_pointer(win_pointer_info &info, POINT const &where, unsigned buttons, bool canceled) +{ + if (!canceled && (where.x == info.x) && (where.y == info.y) && (buttons == info.buttons)) + return; + + // detect multi-click actions + unsigned const pressed(canceled ? 0 : (buttons & ~info.buttons)); + unsigned const released(canceled ? ~info.buttons : (~buttons & info.buttons)); + if (BIT(pressed, 0)) + { + info.primary_down( + where.x, where.y, + std::chrono::milliseconds(GetDoubleClickTime()), + (PT_TOUCH == info.type) ? TAP_DISTANCE : CLICK_DISTANCE, + PT_TOUCH == info.type, + m_ptrdev_info); + } + else if (BIT(info.buttons, 0)) + { + info.check_primary_hold_drag( + where.x, where.y, + std::chrono::milliseconds(GetDoubleClickTime()), + (PT_TOUCH == info.type) ? TAP_DISTANCE : CLICK_DISTANCE); + } + + // update info and push to UI manager + info.x = where.x; + info.y = where.y; + info.buttons = buttons; + if (!canceled) + { + machine().ui_input().push_pointer_update( + target(), + convert_pointer_type(info.type), + info.index, + info.device, + where.x, where.y, + buttons, pressed, released, info.clickcnt); + } + else + { + machine().ui_input().push_pointer_abort( + target(), + convert_pointer_type(info.type), + info.index, + info.device, + where.x, where.y, + released, info.clickcnt); + } +} + +std::vector<win_window_info::win_pointer_info>::iterator win_window_info::map_pointer(WPARAM wparam) +{ + WORD const ptrid(GET_POINTERID_WPARAM(wparam)); + auto found(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), ptrid, &win_pointer_info::compare)); + if ((m_active_pointers.end() != found) && (found->ptrid == ptrid)) + return found; + + if ((sizeof(m_next_pointer) * 8) <= m_next_pointer) + { + assert(~decltype(m_pointer_mask)(0) == m_pointer_mask); + osd_printf_warning("win_window_info: exceeded maximum number of active pointers\n"); + return m_active_pointers.end(); + } + assert(!BIT(m_pointer_mask, m_next_pointer)); + + POINTER_INFO info = { 0 }; + if (!OSD_DYNAMIC_CALL(GetPointerInfo, ptrid, &info)) + { + osd_printf_error("win_window_info: failed to get info for pointer ID %u\n", ptrid); + return m_active_pointers.end(); + } + + auto devpos(std::lower_bound( + m_ptrdev_map.begin(), + m_ptrdev_map.end(), + info.sourceDevice, + [] (std::pair<HANDLE, unsigned> const &mapping, HANDLE device) + { + return mapping.first < device; + })); + + try + { + if ((m_ptrdev_map.end() == devpos) || (devpos->first != info.sourceDevice)) + { + devpos = m_ptrdev_map.emplace(devpos, info.sourceDevice, m_next_ptrdev); + ++m_next_ptrdev; + } + + found = m_active_pointers.emplace( + found, + win_pointer_info(ptrid, info.pointerType, m_next_pointer, devpos->second)); + 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("win_window_info: error allocating pointer data\n"); + return m_active_pointers.end(); + } +} + +std::vector<win_window_info::win_pointer_info>::iterator win_window_info::find_pointer(WPARAM wparam) +{ + WORD const ptrid(GET_POINTERID_WPARAM(wparam)); + auto const found(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), ptrid, &win_pointer_info::compare)); + if ((m_active_pointers.end() != found) && (found->ptrid == ptrid)) + return found; + else + return m_active_pointers.end(); +} + +std::vector<win_window_info::win_pointer_info>::iterator win_window_info::map_mouse_pointer() +{ + auto found(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), MOUSE_POINTER_ID, &win_pointer_info::compare)); + if ((m_active_pointers.end() != found) && (found->ptrid == MOUSE_POINTER_ID)) + return found; + + if ((sizeof(m_next_pointer) * 8) <= m_next_pointer) + { + assert(~decltype(m_pointer_mask)(0) == m_pointer_mask); + osd_printf_warning("win_window_info: exceeded maximum number of active pointers\n"); + return m_active_pointers.end(); + } + assert(!BIT(m_pointer_mask, m_next_pointer)); + + auto devpos(std::lower_bound( + m_ptrdev_map.begin(), + m_ptrdev_map.end(), + INVALID_HANDLE_VALUE, + [] (std::pair<HANDLE, unsigned> const &mapping, HANDLE device) + { + return mapping.first < device; + })); + + try + { + if ((m_ptrdev_map.end() == devpos) || (devpos->first != INVALID_HANDLE_VALUE)) + { + devpos = m_ptrdev_map.emplace(devpos, INVALID_HANDLE_VALUE, m_next_ptrdev); + ++m_next_ptrdev; + } + + found = m_active_pointers.emplace( + found, + win_pointer_info(MOUSE_POINTER_ID, PT_MOUSE, m_next_pointer, devpos->second)); + 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("win_window_info: error allocating pointer data\n"); + return m_active_pointers.end(); + } +} + +std::vector<win_window_info::win_pointer_info>::iterator win_window_info::find_mouse_pointer() +{ + auto const found(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), MOUSE_POINTER_ID, &win_pointer_info::compare)); + if ((m_active_pointers.end() != found) && (found->ptrid == MOUSE_POINTER_ID)) + return found; + else + return m_active_pointers.end(); +} + + +#if (USE_QTDEBUG) //============================================================ // winwindow_qt_filter //============================================================ -#if (USE_QTDEBUG) bool winwindow_qt_filter(void *message) { - MSG *msg = (MSG *)message; + MSG *const msg = reinterpret_cast<MSG *>(message); - if(is_mame_window(msg->hwnd) || (!msg->hwnd && (msg->message >= WM_USER))) + if (is_mame_window(msg->hwnd) || (!msg->hwnd && (msg->message >= WM_USER))) { LONG_PTR ptr; - if(msg->hwnd) // get the machine associated with this window + if (msg->hwnd) // get the machine associated with this window ptr = GetWindowLongPtr(msg->hwnd, GWLP_USERDATA); else // any one will have to do - ptr = (LONG_PTR)osd_common_t::s_window_list.front().get(); + ptr = (LONG_PTR)osd_common_t::window_list().front().get(); - winwindow_dispatch_message(((win_window_info *)ptr)->machine(), msg); + winwindow_dispatch_message(reinterpret_cast<win_window_info *>(ptr)->machine(), *msg); return true; } return false; diff --git a/src/osd/windows/window.h b/src/osd/windows/window.h index b04e35aa110..ada71f1cba7 100644 --- a/src/osd/windows/window.h +++ b/src/osd/windows/window.h @@ -1,40 +1,38 @@ // license:BSD-3-Clause -// copyright-holders:Aaron Giles +// copyright-holders:Aaron Giles, Vas Crabb //============================================================ // // window.h - Win32 window handling // //============================================================ +#ifndef MAME_OSD_WINDOWS_WINDOW_H +#define MAME_OSD_WINDOWS_WINDOW_H -#ifndef __WIN_WINDOW__ -#define __WIN_WINDOW__ - -// standard windows headers -#include <windows.h> -#include <windowsx.h> -#include <mmsystem.h> - -#include <chrono> -#include <mutex> -#include <memory> -#include <list> +#pragma once +#include "emucore.h" #include "render.h" #include "modules/osdwindow.h" +#include "modules/lib/osdlib.h" -//============================================================ -// PARAMETERS -//============================================================ +#include <chrono> +#include <list> +#include <memory> +#include <mutex> +#include <utility> +#include <vector> + +// standard windows headers +#include <windows.h> +#include <windowsx.h> +#include <mmsystem.h> //============================================================ // CONSTANTS //============================================================ -#define RESIZE_STATE_NORMAL 0 -#define RESIZE_STATE_RESIZING 1 -#define RESIZE_STATE_PENDING 2 @@ -53,49 +51,45 @@ enum class win_window_focus class win_window_info : public osd_window_t<HWND> { public: - win_window_info(running_machine &machine, int index, std::shared_ptr<osd_monitor_info> monitor, const osd_window_config *config); + enum + { + RESIZE_STATE_NORMAL, + RESIZE_STATE_RESIZING, + RESIZE_STATE_PENDING + }; - running_machine &machine() const override { return m_machine; } + win_window_info(running_machine &machine, render_module &renderprovider, int index, const std::shared_ptr<osd_monitor_info> &monitor, const osd_window_config *config); - virtual render_target *target() override { return m_target; } - int fullscreen() const override { return m_fullscreen; } bool attached_mode() const { return m_attached_mode; } win_window_focus focus() const; void update() override; - virtual bool win_has_menu() override - { -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - return GetMenu(platform_window()) ? true : false; -#else - return false; -#endif - } - virtual osd_dim get_size() override { -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) RECT client; GetClientRect(platform_window(), &client); return osd_dim(client.right - client.left, client.bottom - client.top); -#else - throw ref new Platform::NotImplementedException(); -#endif } + win_window_info *main_window() const { return m_main; } + void set_main_window(win_window_info &main) { m_main = &main; } + void capture_pointer() override; void release_pointer() override; void show_pointer() override; void hide_pointer() override; - virtual osd_monitor_info *monitor() const override { return m_monitor.get(); } - - void destroy() override; + void complete_destroy() override; // static - static void create(running_machine &machine, int index, std::shared_ptr<osd_monitor_info> monitor, const osd_window_config *config); + static std::unique_ptr<win_window_info> create( + running_machine &machine, + render_module &renderprovider, + int index, + const std::shared_ptr<osd_monitor_info> &monitor, + const osd_window_config *config); // static callbacks @@ -103,38 +97,54 @@ public: // member variables - win_window_info * m_next; volatile int m_init_state; // window handle and info - char m_title[256]; RECT m_non_fullscreen_bounds; int m_startmaximized; int m_isminimized; int m_ismaximized; // monitor info - std::shared_ptr<osd_monitor_info> m_monitor; - int m_fullscreen; - int m_fullscreen_safe; - float m_aspect; + int m_fullscreen_safe; + float m_aspect; // rendering info std::mutex m_render_lock; - render_target * m_target; - int m_targetview; + unsigned m_targetview; int m_targetorient; render_layer_config m_targetlayerconfig; + u32 m_targetvismask; + int m_targetscalemode; + bool m_targetkeepaspect; // input info - std::chrono::system_clock::time_point m_lastclicktime; - int m_lastclickx; - int m_lastclicky; + std::chrono::steady_clock::time_point m_lastclicktime; + int m_lastclickx; + int m_lastclicky; + char16_t m_last_surrogate; + + HDC m_dc; // only used by GDI renderer! + int m_resize_state; private: + struct win_pointer_info : public pointer_info + { + static constexpr bool compare(win_pointer_info const &info, WORD ptrid) { return info.ptrid < ptrid; } + + win_pointer_info(win_pointer_info const &) = default; + win_pointer_info(win_pointer_info &&) = default; + win_pointer_info &operator=(win_pointer_info const &) = default; + win_pointer_info &operator=(win_pointer_info &&) = default; + + win_pointer_info(WORD p, POINTER_INPUT_TYPE t, unsigned i, unsigned d); + + WORD ptrid; + POINTER_INPUT_TYPE type; + }; + void draw_video_contents(HDC dc, bool update); int complete_create(); - void set_starting_view(int index, const char *defview, const char *view); int wnd_extra_width(); int wnd_extra_height(); osd_rect constrain_to_aspect_ratio(const osd_rect &rect, int adjustment); @@ -145,22 +155,40 @@ private: void maximize_window(); void adjust_window_position_after_major_change(); void set_fullscreen(int fullscreen); - std::shared_ptr<osd_monitor_info> monitor_from_rect(const osd_rect* proposed) const; - static POINT s_saved_cursor_pos; - -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - static Windows::UI::Core::CoreCursor^ s_cursor; -#endif - - running_machine & m_machine; + // pointer handling helpers + void pointer_entered(WPARAM wparam, LPARAM lparam); + void pointer_left(WPARAM wparam, LPARAM lparam); + void pointer_updated(WPARAM wparam, LPARAM lparam); + void pointer_capture_changed(WPARAM wparam, LPARAM lparam); + void mouse_left(WPARAM wparam, LPARAM lparam); + void mouse_updated(WPARAM wparam, LPARAM lparam); + void expire_pointer(std::vector<win_pointer_info>::iterator info, POINT const &where, bool canceled); + void update_pointer(win_pointer_info &info, POINT const &where, unsigned buttons, bool canceled); + std::vector<win_pointer_info>::iterator map_pointer(WPARAM wparam); + std::vector<win_pointer_info>::iterator find_pointer(WPARAM wparam); + std::vector<win_pointer_info>::iterator map_mouse_pointer(); + std::vector<win_pointer_info>::iterator find_mouse_pointer(); + + win_window_info * m_main; bool m_attached_mode; -}; -struct osd_draw_callbacks -{ - osd_renderer *(*create)(osd_window *window); - void (*exit)(void); + // these functions first appear in Windows 8/Server 2012 + OSD_DYNAMIC_API(user32, "User32.dll", "User32.dll"); + OSD_DYNAMIC_API_FN(user32, BOOL, WINAPI, GetPointerType, UINT32, POINTER_INPUT_TYPE *); + OSD_DYNAMIC_API_FN(user32, BOOL, WINAPI, GetPointerInfo, UINT32, POINTER_INFO *); + OSD_DYNAMIC_API_FN(user32, BOOL, WINAPI, GetPointerPenInfo, UINT32, POINTER_PEN_INFO *); + OSD_DYNAMIC_API_FN(user32, BOOL, WINAPI, GetPointerTouchInfo, UINT32, POINTER_TOUCH_INFO *); + + // info on currently active pointers - 64 pointers ought to be enough for anyone + uint64_t m_pointer_mask; + unsigned m_next_pointer, m_next_ptrdev; + bool m_tracking_mouse; + std::vector<std::pair<HANDLE, unsigned> > m_ptrdev_map; + std::vector<pointer_dev_info> m_ptrdev_info; + std::vector<win_pointer_info> m_active_pointers; + + static POINT s_saved_cursor_pos; }; @@ -171,22 +199,15 @@ struct osd_draw_callbacks bool winwindow_has_focus(void); void winwindow_update_cursor_state(running_machine &machine); -extern LRESULT CALLBACK winwindow_video_window_proc_ui(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam); - void winwindow_toggle_full_screen(void); void winwindow_take_snap(void); void winwindow_take_video(void); void winwindow_toggle_fsfx(void); -void winwindow_process_events_periodic(running_machine &machine); -void winwindow_process_events(running_machine &machine, bool ingame, bool nodispatch); - void winwindow_ui_pause(running_machine &machine, int pause); int winwindow_ui_is_paused(running_machine &machine); -void winwindow_dispatch_message(running_machine &machine, MSG *message); - -extern int win_create_menu(running_machine &machine, HMENU *menus); +void winwindow_dispatch_message(running_machine &machine, MSG const &message); @@ -205,4 +226,4 @@ static inline int rect_height(const RECT *rect) return rect->bottom - rect->top; } -#endif +#endif // MAME_OSD_WINDOWS_WINDOW_H diff --git a/src/osd/windows/winmain.cpp b/src/osd/windows/winmain.cpp index 721407a777a..2f7df659f44 100644 --- a/src/osd/windows/winmain.cpp +++ b/src/osd/windows/winmain.cpp @@ -6,41 +6,42 @@ // //============================================================ +#include "winmain.h" + +#include "window.h" +#include "winopts.h" + // MAME headers #include "emu.h" -#include "emuopts.h" -#include "strconv.h" +#include "main.h" // MAMEOS headers -#include "winmain.h" -#include "window.h" +#include "strconv.h" #include "winutf8.h" #include "winutil.h" #include "winfile.h" #include "modules/diagnostics/diagnostics_module.h" +#include "modules/lib/osdlib.h" #include "modules/monitor/monitor_common.h" // standard C headers -#include <ctype.h> -#include <stdarg.h> -#include <stdio.h> +#include <cctype> +#include <clocale> +#include <cstdarg> +#include <cstdio> +#include <mutex> +#include <optional> +#include <sstream> +#include <thread> // standard windows headers #include <windows.h> #include <commctrl.h> #include <mmsystem.h> +#include <objbase.h> #include <tchar.h> #include <io.h> -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#include <wrl/client.h> -using namespace Windows::Storage; -using namespace Platform; -using namespace Windows::ApplicationModel; -using namespace Windows::ApplicationModel::Core; -using namespace Windows::UI::Popups; -#endif - #define DEBUG_SLOW_LOCKS 0 //************************************************************************** @@ -57,72 +58,85 @@ using namespace Windows::UI::Popups; // TYPE DEFINITIONS //************************************************************************** -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - //============================================================ // winui_output_error //============================================================ class winui_output_error : public osd_output { -public: - virtual void output_callback(osd_output_channel channel, const char *msg, va_list args) override +private: + struct ui_state { - if (channel == OSD_OUTPUT_CHANNEL_ERROR) + ~ui_state() { - char buffer[1024]; - - // if we are in fullscreen mode, go to windowed mode - if ((video_config.windowed == 0) && !osd_common_t::s_window_list.empty()) - winwindow_toggle_full_screen(); - - vsnprintf(buffer, ARRAY_LENGTH(buffer), msg, args); - win_message_box_utf8(!osd_common_t::s_window_list.empty() ? std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window() : nullptr, buffer, emulator_info::get_appname(), MB_OK); + if (thread) + thread->join(); } - else - chain_output(channel, msg, args); - } -}; -#else + std::ostringstream buffer; + std::optional<std::thread> thread; + std::mutex mutex; + bool active; + }; -//============================================================ -// winuniversal_output_error -//============================================================ + static ui_state &get_state() + { + static ui_state state; + return state; + } -class winuniversal_output_error : public osd_output -{ public: - virtual void output_callback(osd_output_channel channel, const char *msg, va_list args) override + virtual void output_callback(osd_output_channel channel, const util::format_argument_pack<char> &args) override { - char buffer[2048]; if (channel == OSD_OUTPUT_CHANNEL_ERROR) { - vsnprintf(buffer, ARRAY_LENGTH(buffer), msg, args); - - std::wstring wcbuffer(osd::text::to_wstring(buffer)); - std::wstring wcappname(osd::text::to_wstring(emulator_info::get_appname())); + // if we are in fullscreen mode, go to windowed mode + if ((video_config.windowed == 0) && !osd_common_t::window_list().empty()) + winwindow_toggle_full_screen(); - auto dlg = ref new MessageDialog(ref new Platform::String(wcbuffer.data()), ref new Platform::String(wcbuffer.data())); - dlg->ShowAsync(); + auto &state(get_state()); + std::lock_guard<std::mutex> guard(state.mutex); + util::stream_format(state.buffer, args); + if (!state.active) + { + if (state.thread) + { + state.thread->join(); + state.thread = std::nullopt; + } + state.thread.emplace( + [] () + { + auto &state(get_state()); + std::string message; + while (true) + { + { + std::lock_guard<std::mutex> guard(state.mutex); + message = std::move(state.buffer).str(); + if (message.empty()) + { + state.active = false; + return; + } + state.buffer.str(std::string()); + } + // Don't hold any locks lock while calling MessageBox. + // Parent window isn't set because MAME could destroy + // the window out from under us on a fatal error. + win_message_box_utf8(nullptr, message.c_str(), emulator_info::get_appname(), MB_OK); + } + }); + state.active = true; + } } - else if (channel == OSD_OUTPUT_CHANNEL_VERBOSE) + else { - vsnprintf(buffer, ARRAY_LENGTH(buffer), msg, args); - std::wstring wcbuffer = osd::text::to_wstring(buffer); - OutputDebugString(wcbuffer.c_str()); - - // Chain to next anyway - chain_output(channel, msg, args); + chain_output(channel, args); } - else - chain_output(channel, msg, args); } }; -#endif - - //************************************************************************** // GLOBAL VARIABLES //************************************************************************** @@ -134,10 +148,8 @@ int _CRT_glob = 0; // LOCAL VARIABLES //************************************************************************** -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) static int timeresult = !TIMERR_NOERROR; static TIMECAPS timecaps; -#endif static running_machine *g_current_machine; @@ -151,142 +163,16 @@ static int is_double_click_start(int argc); //************************************************************************** -// OPTIONS -//************************************************************************** - -// struct definitions -const options_entry windows_options::s_option_entries[] = -{ - // performance options - { nullptr, nullptr, OPTION_HEADER, "WINDOWS PERFORMANCE OPTIONS" }, - { WINOPTION_PRIORITY "(-15-1)", "0", OPTION_INTEGER, "thread priority for the main game thread; range from -15 to 1" }, - { WINOPTION_PROFILE, "0", OPTION_INTEGER, "enables profiling, specifying the stack depth to track" }, - - // video options - { nullptr, nullptr, OPTION_HEADER, "WINDOWS VIDEO OPTIONS" }, - { WINOPTION_MENU, "0", OPTION_BOOLEAN, "enables menu bar if available by UI implementation" }, - { WINOPTION_ATTACH_WINDOW, "", OPTION_STRING, "attach to arbitrary window" }, - - // post-processing options - { nullptr, nullptr, OPTION_HEADER, "DIRECT3D POST-PROCESSING OPTIONS" }, - { WINOPTION_HLSLPATH, "hlsl", OPTION_STRING, "path to HLSL support files" }, - { WINOPTION_HLSL_ENABLE";hlsl", "0", OPTION_BOOLEAN, "enable HLSL post-processing (PS3.0 required)" }, - { WINOPTION_HLSL_OVERSAMPLING, "0", OPTION_BOOLEAN, "enable HLSL oversampling" }, - { WINOPTION_HLSL_WRITE, OSDOPTVAL_AUTO, OPTION_STRING, "enable HLSL AVI writing (huge disk bandwidth suggested)" }, - { WINOPTION_HLSL_SNAP_WIDTH, "2048", OPTION_STRING, "HLSL upscaled-snapshot width" }, - { WINOPTION_HLSL_SNAP_HEIGHT, "1536", OPTION_STRING, "HLSL upscaled-snapshot height" }, - { WINOPTION_SHADOW_MASK_TILE_MODE, "0", OPTION_INTEGER, "shadow mask tile mode (0 for screen based, 1 for source based)" }, - { WINOPTION_SHADOW_MASK_ALPHA";fs_shadwa(0.0-1.0)", "0.0", OPTION_FLOAT, "shadow mask alpha-blend value (1.0 is fully blended, 0.0 is no mask)" }, - { WINOPTION_SHADOW_MASK_TEXTURE";fs_shadwt(0.0-1.0)", "shadow-mask.png", OPTION_STRING, "shadow mask texture name" }, - { WINOPTION_SHADOW_MASK_COUNT_X";fs_shadww", "6", OPTION_INTEGER, "shadow mask tile width, in screen dimensions" }, - { WINOPTION_SHADOW_MASK_COUNT_Y";fs_shadwh", "4", OPTION_INTEGER, "shadow mask tile height, in screen dimensions" }, - { WINOPTION_SHADOW_MASK_USIZE";fs_shadwu(0.0-1.0)", "0.1875", OPTION_FLOAT, "shadow mask texture width, in U/V dimensions" }, - { WINOPTION_SHADOW_MASK_VSIZE";fs_shadwv(0.0-1.0)", "0.25", OPTION_FLOAT, "shadow mask texture height, in U/V dimensions" }, - { WINOPTION_SHADOW_MASK_UOFFSET";fs_shadwou(-1.0-1.0)", "0.0", OPTION_FLOAT, "shadow mask texture offset, in U direction" }, - { WINOPTION_SHADOW_MASK_VOFFSET";fs_shadwov(-1.0-1.0)", "0.0", OPTION_FLOAT, "shadow mask texture offset, in V direction" }, - { WINOPTION_DISTORTION";fs_dist(-1.0-1.0)", "0.0", OPTION_FLOAT, "screen distortion amount" }, - { WINOPTION_CUBIC_DISTORTION";fs_cubedist(-1.0-1.0)", "0.0", OPTION_FLOAT, "screen cubic distortion amount" }, - { WINOPTION_DISTORT_CORNER";fs_distc(0.0-1.0)", "0.0", OPTION_FLOAT, "screen distort corner amount" }, - { WINOPTION_ROUND_CORNER";fs_rndc(0.0-1.0)", "0.0", OPTION_FLOAT, "screen round corner amount" }, - { WINOPTION_SMOOTH_BORDER";fs_smob(0.0-1.0)", "0.0", OPTION_FLOAT, "screen smooth border amount" }, - { WINOPTION_REFLECTION";fs_ref(0.0-1.0)", "0.0", OPTION_FLOAT, "screen reflection amount" }, - { WINOPTION_VIGNETTING";fs_vig(0.0-1.0)", "0.0", OPTION_FLOAT, "image vignetting amount" }, - /* Beam-related values below this line*/ - { WINOPTION_SCANLINE_AMOUNT";fs_scanam(0.0-4.0)", "0.0", OPTION_FLOAT, "overall alpha scaling value for scanlines" }, - { WINOPTION_SCANLINE_SCALE";fs_scansc(0.0-4.0)", "1.0", OPTION_FLOAT, "overall height scaling value for scanlines" }, - { WINOPTION_SCANLINE_HEIGHT";fs_scanh(0.0-4.0)", "1.0", OPTION_FLOAT, "individual height scaling value for scanlines" }, - { WINOPTION_SCANLINE_VARIATION";fs_scanv(0.0-4.0)", "1.0", OPTION_FLOAT, "individual height varying value for scanlines" }, - { WINOPTION_SCANLINE_BRIGHT_SCALE";fs_scanbs(0.0-2.0)", "1.0", OPTION_FLOAT, "overall brightness scaling value for scanlines (multiplicative)" }, - { WINOPTION_SCANLINE_BRIGHT_OFFSET";fs_scanbo(0.0-1.0)", "0.0", OPTION_FLOAT, "overall brightness offset value for scanlines (additive)" }, - { WINOPTION_SCANLINE_JITTER";fs_scanjt(0.0-4.0)", "0.0", OPTION_FLOAT, "overall interlace jitter scaling value for scanlines" }, - { WINOPTION_HUM_BAR_ALPHA";fs_humba(0.0-1.0)", "0.0", OPTION_FLOAT, "overall alpha scaling value for hum bar" }, - { WINOPTION_DEFOCUS";fs_focus", "0.0,0.0", OPTION_STRING, "overall defocus value in screen-relative coords" }, - { WINOPTION_CONVERGE_X";fs_convx", "0.0,0.0,0.0", OPTION_STRING, "convergence in screen-relative X direction" }, - { WINOPTION_CONVERGE_Y";fs_convy", "0.0,0.0,0.0", OPTION_STRING, "convergence in screen-relative Y direction" }, - { WINOPTION_RADIAL_CONVERGE_X";fs_rconvx", "0.0,0.0,0.0", OPTION_STRING, "radial convergence in screen-relative X direction" }, - { WINOPTION_RADIAL_CONVERGE_Y";fs_rconvy", "0.0,0.0,0.0", OPTION_STRING, "radial convergence in screen-relative Y direction" }, - /* RGB colorspace convolution below this line */ - { WINOPTION_RED_RATIO";fs_redratio", "1.0,0.0,0.0", OPTION_STRING, "red output signal generated by input signal" }, - { WINOPTION_GRN_RATIO";fs_grnratio", "0.0,1.0,0.0", OPTION_STRING, "green output signal generated by input signal" }, - { WINOPTION_BLU_RATIO";fs_bluratio", "0.0,0.0,1.0", OPTION_STRING, "blue output signal generated by input signal" }, - { WINOPTION_SATURATION";fs_sat(0.0-4.0)", "1.0", OPTION_FLOAT, "saturation scaling value" }, - { WINOPTION_OFFSET";fs_offset", "0.0,0.0,0.0", OPTION_STRING, "signal offset value (additive)" }, - { WINOPTION_SCALE";fs_scale", "1.0,1.0,1.0", OPTION_STRING, "signal scaling value (multiplicative)" }, - { WINOPTION_POWER";fs_power", "1.0,1.0,1.0", OPTION_STRING, "signal power value (exponential)" }, - { WINOPTION_FLOOR";fs_floor", "0.0,0.0,0.0", OPTION_STRING, "signal floor level" }, - { WINOPTION_PHOSPHOR";fs_phosphor", "0.0,0.0,0.0", OPTION_STRING, "phosphorescence decay rate (0.0 is instant, 1.0 is forever)" }, - { WINOPTION_CHROMA_MODE, "3", OPTION_INTEGER, "number of phosphors to use: 1 - monochrome, 2 - dichrome, 3 - trichrome (color)" }, - { WINOPTION_CHROMA_CONVERSION_GAIN, "0.299,0.587,0.114", OPTION_STRING, "gain to be applied when summing RGB signal for monochrome and dichrome modes" }, - { WINOPTION_CHROMA_A, "0.64,0.33", OPTION_STRING, "chromaticity coordinate for first phosphor" }, - { WINOPTION_CHROMA_B, "0.30,0.60", OPTION_STRING, "chromaticity coordinate for second phosphor" }, - { WINOPTION_CHROMA_C, "0.15,0.06", OPTION_STRING, "chromaticity coordinate for third phosphor" }, - { WINOPTION_CHROMA_Y_GAIN, "0.2126,0.7152,0.0722", OPTION_STRING, "gain to be applied for each phosphor" }, - /* NTSC simulation below this line */ - { nullptr, nullptr, OPTION_HEADER, "NTSC POST-PROCESSING OPTIONS" }, - { WINOPTION_YIQ_ENABLE";yiq", "0", OPTION_BOOLEAN, "enable YIQ-space HLSL post-processing" }, - { WINOPTION_YIQ_JITTER";yiqj", "0.0", OPTION_FLOAT, "jitter for the NTSC signal processing" }, - { WINOPTION_YIQ_CCVALUE";yiqcc", "3.57954545", OPTION_FLOAT, "color carrier frequency for NTSC signal processing" }, - { WINOPTION_YIQ_AVALUE";yiqa", "0.5", OPTION_FLOAT, "A value for NTSC signal processing" }, - { WINOPTION_YIQ_BVALUE";yiqb", "0.5", OPTION_FLOAT, "B value for NTSC signal processing" }, - { WINOPTION_YIQ_OVALUE";yiqo", "0.0", OPTION_FLOAT, "outgoing Color Carrier phase offset for NTSC signal processing" }, - { WINOPTION_YIQ_PVALUE";yiqp", "1.0", OPTION_FLOAT, "incoming Pixel Clock scaling value for NTSC signal processing" }, - { WINOPTION_YIQ_NVALUE";yiqn", "1.0", OPTION_FLOAT, "Y filter notch width for NTSC signal processing" }, - { WINOPTION_YIQ_YVALUE";yiqy", "6.0", OPTION_FLOAT, "Y filter cutoff frequency for NTSC signal processing" }, - { WINOPTION_YIQ_IVALUE";yiqi", "1.2", OPTION_FLOAT, "I filter cutoff frequency for NTSC signal processing" }, - { WINOPTION_YIQ_QVALUE";yiqq", "0.6", OPTION_FLOAT, "Q filter cutoff frequency for NTSC signal processing" }, - { WINOPTION_YIQ_SCAN_TIME";yiqsc", "52.6", OPTION_FLOAT, "horizontal scanline duration for NTSC signal processing (microseconds)" }, - { WINOPTION_YIQ_PHASE_COUNT";yiqpc", "2", OPTION_INTEGER, "phase count value for NTSC signal processing" }, - /* Vector simulation below this line */ - { nullptr, nullptr, OPTION_HEADER, "VECTOR POST-PROCESSING OPTIONS" }, - { WINOPTION_VECTOR_BEAM_SMOOTH";vecsmooth", "0.0", OPTION_FLOAT, "vector beam smoothness" }, - { WINOPTION_VECTOR_LENGTH_SCALE";vecscale", "0.5", OPTION_FLOAT, "maximum vector attenuation" }, - { WINOPTION_VECTOR_LENGTH_RATIO";vecratio", "0.5", OPTION_FLOAT, "minimum vector length affected by attenuation (vector length to screen size ratio)" }, - /* Bloom below this line */ - { nullptr, nullptr, OPTION_HEADER, "BLOOM POST-PROCESSING OPTIONS" }, - { WINOPTION_BLOOM_BLEND_MODE, "0", OPTION_INTEGER, "bloom blend mode (0 for brighten, 1 for darken)" }, - { WINOPTION_BLOOM_SCALE, "0.0", OPTION_FLOAT, "intensity factor for bloom" }, - { WINOPTION_BLOOM_OVERDRIVE, "1.0,1.0,1.0", OPTION_STRING, "overdrive factor for bloom" }, - { WINOPTION_BLOOM_LEVEL0_WEIGHT, "1.0", OPTION_FLOAT, "bloom level 0 weight (full-size target)" }, - { WINOPTION_BLOOM_LEVEL1_WEIGHT, "0.64", OPTION_FLOAT, "bloom level 1 weight (1/4 smaller that level 0 target)" }, - { WINOPTION_BLOOM_LEVEL2_WEIGHT, "0.32", OPTION_FLOAT, "bloom level 2 weight (1/4 smaller that level 1 target)" }, - { WINOPTION_BLOOM_LEVEL3_WEIGHT, "0.16", OPTION_FLOAT, "bloom level 3 weight (1/4 smaller that level 2 target)" }, - { WINOPTION_BLOOM_LEVEL4_WEIGHT, "0.08", OPTION_FLOAT, "bloom level 4 weight (1/4 smaller that level 3 target)" }, - { WINOPTION_BLOOM_LEVEL5_WEIGHT, "0.06", OPTION_FLOAT, "bloom level 5 weight (1/4 smaller that level 4 target)" }, - { WINOPTION_BLOOM_LEVEL6_WEIGHT, "0.04", OPTION_FLOAT, "bloom level 6 weight (1/4 smaller that level 5 target)" }, - { WINOPTION_BLOOM_LEVEL7_WEIGHT, "0.02", OPTION_FLOAT, "bloom level 7 weight (1/4 smaller that level 6 target)" }, - { WINOPTION_BLOOM_LEVEL8_WEIGHT, "0.01", OPTION_FLOAT, "bloom level 8 weight (1/4 smaller that level 7 target)" }, - { WINOPTION_LUT_TEXTURE, "", OPTION_STRING, "3D LUT texture filename for screen, PNG format" }, - { WINOPTION_LUT_ENABLE, "0", OPTION_BOOLEAN, "Enables 3D LUT to be applied to screen after post-processing" }, - { WINOPTION_UI_LUT_TEXTURE, "", OPTION_STRING, "3D LUT texture filename of UI, PNG format" }, - { WINOPTION_UI_LUT_ENABLE, "0", OPTION_BOOLEAN, "enable 3D LUT to be applied to UI and artwork after post-processing" }, - - // full screen options - { nullptr, nullptr, OPTION_HEADER, "FULL SCREEN OPTIONS" }, - { WINOPTION_TRIPLEBUFFER ";tb", "0", OPTION_BOOLEAN, "enable triple buffering" }, - { WINOPTION_FULLSCREENBRIGHTNESS ";fsb(0.1-2.0)", "1.0", OPTION_FLOAT, "brightness value in full screen mode" }, - { WINOPTION_FULLSCREENCONTRAST ";fsc(0.1-2.0)", "1.0", OPTION_FLOAT, "contrast value in full screen mode" }, - { WINOPTION_FULLSCREENGAMMA ";fsg(0.1-3.0)", "1.0", OPTION_FLOAT, "gamma value in full screen mode" }, - - // input options - { nullptr, nullptr, OPTION_HEADER, "INPUT DEVICE OPTIONS" }, - { WINOPTION_GLOBAL_INPUTS, "0", OPTION_BOOLEAN, "enable global inputs" }, - { WINOPTION_DUAL_LIGHTGUN ";dual", "0", OPTION_BOOLEAN, "enable dual lightgun input" }, - - { nullptr } -}; - -//************************************************************************** // MAIN ENTRY POINT //************************************************************************** -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - //============================================================ // main //============================================================ int main(int argc, char *argv[]) { + std::setlocale(LC_ALL, ""); std::vector<std::string> args = osd_get_command_line(argc, argv); // use small output buffers on non-TTYs (i.e. pipes) @@ -295,6 +181,17 @@ int main(int argc, char *argv[]) if (!isatty(fileno(stderr))) setvbuf(stderr, (char *) nullptr, _IOFBF, 64); + { + // Disable legacy mouse to pointer event translation - it's broken: + // * No WM_POINTERLEAVE event when mouse pointer moves directly to an + // overlapping window from the same process. + // * Still receive occasional WM_MOUSEMOVE events. + OSD_DYNAMIC_API(user32, "User32.dll", "User32.dll"); + OSD_DYNAMIC_API_FN(user32, BOOL, WINAPI, EnableMouseInPointer, BOOL); + if (OSD_DYNAMIC_API_TEST(EnableMouseInPointer)) + OSD_DYNAMIC_CALL(EnableMouseInPointer, FALSE); + } + // initialize common controls InitCommonControls(); @@ -364,107 +261,6 @@ static BOOL WINAPI control_handler(DWORD type) return TRUE; } -#else - -// The main function is only used to initialize our IFrameworkView class. -[Platform::MTAThread] -int main(Platform::Array<Platform::String^>^ args) -{ - auto direct3DApplicationSource = ref new MameViewSource(); - CoreApplication::Run(direct3DApplicationSource); - return 0; -} - -MameMainApp::MameMainApp() -{ - // Turn off application view scaling so XBOX gets full screen - Windows::UI::ViewManagement::ApplicationViewScaling::TrySetDisableLayoutScaling(true); -} - -void MameMainApp::Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView) -{ - // Register event handlers for app lifecycle. -} - -// Called when the CoreWindow object is created (or re-created). -void MameMainApp::SetWindow(Windows::UI::Core::CoreWindow^ window) -{ - // Attach event handlers on the window for input, etc. -} - -// Initializes scene resources, or loads a previously saved app state. -void MameMainApp::Load(Platform::String^ entryPoint) -{ -} - -void MameMainApp::Run() -{ - // use small output buffers on non-TTYs (i.e. pipes) - if (!isatty(fileno(stdout))) - setvbuf(stdout, (char *) nullptr, _IOFBF, 64); - if (!isatty(fileno(stderr))) - setvbuf(stderr, (char *) nullptr, _IOFBF, 64); - - // parse config and cmdline options - m_options = std::make_unique<windows_options>(); - m_osd = std::make_unique<windows_osd_interface>(*m_options.get()); - - // Since we're a GUI app, out errors to message boxes - // Initialize this after the osd interface so that we are first in the - // output order - winuniversal_output_error winerror; - osd_output::push(&winerror); - - m_osd->register_options(); - - // To satisfy the latter things, pass in the module path name - char exe_path[MAX_PATH]; - GetModuleFileNameA(nullptr, exe_path, MAX_PATH); - char* args[3] = { exe_path, (char*)"-verbose", (char*)"-mouse" }; - - DWORD result = emulator_info::start_frontend(*m_options.get(), *m_osd.get(), ARRAY_LENGTH(args), args); - osd_output::pop(&winerror); -} - -// Required for IFrameworkView. -void MameMainApp::Uninitialize() -{ - // Terminate events do not cause Uninitialize to be called. It will be called if your IFrameworkView - // class is torn down while the app is in the foreground. -} - -IFrameworkView^ MameViewSource::CreateView() -{ - return ref new MameMainApp(); -} - -#endif - - -//============================================================ -// windows_options -//============================================================ - -windows_options::windows_options() -: osd_options() -{ - add_entries(s_option_entries); -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - String^ path = ApplicationData::Current->LocalFolder->Path + L"\\"; - set_default_value(OPTION_INIPATH, (osd::text::from_wstring((LPCWSTR)path->Data()) + ";" + ini_path()).c_str()); - set_default_value(OPTION_CFG_DIRECTORY, (osd::text::from_wstring((LPCWSTR)path->Data()) + cfg_directory()).c_str()); - set_default_value(OPTION_NVRAM_DIRECTORY, (osd::text::from_wstring((LPCWSTR)path->Data()) + nvram_directory()).c_str()); - set_default_value(OPTION_INPUT_DIRECTORY, (osd::text::from_wstring((LPCWSTR)path->Data()) + input_directory()).c_str()); - set_default_value(OPTION_STATE_DIRECTORY, (osd::text::from_wstring((LPCWSTR)path->Data()) + state_directory()).c_str()); - set_default_value(OPTION_SNAPSHOT_DIRECTORY, (osd::text::from_wstring((LPCWSTR)path->Data()) + snapshot_directory()).c_str()); - set_default_value(OPTION_DIFF_DIRECTORY, (osd::text::from_wstring((LPCWSTR)path->Data()) + diff_directory()).c_str()); - set_default_value(OPTION_COMMENT_DIRECTORY, (osd::text::from_wstring((LPCWSTR)path->Data()) + comment_directory()).c_str()); - - set_default_value(OPTION_HOMEPATH, osd::text::from_wstring((LPCWSTR)path->Data()).c_str()); - set_default_value(OPTION_MEDIAPATH, (osd::text::from_wstring((LPCWSTR)path->Data()) + media_path()).c_str()); -#endif -} - //============================================================ // output_oslog @@ -486,6 +282,8 @@ void windows_osd_interface::output_oslog(const char *buffer) windows_osd_interface::windows_osd_interface(windows_options &options) : osd_common_t(options) , m_options(options) + , m_com_status(SUCCEEDED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED))) + , m_last_event_check(std::chrono::steady_clock::time_point::min()) { } @@ -496,25 +294,12 @@ windows_osd_interface::windows_osd_interface(windows_options &options) windows_osd_interface::~windows_osd_interface() { + if (m_com_status) + CoUninitialize(); } //============================================================ -// video_register -//============================================================ - -void windows_osd_interface::video_register() -{ - video_options_add("gdi", nullptr); - video_options_add("d3d", nullptr); -#if USE_OPENGL - video_options_add("opengl", nullptr); -#endif - video_options_add("bgfx", nullptr); - //video_options_add("auto", nullptr); // making d3d video default one -} - -//============================================================ // init //============================================================ @@ -524,12 +309,13 @@ void windows_osd_interface::init(running_machine &machine) osd_common_t::init(machine); const char *stemp; - windows_options &options = downcast<windows_options &>(machine.options()); + auto &options = downcast<windows_options &>(machine.options()); // 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); @@ -566,23 +352,15 @@ void windows_osd_interface::init(running_machine &machine) // initialize the subsystems osd_common_t::init_subsystems(); - // notify listeners of screen configuration - for (auto info : osd_common_t::s_window_list) - { - machine.output().set_value(string_format("Orientation(%s)", info->monitor()->devicename()).c_str(), std::static_pointer_cast<win_window_info>(info)->m_targetorient); - } - // hook up the debugger log if (options.oslog()) machine.add_logerror_callback(&windows_osd_interface::output_oslog); -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) // crank up the multimedia timer resolution to its max // this gives the system much finer timeslices timeresult = timeGetDevCaps(&timecaps, sizeof(timecaps)); if (timeresult == TIMERR_NOERROR) timeBeginPeriod(timecaps.wPeriodMin); -#endif // create and start the profiler if (profile > 0) @@ -616,30 +394,15 @@ void windows_osd_interface::osd_exit() diagnostics_module::get_instance()->stop_profiler(); diagnostics_module::get_instance()->print_profiler_results(); -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) // restore the timer resolution if (timeresult == TIMERR_NOERROR) timeEndPeriod(timecaps.wPeriodMin); -#endif // one last pass at events - winwindow_process_events(machine(), false, false); -} - - -//============================================================ -// osd_setup_osd_specific_emu_options -//============================================================ - -void osd_setup_osd_specific_emu_options(emu_options &opts) -{ - opts.add_entries(osd_options::s_option_entries); - opts.add_entries(windows_options::s_option_entries); + process_events(false, false); } -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - //============================================================ // check_for_double_click_start //============================================================ @@ -654,5 +417,3 @@ static int is_double_click_start(int argc) // try to determine if MAME was simply double-clicked return (argc <= 1 && startup_info.dwFlags && !(startup_info.dwFlags & STARTF_USESTDHANDLES)); } - -#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) diff --git a/src/osd/windows/winmain.h b/src/osd/windows/winmain.h index 21e1b9d2044..5b8e992be6b 100644 --- a/src/osd/windows/winmain.h +++ b/src/osd/windows/winmain.h @@ -5,235 +5,19 @@ // winmain.h - Win32 main program and core headers // //============================================================ +#ifndef MAME_OSD_WINDOWS_WINMAIN_H +#define MAME_OSD_WINDOWS_WINMAIN_H -#ifndef __WINDOWS_WINMAIN_H__ -#define __WINDOWS_WINMAIN_H__ +#pragma once -#include <winapifamily.h> -#include "osdepend.h" -#include "modules/lib/osdobj_common.h" - - -//============================================================ -// CONSTANTS -//============================================================ - -// performance options -#define WINOPTION_PRIORITY "priority" -#define WINOPTION_PROFILE "profile" - -// video options -#define WINOPTION_MENU "menu" -#define WINOPTION_ATTACH_WINDOW "attach_window" - -// core post-processing options -#define WINOPTION_HLSLPATH "hlslpath" -#define WINOPTION_HLSL_ENABLE "hlsl_enable" -#define WINOPTION_HLSL_OVERSAMPLING "hlsl_oversampling" -#define WINOPTION_HLSL_WRITE "hlsl_write" -#define WINOPTION_HLSL_SNAP_WIDTH "hlsl_snap_width" -#define WINOPTION_HLSL_SNAP_HEIGHT "hlsl_snap_height" -#define WINOPTION_SHADOW_MASK_TILE_MODE "shadow_mask_tile_mode" -#define WINOPTION_SHADOW_MASK_ALPHA "shadow_mask_alpha" -#define WINOPTION_SHADOW_MASK_TEXTURE "shadow_mask_texture" -#define WINOPTION_SHADOW_MASK_COUNT_X "shadow_mask_x_count" -#define WINOPTION_SHADOW_MASK_COUNT_Y "shadow_mask_y_count" -#define WINOPTION_SHADOW_MASK_USIZE "shadow_mask_usize" -#define WINOPTION_SHADOW_MASK_VSIZE "shadow_mask_vsize" -#define WINOPTION_SHADOW_MASK_UOFFSET "shadow_mask_uoffset" -#define WINOPTION_SHADOW_MASK_VOFFSET "shadow_mask_voffset" -#define WINOPTION_REFLECTION "reflection" -#define WINOPTION_DISTORTION "distortion" -#define WINOPTION_CUBIC_DISTORTION "cubic_distortion" -#define WINOPTION_DISTORT_CORNER "distort_corner" -#define WINOPTION_ROUND_CORNER "round_corner" -#define WINOPTION_SMOOTH_BORDER "smooth_border" -#define WINOPTION_VIGNETTING "vignetting" -#define WINOPTION_SCANLINE_AMOUNT "scanline_alpha" -#define WINOPTION_SCANLINE_SCALE "scanline_size" -#define WINOPTION_SCANLINE_HEIGHT "scanline_height" -#define WINOPTION_SCANLINE_VARIATION "scanline_variation" -#define WINOPTION_SCANLINE_BRIGHT_SCALE "scanline_bright_scale" -#define WINOPTION_SCANLINE_BRIGHT_OFFSET "scanline_bright_offset" -#define WINOPTION_SCANLINE_JITTER "scanline_jitter" -#define WINOPTION_HUM_BAR_ALPHA "hum_bar_alpha" -#define WINOPTION_DEFOCUS "defocus" -#define WINOPTION_CONVERGE_X "converge_x" -#define WINOPTION_CONVERGE_Y "converge_y" -#define WINOPTION_RADIAL_CONVERGE_X "radial_converge_x" -#define WINOPTION_RADIAL_CONVERGE_Y "radial_converge_y" -#define WINOPTION_RED_RATIO "red_ratio" -#define WINOPTION_GRN_RATIO "grn_ratio" -#define WINOPTION_BLU_RATIO "blu_ratio" -#define WINOPTION_OFFSET "offset" -#define WINOPTION_SCALE "scale" -#define WINOPTION_POWER "power" -#define WINOPTION_FLOOR "floor" -#define WINOPTION_PHOSPHOR "phosphor_life" -#define WINOPTION_SATURATION "saturation" -#define WINOPTION_CHROMA_MODE "chroma_mode" -#define WINOPTION_CHROMA_CONVERSION_GAIN "chroma_conversion_gain" -#define WINOPTION_CHROMA_A "chroma_a" -#define WINOPTION_CHROMA_B "chroma_b" -#define WINOPTION_CHROMA_C "chroma_c" -#define WINOPTION_CHROMA_Y_GAIN "chroma_y_gain" -#define WINOPTION_YIQ_ENABLE "yiq_enable" -#define WINOPTION_YIQ_JITTER "yiq_jitter" -#define WINOPTION_YIQ_CCVALUE "yiq_cc" -#define WINOPTION_YIQ_AVALUE "yiq_a" -#define WINOPTION_YIQ_BVALUE "yiq_b" -#define WINOPTION_YIQ_OVALUE "yiq_o" -#define WINOPTION_YIQ_PVALUE "yiq_p" -#define WINOPTION_YIQ_NVALUE "yiq_n" -#define WINOPTION_YIQ_YVALUE "yiq_y" -#define WINOPTION_YIQ_IVALUE "yiq_i" -#define WINOPTION_YIQ_QVALUE "yiq_q" -#define WINOPTION_YIQ_SCAN_TIME "yiq_scan_time" -#define WINOPTION_YIQ_PHASE_COUNT "yiq_phase_count" -#define WINOPTION_VECTOR_BEAM_SMOOTH "vector_beam_smooth" -#define WINOPTION_VECTOR_LENGTH_SCALE "vector_length_scale" -#define WINOPTION_VECTOR_LENGTH_RATIO "vector_length_ratio" -#define WINOPTION_BLOOM_BLEND_MODE "bloom_blend_mode" -#define WINOPTION_BLOOM_SCALE "bloom_scale" -#define WINOPTION_BLOOM_OVERDRIVE "bloom_overdrive" -#define WINOPTION_BLOOM_LEVEL0_WEIGHT "bloom_lvl0_weight" -#define WINOPTION_BLOOM_LEVEL1_WEIGHT "bloom_lvl1_weight" -#define WINOPTION_BLOOM_LEVEL2_WEIGHT "bloom_lvl2_weight" -#define WINOPTION_BLOOM_LEVEL3_WEIGHT "bloom_lvl3_weight" -#define WINOPTION_BLOOM_LEVEL4_WEIGHT "bloom_lvl4_weight" -#define WINOPTION_BLOOM_LEVEL5_WEIGHT "bloom_lvl5_weight" -#define WINOPTION_BLOOM_LEVEL6_WEIGHT "bloom_lvl6_weight" -#define WINOPTION_BLOOM_LEVEL7_WEIGHT "bloom_lvl7_weight" -#define WINOPTION_BLOOM_LEVEL8_WEIGHT "bloom_lvl8_weight" -#define WINOPTION_LUT_TEXTURE "lut_texture" -#define WINOPTION_LUT_ENABLE "lut_enable" -#define WINOPTION_UI_LUT_TEXTURE "ui_lut_texture" -#define WINOPTION_UI_LUT_ENABLE "ui_lut_enable" - -// full screen options -#define WINOPTION_TRIPLEBUFFER "triplebuffer" -#define WINOPTION_FULLSCREENBRIGHTNESS "full_screen_brightness" -#define WINOPTION_FULLSCREENCONTRAST "full_screen_contrast" -#define WINOPTION_FULLSCREENGAMMA "full_screen_gamma" - -// input options -#define WINOPTION_GLOBAL_INPUTS "global_inputs" -#define WINOPTION_DUAL_LIGHTGUN "dual_lightgun" - -//============================================================ -// TYPE DEFINITIONS -//============================================================ - -class windows_options : public osd_options -{ -public: - // construction/destruction - windows_options(); - - // performance options - int priority() const { return int_value(WINOPTION_PRIORITY); } - int profile() const { return int_value(WINOPTION_PROFILE); } - - // video options - bool menu() const { return bool_value(WINOPTION_MENU); } - const char *attach_window() const { return value(WINOPTION_ATTACH_WINDOW); } +#include "winopts.h" - // core post-processing options - const char *screen_post_fx_dir() const { return value(WINOPTION_HLSLPATH); } - bool d3d_hlsl_enable() const { return bool_value(WINOPTION_HLSL_ENABLE); } - bool d3d_hlsl_oversampling() const { return bool_value(WINOPTION_HLSL_OVERSAMPLING); } - const char *d3d_hlsl_write() const { return value(WINOPTION_HLSL_WRITE); } - int d3d_snap_width() const { return int_value(WINOPTION_HLSL_SNAP_WIDTH); } - int d3d_snap_height() const { return int_value(WINOPTION_HLSL_SNAP_HEIGHT); } - int screen_shadow_mask_tile_mode() const { return int_value(WINOPTION_SHADOW_MASK_TILE_MODE); } - float screen_shadow_mask_alpha() const { return float_value(WINOPTION_SHADOW_MASK_ALPHA); } - const char *screen_shadow_mask_texture() const { return value(WINOPTION_SHADOW_MASK_TEXTURE); } - int screen_shadow_mask_count_x() const { return int_value(WINOPTION_SHADOW_MASK_COUNT_X); } - int screen_shadow_mask_count_y() const { return int_value(WINOPTION_SHADOW_MASK_COUNT_Y); } - float screen_shadow_mask_u_size() const { return float_value(WINOPTION_SHADOW_MASK_USIZE); } - float screen_shadow_mask_v_size() const { return float_value(WINOPTION_SHADOW_MASK_VSIZE); } - float screen_shadow_mask_u_offset() const { return float_value(WINOPTION_SHADOW_MASK_UOFFSET); } - float screen_shadow_mask_v_offset() const { return float_value(WINOPTION_SHADOW_MASK_VOFFSET); } - float screen_scanline_amount() const { return float_value(WINOPTION_SCANLINE_AMOUNT); } - float screen_scanline_scale() const { return float_value(WINOPTION_SCANLINE_SCALE); } - float screen_scanline_height() const { return float_value(WINOPTION_SCANLINE_HEIGHT); } - float screen_scanline_variation() const { return float_value(WINOPTION_SCANLINE_VARIATION); } - float screen_scanline_bright_scale() const { return float_value(WINOPTION_SCANLINE_BRIGHT_SCALE); } - float screen_scanline_bright_offset() const { return float_value(WINOPTION_SCANLINE_BRIGHT_OFFSET); } - float screen_scanline_jitter() const { return float_value(WINOPTION_SCANLINE_JITTER); } - float screen_hum_bar_alpha() const { return float_value(WINOPTION_HUM_BAR_ALPHA); } - float screen_reflection() const { return float_value(WINOPTION_REFLECTION); } - float screen_distortion() const { return float_value(WINOPTION_DISTORTION); } - float screen_cubic_distortion() const { return float_value(WINOPTION_CUBIC_DISTORTION); } - float screen_distort_corner() const { return float_value(WINOPTION_DISTORT_CORNER); } - float screen_round_corner() const { return float_value(WINOPTION_ROUND_CORNER); } - float screen_smooth_border() const { return float_value(WINOPTION_SMOOTH_BORDER); } - float screen_vignetting() const { return float_value(WINOPTION_VIGNETTING); } - const char *screen_defocus() const { return value(WINOPTION_DEFOCUS); } - const char *screen_converge_x() const { return value(WINOPTION_CONVERGE_X); } - const char *screen_converge_y() const { return value(WINOPTION_CONVERGE_Y); } - const char *screen_radial_converge_x() const { return value(WINOPTION_RADIAL_CONVERGE_X); } - const char *screen_radial_converge_y() const { return value(WINOPTION_RADIAL_CONVERGE_Y); } - const char *screen_red_ratio() const { return value(WINOPTION_RED_RATIO); } - const char *screen_grn_ratio() const { return value(WINOPTION_GRN_RATIO); } - const char *screen_blu_ratio() const { return value(WINOPTION_BLU_RATIO); } - bool screen_yiq_enable() const { return bool_value(WINOPTION_YIQ_ENABLE); } - float screen_yiq_jitter() const { return float_value(WINOPTION_YIQ_JITTER); } - float screen_yiq_cc() const { return float_value(WINOPTION_YIQ_CCVALUE); } - float screen_yiq_a() const { return float_value(WINOPTION_YIQ_AVALUE); } - float screen_yiq_b() const { return float_value(WINOPTION_YIQ_BVALUE); } - float screen_yiq_o() const { return float_value(WINOPTION_YIQ_OVALUE); } - float screen_yiq_p() const { return float_value(WINOPTION_YIQ_PVALUE); } - float screen_yiq_n() const { return float_value(WINOPTION_YIQ_NVALUE); } - float screen_yiq_y() const { return float_value(WINOPTION_YIQ_YVALUE); } - float screen_yiq_i() const { return float_value(WINOPTION_YIQ_IVALUE); } - float screen_yiq_q() const { return float_value(WINOPTION_YIQ_QVALUE); } - float screen_yiq_scan_time() const { return float_value(WINOPTION_YIQ_SCAN_TIME); } - int screen_yiq_phase_count() const { return int_value(WINOPTION_YIQ_PHASE_COUNT); } - float screen_vector_beam_smooth() const { return float_value(WINOPTION_VECTOR_BEAM_SMOOTH); } - float screen_vector_length_scale() const { return float_value(WINOPTION_VECTOR_LENGTH_SCALE); } - float screen_vector_length_ratio() const { return float_value(WINOPTION_VECTOR_LENGTH_RATIO); } - int screen_bloom_blend_mode() const { return int_value(WINOPTION_BLOOM_BLEND_MODE); } - float screen_bloom_scale() const { return float_value(WINOPTION_BLOOM_SCALE); } - const char *screen_bloom_overdrive() const { return value(WINOPTION_BLOOM_OVERDRIVE); } - float screen_bloom_lvl0_weight() const { return float_value(WINOPTION_BLOOM_LEVEL0_WEIGHT); } - float screen_bloom_lvl1_weight() const { return float_value(WINOPTION_BLOOM_LEVEL1_WEIGHT); } - float screen_bloom_lvl2_weight() const { return float_value(WINOPTION_BLOOM_LEVEL2_WEIGHT); } - float screen_bloom_lvl3_weight() const { return float_value(WINOPTION_BLOOM_LEVEL3_WEIGHT); } - float screen_bloom_lvl4_weight() const { return float_value(WINOPTION_BLOOM_LEVEL4_WEIGHT); } - float screen_bloom_lvl5_weight() const { return float_value(WINOPTION_BLOOM_LEVEL5_WEIGHT); } - float screen_bloom_lvl6_weight() const { return float_value(WINOPTION_BLOOM_LEVEL6_WEIGHT); } - float screen_bloom_lvl7_weight() const { return float_value(WINOPTION_BLOOM_LEVEL7_WEIGHT); } - float screen_bloom_lvl8_weight() const { return float_value(WINOPTION_BLOOM_LEVEL8_WEIGHT); } - const char *screen_offset() const { return value(WINOPTION_OFFSET); } - const char *screen_scale() const { return value(WINOPTION_SCALE); } - const char *screen_power() const { return value(WINOPTION_POWER); } - const char *screen_floor() const { return value(WINOPTION_FLOOR); } - const char *screen_phosphor() const { return value(WINOPTION_PHOSPHOR); } - float screen_saturation() const { return float_value(WINOPTION_SATURATION); } - int screen_chroma_mode() const { return int_value(WINOPTION_CHROMA_MODE); } - const char *screen_chroma_a() const { return value(WINOPTION_CHROMA_A); } - const char *screen_chroma_b() const { return value(WINOPTION_CHROMA_B); } - const char *screen_chroma_c() const { return value(WINOPTION_CHROMA_C); } - const char *screen_chroma_conversion_gain() const { return value(WINOPTION_CHROMA_CONVERSION_GAIN); } - const char *screen_chroma_y_gain() const { return value(WINOPTION_CHROMA_Y_GAIN); } - const char *screen_lut_texture() const { return value(WINOPTION_LUT_TEXTURE); } - bool screen_lut_enable() const { return bool_value(WINOPTION_LUT_ENABLE); } - const char *ui_lut_texture() const { return value(WINOPTION_UI_LUT_TEXTURE); } - bool ui_lut_enable() const { return bool_value(WINOPTION_UI_LUT_ENABLE); } - - // full screen options - bool triple_buffer() const { return bool_value(WINOPTION_TRIPLEBUFFER); } - float full_screen_brightness() const { return float_value(WINOPTION_FULLSCREENBRIGHTNESS); } - float full_screen_contrast() const { return float_value(WINOPTION_FULLSCREENCONTRAST); } - float full_screen_gamma() const { return float_value(WINOPTION_FULLSCREENGAMMA); } +#include "modules/lib/osdobj_common.h" +#include "osdepend.h" - // input options - bool global_inputs() const { return bool_value(WINOPTION_GLOBAL_INPUTS); } - bool dual_lightgun() const { return bool_value(WINOPTION_DUAL_LIGHTGUN); } +#include <chrono> +#include <vector> - static const options_entry s_option_entries[]; -}; //============================================================ // TYPE DEFINITIONS @@ -244,7 +28,10 @@ enum input_event INPUT_EVENT_KEYDOWN, INPUT_EVENT_KEYUP, INPUT_EVENT_RAWINPUT, - INPUT_EVENT_MOUSE_BUTTON + INPUT_EVENT_ARRIVAL, + INPUT_EVENT_REMOVAL, + INPUT_EVENT_MOUSE_BUTTON, + INPUT_EVENT_MOUSE_WHEEL }; struct KeyPressEventArgs @@ -254,24 +41,19 @@ struct KeyPressEventArgs uint8_t scancode; }; -struct MouseButtonEventArgs +struct MouseUpdateEventArgs { - int button; - int keydown; + unsigned pressed; + unsigned released; + int vdelta; + int hdelta; int xpos; int ypos; }; -// Forward declarations -struct _EXCEPTION_POINTERS; class windows_osd_interface : public osd_common_t { -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - // Access to exception filter static method - friend int main(int argc, char *argv[]); -#endif - public: // construction/destruction windows_osd_interface(windows_options &options); @@ -280,15 +62,15 @@ public: // general overridables virtual void init(running_machine &machine) override; virtual void update(bool skip_redraw) override; + virtual void input_update(bool relative_reset) override; + virtual void check_osd_inputs() override; // input overrideables - virtual void customize_input_type_list(simple_list<input_type_entry> &typelist) override; + virtual void customize_input_type_list(std::vector<input_type_entry> &typelist) override; // video overridables virtual void add_audio_to_recording(const int16_t *buffer, int samples_this_frame) override; - virtual void video_register() override; - virtual bool video_init() override; virtual bool window_init() override; @@ -297,65 +79,38 @@ public: void extract_video_config(); - // windows osd specific - bool handle_input_event(input_event eventid, void *eventdata) const; + // windows OSD specific + bool handle_input_event(input_event eventid, const void *eventdata) const; bool should_hide_mouse() const; - void poll_input(running_machine &machine) const; + + virtual bool has_focus() const override; + virtual void process_events() override; virtual windows_options &options() override { return m_options; } int window_count(); -protected: - virtual void build_slider_list() override; - virtual void update_slider_list() override; - - void check_osd_inputs(); + using osd_common_t::poll_input_modules; // Win32 debugger calls this directly, which it shouldn't private: + void process_events(bool ingame, bool nodispatch); virtual void osd_exit() override; static void output_oslog(const char *buffer); - windows_options & m_options; + windows_options &m_options; + bool const m_com_status; - static const int DEFAULT_FONT_HEIGHT = 200; -}; + std::chrono::steady_clock::time_point m_last_event_check; -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - -ref class MameMainApp sealed : public Windows::ApplicationModel::Core::IFrameworkView -{ -private: - std::unique_ptr<windows_options> m_options; - std::unique_ptr<windows_osd_interface> m_osd; - -public: - MameMainApp(); - - // IFrameworkView Methods. - virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView); - virtual void SetWindow(Windows::UI::Core::CoreWindow^ window); - virtual void Load(Platform::String^ entryPoint); - virtual void Run(); - virtual void Uninitialize(); -}; - -ref class MameViewSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource -{ -public: - virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView(); + static inline constexpr int DEFAULT_FONT_HEIGHT = 200; }; -#endif //============================================================ // GLOBAL VARIABLES //============================================================ -extern const options_entry mame_win_options[]; - // defined in winwork.c extern int osd_num_processors; - -#endif +#endif // MAME_OSD_WINDOWS_WINMAIN_H diff --git a/src/osd/windows/winmenu.cpp b/src/osd/windows/winmenu.cpp deleted file mode 100644 index d55bd3e3a79..00000000000 --- a/src/osd/windows/winmenu.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles -//============================================================ -// -// winmenu.cpp - Win32 OSD core dummy menu implementation -// -//============================================================ - -// standard windows headers -#include <windows.h> - -#include "emu.h" - -#include "window.h" - -//============================================================ -// winwindow_video_window_proc_ui -// (window thread) -//============================================================ - -LRESULT CALLBACK winwindow_video_window_proc_ui(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam) -{ - return win_window_info::video_window_proc(wnd, message, wparam, lparam); -} - -//============================================================ -// win_create_menu -//============================================================ - -int win_create_menu(running_machine &machine, HMENU *menus) -{ - return 0; -} diff --git a/src/osd/windows/winopts.cpp b/src/osd/windows/winopts.cpp new file mode 100644 index 00000000000..0408593dda3 --- /dev/null +++ b/src/osd/windows/winopts.cpp @@ -0,0 +1,157 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +//============================================================ +// +// winopts.cpp - Win32 options +// +//============================================================ + +#include "winopts.h" + + +namespace { + +//************************************************************************** +// OPTIONS +//************************************************************************** + +options_entry const f_win_option_entries[] = +{ + // performance options + { nullptr, nullptr, core_options::option_type::HEADER, "WINDOWS PERFORMANCE OPTIONS" }, + { WINOPTION_PRIORITY "(-15-1)", "0", core_options::option_type::INTEGER, "thread priority for the main game thread; range from -15 to 1" }, + { WINOPTION_PROFILE, "0", core_options::option_type::INTEGER, "enables profiling, specifying the stack depth to track" }, + + // video options + { nullptr, nullptr, core_options::option_type::HEADER, "WINDOWS VIDEO OPTIONS" }, + { WINOPTION_ATTACH_WINDOW, "", core_options::option_type::STRING, "attach to arbitrary window" }, + + // post-processing options + { nullptr, nullptr, core_options::option_type::HEADER, "DIRECT3D POST-PROCESSING OPTIONS" }, + { WINOPTION_HLSLPATH, "hlsl", core_options::option_type::PATH, "path to HLSL support files" }, + { WINOPTION_HLSL_ENABLE";hlsl", "0", core_options::option_type::BOOLEAN, "enable HLSL post-processing (PS3.0 required)" }, + { WINOPTION_HLSL_OVERSAMPLING, "0", core_options::option_type::BOOLEAN, "enable HLSL oversampling" }, + { WINOPTION_HLSL_WRITE, OSDOPTVAL_AUTO, core_options::option_type::PATH, "enable HLSL AVI writing (huge disk bandwidth suggested)" }, + { WINOPTION_HLSL_SNAP_WIDTH, "2048", core_options::option_type::STRING, "HLSL upscaled-snapshot width" }, + { WINOPTION_HLSL_SNAP_HEIGHT, "1536", core_options::option_type::STRING, "HLSL upscaled-snapshot height" }, + { WINOPTION_SHADOW_MASK_TILE_MODE, "0", core_options::option_type::INTEGER, "shadow mask tile mode (0 for screen based, 1 for source based)" }, + { WINOPTION_SHADOW_MASK_ALPHA ";fs_shadwa(0.0-1.0)", "0.0", core_options::option_type::FLOAT, "shadow mask alpha-blend value (1.0 is fully blended, 0.0 is no mask)" }, + { WINOPTION_SHADOW_MASK_TEXTURE ";fs_shadwt(0.0-1.0)", "shadow-mask.png", core_options::option_type::STRING, "shadow mask texture name" }, + { WINOPTION_SHADOW_MASK_COUNT_X ";fs_shadww", "6", core_options::option_type::INTEGER, "shadow mask tile width, in screen dimensions" }, + { WINOPTION_SHADOW_MASK_COUNT_Y ";fs_shadwh", "4", core_options::option_type::INTEGER, "shadow mask tile height, in screen dimensions" }, + { WINOPTION_SHADOW_MASK_USIZE ";fs_shadwu(0.0-1.0)", "0.1875", core_options::option_type::FLOAT, "shadow mask texture width, in U/V dimensions" }, + { WINOPTION_SHADOW_MASK_VSIZE ";fs_shadwv(0.0-1.0)", "0.25", core_options::option_type::FLOAT, "shadow mask texture height, in U/V dimensions" }, + { WINOPTION_SHADOW_MASK_UOFFSET ";fs_shadwou(-1.0-1.0)", "0.0", core_options::option_type::FLOAT, "shadow mask texture offset, in U direction" }, + { WINOPTION_SHADOW_MASK_VOFFSET ";fs_shadwov(-1.0-1.0)", "0.0", core_options::option_type::FLOAT, "shadow mask texture offset, in V direction" }, + { WINOPTION_DISTORTION ";fs_dist(-1.0-1.0)", "0.0", core_options::option_type::FLOAT, "screen distortion amount" }, + { WINOPTION_CUBIC_DISTORTION ";fs_cubedist(-1.0-1.0)", "0.0", core_options::option_type::FLOAT, "screen cubic distortion amount" }, + { WINOPTION_DISTORT_CORNER ";fs_distc(0.0-1.0)", "0.0", core_options::option_type::FLOAT, "screen distort corner amount" }, + { WINOPTION_ROUND_CORNER ";fs_rndc(0.0-1.0)", "0.0", core_options::option_type::FLOAT, "screen round corner amount" }, + { WINOPTION_SMOOTH_BORDER ";fs_smob(0.0-1.0)", "0.0", core_options::option_type::FLOAT, "screen smooth border amount" }, + { WINOPTION_REFLECTION ";fs_ref(0.0-1.0)", "0.0", core_options::option_type::FLOAT, "screen reflection amount" }, + { WINOPTION_VIGNETTING ";fs_vig(0.0-1.0)", "0.0", core_options::option_type::FLOAT, "image vignetting amount" }, + // Beam-related values below this line + { WINOPTION_SCANLINE_AMOUNT ";fs_scanam(0.0-4.0)", "0.0", core_options::option_type::FLOAT, "overall alpha scaling value for scanlines" }, + { WINOPTION_SCANLINE_SCALE ";fs_scansc(0.0-4.0)", "1.0", core_options::option_type::FLOAT, "overall height scaling value for scanlines" }, + { WINOPTION_SCANLINE_HEIGHT ";fs_scanh(0.0-4.0)", "1.0", core_options::option_type::FLOAT, "individual height scaling value for scanlines" }, + { WINOPTION_SCANLINE_VARIATION ";fs_scanv(0.0-4.0)", "1.0", core_options::option_type::FLOAT, "individual height varying value for scanlines" }, + { WINOPTION_SCANLINE_BRIGHT_SCALE ";fs_scanbs(0.0-2.0)", "1.0", core_options::option_type::FLOAT, "overall brightness scaling value for scanlines (multiplicative)" }, + { WINOPTION_SCANLINE_BRIGHT_OFFSET ";fs_scanbo(0.0-1.0)", "0.0", core_options::option_type::FLOAT, "overall brightness offset value for scanlines (additive)" }, + { WINOPTION_SCANLINE_JITTER ";fs_scanjt(0.0-4.0)", "0.0", core_options::option_type::FLOAT, "overall interlace jitter scaling value for scanlines" }, + { WINOPTION_HUM_BAR_ALPHA ";fs_humba(0.0-1.0)", "0.0", core_options::option_type::FLOAT, "overall alpha scaling value for hum bar" }, + { WINOPTION_DEFOCUS ";fs_focus", "0.0,0.0", core_options::option_type::STRING, "overall defocus value in screen-relative coords" }, + { WINOPTION_CONVERGE_X ";fs_convx", "0.0,0.0,0.0", core_options::option_type::STRING, "convergence in screen-relative X direction" }, + { WINOPTION_CONVERGE_Y ";fs_convy", "0.0,0.0,0.0", core_options::option_type::STRING, "convergence in screen-relative Y direction" }, + { WINOPTION_RADIAL_CONVERGE_X ";fs_rconvx", "0.0,0.0,0.0", core_options::option_type::STRING, "radial convergence in screen-relative X direction" }, + { WINOPTION_RADIAL_CONVERGE_Y ";fs_rconvy", "0.0,0.0,0.0", core_options::option_type::STRING, "radial convergence in screen-relative Y direction" }, + // RGB colorspace convolution below this line + { WINOPTION_RED_RATIO ";fs_redratio", "1.0,0.0,0.0", core_options::option_type::STRING, "red output signal generated by input signal" }, + { WINOPTION_GRN_RATIO ";fs_grnratio", "0.0,1.0,0.0", core_options::option_type::STRING, "green output signal generated by input signal" }, + { WINOPTION_BLU_RATIO ";fs_bluratio", "0.0,0.0,1.0", core_options::option_type::STRING, "blue output signal generated by input signal" }, + { WINOPTION_SATURATION ";fs_sat(0.0-4.0)", "1.0", core_options::option_type::FLOAT, "saturation scaling value" }, + { WINOPTION_OFFSET ";fs_offset", "0.0,0.0,0.0", core_options::option_type::STRING, "signal offset value (additive)" }, + { WINOPTION_SCALE ";fs_scale", "1.0,1.0,1.0", core_options::option_type::STRING, "signal scaling value (multiplicative)" }, + { WINOPTION_POWER ";fs_power", "1.0,1.0,1.0", core_options::option_type::STRING, "signal power value (exponential)" }, + { WINOPTION_FLOOR ";fs_floor", "0.0,0.0,0.0", core_options::option_type::STRING, "signal floor level" }, + { WINOPTION_PHOSPHOR";fs_phosphor", "0.0,0.0,0.0", core_options::option_type::STRING, "phosphorescence decay rate (0.0 is instant, 1.0 is forever)" }, + { WINOPTION_CHROMA_MODE, "3", core_options::option_type::INTEGER, "number of phosphors to use: 1 - monochrome, 2 - dichrome, 3 - trichrome (color)" }, + { WINOPTION_CHROMA_CONVERSION_GAIN, "0.299,0.587,0.114", core_options::option_type::STRING, "gain to be applied when summing RGB signal for monochrome and dichrome modes" }, + { WINOPTION_CHROMA_A, "0.64,0.33", core_options::option_type::STRING, "chromaticity coordinate for first phosphor" }, + { WINOPTION_CHROMA_B, "0.30,0.60", core_options::option_type::STRING, "chromaticity coordinate for second phosphor" }, + { WINOPTION_CHROMA_C, "0.15,0.06", core_options::option_type::STRING, "chromaticity coordinate for third phosphor" }, + { WINOPTION_CHROMA_Y_GAIN, "0.2126,0.7152,0.0722", core_options::option_type::STRING, "gain to be applied for each phosphor" }, + // NTSC simulation below this line + { nullptr, nullptr, core_options::option_type::HEADER, "NTSC POST-PROCESSING OPTIONS" }, + { WINOPTION_YIQ_ENABLE ";yiq", "0", core_options::option_type::BOOLEAN, "enable YIQ-space HLSL post-processing" }, + { WINOPTION_YIQ_JITTER ";yiqj", "0.0", core_options::option_type::FLOAT, "jitter for the NTSC signal processing" }, + { WINOPTION_YIQ_CCVALUE ";yiqcc", "3.57954545", core_options::option_type::FLOAT, "color carrier frequency for NTSC signal processing" }, + { WINOPTION_YIQ_AVALUE ";yiqa", "0.5", core_options::option_type::FLOAT, "A value for NTSC signal processing" }, + { WINOPTION_YIQ_BVALUE ";yiqb", "0.5", core_options::option_type::FLOAT, "B value for NTSC signal processing" }, + { WINOPTION_YIQ_OVALUE ";yiqo", "0.0", core_options::option_type::FLOAT, "outgoing Color Carrier phase offset for NTSC signal processing" }, + { WINOPTION_YIQ_PVALUE ";yiqp", "1.0", core_options::option_type::FLOAT, "incoming Pixel Clock scaling value for NTSC signal processing" }, + { WINOPTION_YIQ_NVALUE ";yiqn", "1.0", core_options::option_type::FLOAT, "Y filter notch width for NTSC signal processing" }, + { WINOPTION_YIQ_YVALUE ";yiqy", "6.0", core_options::option_type::FLOAT, "Y filter cutoff frequency for NTSC signal processing" }, + { WINOPTION_YIQ_IVALUE ";yiqi", "1.2", core_options::option_type::FLOAT, "I filter cutoff frequency for NTSC signal processing" }, + { WINOPTION_YIQ_QVALUE ";yiqq", "0.6", core_options::option_type::FLOAT, "Q filter cutoff frequency for NTSC signal processing" }, + { WINOPTION_YIQ_SCAN_TIME ";yiqsc", "52.6", core_options::option_type::FLOAT, "horizontal scanline duration for NTSC signal processing (microseconds)" }, + { WINOPTION_YIQ_PHASE_COUNT ";yiqpc", "2", core_options::option_type::INTEGER, "phase count value for NTSC signal processing" }, + // Vector simulation below this line + { nullptr, nullptr, core_options::option_type::HEADER, "VECTOR POST-PROCESSING OPTIONS" }, + { WINOPTION_VECTOR_BEAM_SMOOTH ";vecsmooth", "0.0", core_options::option_type::FLOAT, "vector beam smoothness" }, + { WINOPTION_VECTOR_LENGTH_SCALE ";vecscale", "0.5", core_options::option_type::FLOAT, "maximum vector attenuation" }, + { WINOPTION_VECTOR_LENGTH_RATIO ";vecratio", "0.5", core_options::option_type::FLOAT, "minimum vector length affected by attenuation (vector length to screen size ratio)" }, + // Bloom below this line + { nullptr, nullptr, core_options::option_type::HEADER, "BLOOM POST-PROCESSING OPTIONS" }, + { WINOPTION_BLOOM_BLEND_MODE, "0", core_options::option_type::INTEGER, "bloom blend mode (0 for brighten, 1 for darken)" }, + { WINOPTION_BLOOM_SCALE, "0.0", core_options::option_type::FLOAT, "intensity factor for bloom" }, + { WINOPTION_BLOOM_OVERDRIVE, "1.0,1.0,1.0", core_options::option_type::STRING, "overdrive factor for bloom" }, + { WINOPTION_BLOOM_LEVEL0_WEIGHT, "1.0", core_options::option_type::FLOAT, "bloom level 0 weight (full-size target)" }, + { WINOPTION_BLOOM_LEVEL1_WEIGHT, "0.64", core_options::option_type::FLOAT, "bloom level 1 weight (1/4 smaller that level 0 target)" }, + { WINOPTION_BLOOM_LEVEL2_WEIGHT, "0.32", core_options::option_type::FLOAT, "bloom level 2 weight (1/4 smaller that level 1 target)" }, + { WINOPTION_BLOOM_LEVEL3_WEIGHT, "0.16", core_options::option_type::FLOAT, "bloom level 3 weight (1/4 smaller that level 2 target)" }, + { WINOPTION_BLOOM_LEVEL4_WEIGHT, "0.08", core_options::option_type::FLOAT, "bloom level 4 weight (1/4 smaller that level 3 target)" }, + { WINOPTION_BLOOM_LEVEL5_WEIGHT, "0.06", core_options::option_type::FLOAT, "bloom level 5 weight (1/4 smaller that level 4 target)" }, + { WINOPTION_BLOOM_LEVEL6_WEIGHT, "0.04", core_options::option_type::FLOAT, "bloom level 6 weight (1/4 smaller that level 5 target)" }, + { WINOPTION_BLOOM_LEVEL7_WEIGHT, "0.02", core_options::option_type::FLOAT, "bloom level 7 weight (1/4 smaller that level 6 target)" }, + { WINOPTION_BLOOM_LEVEL8_WEIGHT, "0.01", core_options::option_type::FLOAT, "bloom level 8 weight (1/4 smaller that level 7 target)" }, + { WINOPTION_LUT_TEXTURE, "lut-default.png", core_options::option_type::PATH, "3D LUT texture filename for screen, PNG format" }, + { WINOPTION_LUT_ENABLE, "0", core_options::option_type::BOOLEAN, "Enables 3D LUT to be applied to screen after post-processing" }, + { WINOPTION_UI_LUT_TEXTURE, "lut-default.png", core_options::option_type::PATH, "3D LUT texture filename of UI, PNG format" }, + { WINOPTION_UI_LUT_ENABLE, "0", core_options::option_type::BOOLEAN, "enable 3D LUT to be applied to UI and artwork after post-processing" }, + + // full screen options + { nullptr, nullptr, core_options::option_type::HEADER, "FULL SCREEN OPTIONS" }, + { WINOPTION_TRIPLEBUFFER ";tb", "0", core_options::option_type::BOOLEAN, "enable triple buffering" }, + { WINOPTION_FULLSCREENBRIGHTNESS ";fsb(0.1-2.0)", "1.0", core_options::option_type::FLOAT, "brightness value in full screen mode" }, + { WINOPTION_FULLSCREENCONTRAST ";fsc(0.1-2.0)", "1.0", core_options::option_type::FLOAT, "contrast value in full screen mode" }, + { WINOPTION_FULLSCREENGAMMA ";fsg(0.1-3.0)", "1.0", core_options::option_type::FLOAT, "gamma value in full screen mode" }, + + // input options + { nullptr, nullptr, core_options::option_type::HEADER, "INPUT DEVICE OPTIONS" }, + { WINOPTION_DUAL_LIGHTGUN ";dual", "0", core_options::option_type::BOOLEAN, "enable dual lightgun input" }, + + { nullptr } +}; + +} // anonymous namespace + + +//============================================================ +// windows_options +//============================================================ + +windows_options::windows_options() : osd_options() +{ + add_entries(f_win_option_entries); +} + + +//============================================================ +// osd_setup_osd_specific_emu_options +//============================================================ + +void osd_setup_osd_specific_emu_options(emu_options &opts) +{ + opts.add_entries(osd_options::s_option_entries); + opts.add_entries(f_win_option_entries); +} diff --git a/src/osd/windows/winopts.h b/src/osd/windows/winopts.h new file mode 100644 index 00000000000..44936f2d192 --- /dev/null +++ b/src/osd/windows/winopts.h @@ -0,0 +1,232 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +//============================================================ +// +// winopts.h - Win32 options +// +//============================================================ +#ifndef MAME_OSD_WINDOWS_WINOPTS_H +#define MAME_OSD_WINDOWS_WINOPTS_H + +#pragma once + +#include "modules/lib/osdobj_common.h" + + +//============================================================ +// Option identifiers +//============================================================ + +// performance options +#define WINOPTION_PRIORITY "priority" +#define WINOPTION_PROFILE "profile" + +// video options +#define WINOPTION_ATTACH_WINDOW "attach_window" + +// core post-processing options +#define WINOPTION_HLSLPATH "hlslpath" +#define WINOPTION_HLSL_ENABLE "hlsl_enable" +#define WINOPTION_HLSL_OVERSAMPLING "hlsl_oversampling" +#define WINOPTION_HLSL_WRITE "hlsl_write" +#define WINOPTION_HLSL_SNAP_WIDTH "hlsl_snap_width" +#define WINOPTION_HLSL_SNAP_HEIGHT "hlsl_snap_height" +#define WINOPTION_SHADOW_MASK_TILE_MODE "shadow_mask_tile_mode" +#define WINOPTION_SHADOW_MASK_ALPHA "shadow_mask_alpha" +#define WINOPTION_SHADOW_MASK_TEXTURE "shadow_mask_texture" +#define WINOPTION_SHADOW_MASK_COUNT_X "shadow_mask_x_count" +#define WINOPTION_SHADOW_MASK_COUNT_Y "shadow_mask_y_count" +#define WINOPTION_SHADOW_MASK_USIZE "shadow_mask_usize" +#define WINOPTION_SHADOW_MASK_VSIZE "shadow_mask_vsize" +#define WINOPTION_SHADOW_MASK_UOFFSET "shadow_mask_uoffset" +#define WINOPTION_SHADOW_MASK_VOFFSET "shadow_mask_voffset" +#define WINOPTION_REFLECTION "reflection" +#define WINOPTION_DISTORTION "distortion" +#define WINOPTION_CUBIC_DISTORTION "cubic_distortion" +#define WINOPTION_DISTORT_CORNER "distort_corner" +#define WINOPTION_ROUND_CORNER "round_corner" +#define WINOPTION_SMOOTH_BORDER "smooth_border" +#define WINOPTION_VIGNETTING "vignetting" +#define WINOPTION_SCANLINE_AMOUNT "scanline_alpha" +#define WINOPTION_SCANLINE_SCALE "scanline_size" +#define WINOPTION_SCANLINE_HEIGHT "scanline_height" +#define WINOPTION_SCANLINE_VARIATION "scanline_variation" +#define WINOPTION_SCANLINE_BRIGHT_SCALE "scanline_bright_scale" +#define WINOPTION_SCANLINE_BRIGHT_OFFSET "scanline_bright_offset" +#define WINOPTION_SCANLINE_JITTER "scanline_jitter" +#define WINOPTION_HUM_BAR_ALPHA "hum_bar_alpha" +#define WINOPTION_DEFOCUS "defocus" +#define WINOPTION_CONVERGE_X "converge_x" +#define WINOPTION_CONVERGE_Y "converge_y" +#define WINOPTION_RADIAL_CONVERGE_X "radial_converge_x" +#define WINOPTION_RADIAL_CONVERGE_Y "radial_converge_y" +#define WINOPTION_RED_RATIO "red_ratio" +#define WINOPTION_GRN_RATIO "grn_ratio" +#define WINOPTION_BLU_RATIO "blu_ratio" +#define WINOPTION_OFFSET "offset" +#define WINOPTION_SCALE "scale" +#define WINOPTION_POWER "power" +#define WINOPTION_FLOOR "floor" +#define WINOPTION_PHOSPHOR "phosphor_life" +#define WINOPTION_SATURATION "saturation" +#define WINOPTION_CHROMA_MODE "chroma_mode" +#define WINOPTION_CHROMA_CONVERSION_GAIN "chroma_conversion_gain" +#define WINOPTION_CHROMA_A "chroma_a" +#define WINOPTION_CHROMA_B "chroma_b" +#define WINOPTION_CHROMA_C "chroma_c" +#define WINOPTION_CHROMA_Y_GAIN "chroma_y_gain" +#define WINOPTION_YIQ_ENABLE "yiq_enable" +#define WINOPTION_YIQ_JITTER "yiq_jitter" +#define WINOPTION_YIQ_CCVALUE "yiq_cc" +#define WINOPTION_YIQ_AVALUE "yiq_a" +#define WINOPTION_YIQ_BVALUE "yiq_b" +#define WINOPTION_YIQ_OVALUE "yiq_o" +#define WINOPTION_YIQ_PVALUE "yiq_p" +#define WINOPTION_YIQ_NVALUE "yiq_n" +#define WINOPTION_YIQ_YVALUE "yiq_y" +#define WINOPTION_YIQ_IVALUE "yiq_i" +#define WINOPTION_YIQ_QVALUE "yiq_q" +#define WINOPTION_YIQ_SCAN_TIME "yiq_scan_time" +#define WINOPTION_YIQ_PHASE_COUNT "yiq_phase_count" +#define WINOPTION_VECTOR_BEAM_SMOOTH "vector_beam_smooth" +#define WINOPTION_VECTOR_LENGTH_SCALE "vector_length_scale" +#define WINOPTION_VECTOR_LENGTH_RATIO "vector_length_ratio" +#define WINOPTION_BLOOM_BLEND_MODE "bloom_blend_mode" +#define WINOPTION_BLOOM_SCALE "bloom_scale" +#define WINOPTION_BLOOM_OVERDRIVE "bloom_overdrive" +#define WINOPTION_BLOOM_LEVEL0_WEIGHT "bloom_lvl0_weight" +#define WINOPTION_BLOOM_LEVEL1_WEIGHT "bloom_lvl1_weight" +#define WINOPTION_BLOOM_LEVEL2_WEIGHT "bloom_lvl2_weight" +#define WINOPTION_BLOOM_LEVEL3_WEIGHT "bloom_lvl3_weight" +#define WINOPTION_BLOOM_LEVEL4_WEIGHT "bloom_lvl4_weight" +#define WINOPTION_BLOOM_LEVEL5_WEIGHT "bloom_lvl5_weight" +#define WINOPTION_BLOOM_LEVEL6_WEIGHT "bloom_lvl6_weight" +#define WINOPTION_BLOOM_LEVEL7_WEIGHT "bloom_lvl7_weight" +#define WINOPTION_BLOOM_LEVEL8_WEIGHT "bloom_lvl8_weight" +#define WINOPTION_LUT_TEXTURE "lut_texture" +#define WINOPTION_LUT_ENABLE "lut_enable" +#define WINOPTION_UI_LUT_TEXTURE "ui_lut_texture" +#define WINOPTION_UI_LUT_ENABLE "ui_lut_enable" + +// full screen options +#define WINOPTION_TRIPLEBUFFER "triplebuffer" +#define WINOPTION_FULLSCREENBRIGHTNESS "full_screen_brightness" +#define WINOPTION_FULLSCREENCONTRAST "full_screen_contrast" +#define WINOPTION_FULLSCREENGAMMA "full_screen_gamma" + +// input options +#define WINOPTION_DUAL_LIGHTGUN "dual_lightgun" + + +//============================================================ +// TYPE DEFINITIONS +//============================================================ + +class windows_options : public osd_options +{ +public: + // construction/destruction + windows_options(); + + // performance options + int priority() const { return int_value(WINOPTION_PRIORITY); } + int profile() const { return int_value(WINOPTION_PROFILE); } + + // video options + const char *attach_window() const { return value(WINOPTION_ATTACH_WINDOW); } + + // core post-processing options + const char *screen_post_fx_dir() const { return value(WINOPTION_HLSLPATH); } + bool d3d_hlsl_enable() const { return bool_value(WINOPTION_HLSL_ENABLE); } + bool d3d_hlsl_oversampling() const { return bool_value(WINOPTION_HLSL_OVERSAMPLING); } + const char *d3d_hlsl_write() const { return value(WINOPTION_HLSL_WRITE); } + int d3d_snap_width() const { return int_value(WINOPTION_HLSL_SNAP_WIDTH); } + int d3d_snap_height() const { return int_value(WINOPTION_HLSL_SNAP_HEIGHT); } + int screen_shadow_mask_tile_mode() const { return int_value(WINOPTION_SHADOW_MASK_TILE_MODE); } + float screen_shadow_mask_alpha() const { return float_value(WINOPTION_SHADOW_MASK_ALPHA); } + const char *screen_shadow_mask_texture() const { return value(WINOPTION_SHADOW_MASK_TEXTURE); } + int screen_shadow_mask_count_x() const { return int_value(WINOPTION_SHADOW_MASK_COUNT_X); } + int screen_shadow_mask_count_y() const { return int_value(WINOPTION_SHADOW_MASK_COUNT_Y); } + float screen_shadow_mask_u_size() const { return float_value(WINOPTION_SHADOW_MASK_USIZE); } + float screen_shadow_mask_v_size() const { return float_value(WINOPTION_SHADOW_MASK_VSIZE); } + float screen_shadow_mask_u_offset() const { return float_value(WINOPTION_SHADOW_MASK_UOFFSET); } + float screen_shadow_mask_v_offset() const { return float_value(WINOPTION_SHADOW_MASK_VOFFSET); } + float screen_scanline_amount() const { return float_value(WINOPTION_SCANLINE_AMOUNT); } + float screen_scanline_scale() const { return float_value(WINOPTION_SCANLINE_SCALE); } + float screen_scanline_height() const { return float_value(WINOPTION_SCANLINE_HEIGHT); } + float screen_scanline_variation() const { return float_value(WINOPTION_SCANLINE_VARIATION); } + float screen_scanline_bright_scale() const { return float_value(WINOPTION_SCANLINE_BRIGHT_SCALE); } + float screen_scanline_bright_offset() const { return float_value(WINOPTION_SCANLINE_BRIGHT_OFFSET); } + float screen_scanline_jitter() const { return float_value(WINOPTION_SCANLINE_JITTER); } + float screen_hum_bar_alpha() const { return float_value(WINOPTION_HUM_BAR_ALPHA); } + float screen_reflection() const { return float_value(WINOPTION_REFLECTION); } + float screen_distortion() const { return float_value(WINOPTION_DISTORTION); } + float screen_cubic_distortion() const { return float_value(WINOPTION_CUBIC_DISTORTION); } + float screen_distort_corner() const { return float_value(WINOPTION_DISTORT_CORNER); } + float screen_round_corner() const { return float_value(WINOPTION_ROUND_CORNER); } + float screen_smooth_border() const { return float_value(WINOPTION_SMOOTH_BORDER); } + float screen_vignetting() const { return float_value(WINOPTION_VIGNETTING); } + const char *screen_defocus() const { return value(WINOPTION_DEFOCUS); } + const char *screen_converge_x() const { return value(WINOPTION_CONVERGE_X); } + const char *screen_converge_y() const { return value(WINOPTION_CONVERGE_Y); } + const char *screen_radial_converge_x() const { return value(WINOPTION_RADIAL_CONVERGE_X); } + const char *screen_radial_converge_y() const { return value(WINOPTION_RADIAL_CONVERGE_Y); } + const char *screen_red_ratio() const { return value(WINOPTION_RED_RATIO); } + const char *screen_grn_ratio() const { return value(WINOPTION_GRN_RATIO); } + const char *screen_blu_ratio() const { return value(WINOPTION_BLU_RATIO); } + bool screen_yiq_enable() const { return bool_value(WINOPTION_YIQ_ENABLE); } + float screen_yiq_jitter() const { return float_value(WINOPTION_YIQ_JITTER); } + float screen_yiq_cc() const { return float_value(WINOPTION_YIQ_CCVALUE); } + float screen_yiq_a() const { return float_value(WINOPTION_YIQ_AVALUE); } + float screen_yiq_b() const { return float_value(WINOPTION_YIQ_BVALUE); } + float screen_yiq_o() const { return float_value(WINOPTION_YIQ_OVALUE); } + float screen_yiq_p() const { return float_value(WINOPTION_YIQ_PVALUE); } + float screen_yiq_n() const { return float_value(WINOPTION_YIQ_NVALUE); } + float screen_yiq_y() const { return float_value(WINOPTION_YIQ_YVALUE); } + float screen_yiq_i() const { return float_value(WINOPTION_YIQ_IVALUE); } + float screen_yiq_q() const { return float_value(WINOPTION_YIQ_QVALUE); } + float screen_yiq_scan_time() const { return float_value(WINOPTION_YIQ_SCAN_TIME); } + int screen_yiq_phase_count() const { return int_value(WINOPTION_YIQ_PHASE_COUNT); } + float screen_vector_beam_smooth() const { return float_value(WINOPTION_VECTOR_BEAM_SMOOTH); } + float screen_vector_length_scale() const { return float_value(WINOPTION_VECTOR_LENGTH_SCALE); } + float screen_vector_length_ratio() const { return float_value(WINOPTION_VECTOR_LENGTH_RATIO); } + int screen_bloom_blend_mode() const { return int_value(WINOPTION_BLOOM_BLEND_MODE); } + float screen_bloom_scale() const { return float_value(WINOPTION_BLOOM_SCALE); } + const char *screen_bloom_overdrive() const { return value(WINOPTION_BLOOM_OVERDRIVE); } + float screen_bloom_lvl0_weight() const { return float_value(WINOPTION_BLOOM_LEVEL0_WEIGHT); } + float screen_bloom_lvl1_weight() const { return float_value(WINOPTION_BLOOM_LEVEL1_WEIGHT); } + float screen_bloom_lvl2_weight() const { return float_value(WINOPTION_BLOOM_LEVEL2_WEIGHT); } + float screen_bloom_lvl3_weight() const { return float_value(WINOPTION_BLOOM_LEVEL3_WEIGHT); } + float screen_bloom_lvl4_weight() const { return float_value(WINOPTION_BLOOM_LEVEL4_WEIGHT); } + float screen_bloom_lvl5_weight() const { return float_value(WINOPTION_BLOOM_LEVEL5_WEIGHT); } + float screen_bloom_lvl6_weight() const { return float_value(WINOPTION_BLOOM_LEVEL6_WEIGHT); } + float screen_bloom_lvl7_weight() const { return float_value(WINOPTION_BLOOM_LEVEL7_WEIGHT); } + float screen_bloom_lvl8_weight() const { return float_value(WINOPTION_BLOOM_LEVEL8_WEIGHT); } + const char *screen_offset() const { return value(WINOPTION_OFFSET); } + const char *screen_scale() const { return value(WINOPTION_SCALE); } + const char *screen_power() const { return value(WINOPTION_POWER); } + const char *screen_floor() const { return value(WINOPTION_FLOOR); } + const char *screen_phosphor() const { return value(WINOPTION_PHOSPHOR); } + float screen_saturation() const { return float_value(WINOPTION_SATURATION); } + int screen_chroma_mode() const { return int_value(WINOPTION_CHROMA_MODE); } + const char *screen_chroma_a() const { return value(WINOPTION_CHROMA_A); } + const char *screen_chroma_b() const { return value(WINOPTION_CHROMA_B); } + const char *screen_chroma_c() const { return value(WINOPTION_CHROMA_C); } + const char *screen_chroma_conversion_gain() const { return value(WINOPTION_CHROMA_CONVERSION_GAIN); } + const char *screen_chroma_y_gain() const { return value(WINOPTION_CHROMA_Y_GAIN); } + const char *screen_lut_texture() const { return value(WINOPTION_LUT_TEXTURE); } + bool screen_lut_enable() const { return bool_value(WINOPTION_LUT_ENABLE); } + const char *ui_lut_texture() const { return value(WINOPTION_UI_LUT_TEXTURE); } + bool ui_lut_enable() const { return bool_value(WINOPTION_UI_LUT_ENABLE); } + + // full screen options + bool triple_buffer() const { return bool_value(WINOPTION_TRIPLEBUFFER); } + float full_screen_brightness() const { return float_value(WINOPTION_FULLSCREENBRIGHTNESS); } + float full_screen_contrast() const { return float_value(WINOPTION_FULLSCREENCONTRAST); } + float full_screen_gamma() const { return float_value(WINOPTION_FULLSCREENGAMMA); } + + // input options + bool dual_lightgun() const { return bool_value(WINOPTION_DUAL_LIGHTGUN); } +}; + +#endif // MAME_OSD_WINDOWS_WINOPTS_H diff --git a/src/osd/windows/winutf8.cpp b/src/osd/windows/winutf8.cpp index a860aeb55cc..cdb0e87a86b 100644 --- a/src/osd/windows/winutf8.cpp +++ b/src/osd/windows/winutf8.cpp @@ -10,7 +10,7 @@ #include "winutf8.h" #include "strconv.h" -#include <stdlib.h> +#include <cstdlib> // standard windows headers #include <shellapi.h> @@ -27,8 +27,6 @@ void win_output_debug_string_utf8(const char *string) } -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - //============================================================ // win_message_box_utf8 //============================================================ @@ -55,9 +53,6 @@ int win_message_box_utf8(HWND window, const char *text, const char *caption, UIN return MessageBox(window, t_text, t_caption, type); } -#endif - - //============================================================ // win_set_window_text_utf8 @@ -75,13 +70,7 @@ BOOL win_set_window_text_utf8(HWND window, const char *text) t_text = ts_text.c_str(); } -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) result = SetWindowText(window, t_text); -#else - Windows::UI::ViewManagement::ApplicationView::GetForCurrentView()->Title = ref new Platform::String(t_text); - result = TRUE; -#endif - return result; } @@ -93,30 +82,17 @@ BOOL win_set_window_text_utf8(HWND window, const char *text) std::string win_get_window_text_utf8(HWND window) { -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - { - // invoke the core Win32 API - int length = GetWindowTextLength(window); - if (length <= 0) - return std::string(); - - TCHAR *buffer = (TCHAR *) alloca((length + 1) * sizeof(TCHAR)); - GetWindowText(window, buffer, length + 1); - return osd::text::from_tstring(buffer); - } -#else - { - TCHAR t_buffer[256]; - auto title = Windows::UI::ViewManagement::ApplicationView::GetForCurrentView()->Title; - wcsncpy(t_buffer, title->Data(), ARRAY_LENGTH(t_buffer)); - return osd::text::from_tstring(t_buffer); - } -#endif + // invoke the core Win32 API + int length = GetWindowTextLength(window); + if (length <= 0) + return std::string(); + + auto *buffer = (TCHAR *) alloca((length + 1) * sizeof(TCHAR)); + GetWindowText(window, buffer, length + 1); + return osd::text::from_tstring(buffer); } -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - //============================================================ // win_create_window_ex_utf8 //============================================================ @@ -138,5 +114,3 @@ HWND win_create_window_ex_utf8(DWORD exstyle, const char* classname, const char* return CreateWindowEx(exstyle, ts_classname.c_str(), t_windowname, style, x, y, width, height, parent, menu, instance, param); } - -#endif diff --git a/src/osd/windows/winutil.cpp b/src/osd/windows/winutil.cpp index c06b4d2eee2..55b11f27522 100644 --- a/src/osd/windows/winutil.cpp +++ b/src/osd/windows/winutil.cpp @@ -6,17 +6,17 @@ // //============================================================ -// standard windows headers -#include <windows.h> -#include <direct.h> +#include "winutil.h" -// MAME headers -#include "emu.h" +// lib/util +#include "timeconv.h" -// MAMEOS headers -#include "winutil.h" +// osd #include "strconv.h" -#include "timeconv.h" + +// standard windows headers +#include <windows.h> +#include <direct.h> //============================================================ @@ -51,7 +51,7 @@ std::chrono::system_clock::time_point win_time_point_from_filetime(LPFILETIME fi // win_is_gui_application //============================================================ -BOOL win_is_gui_application(void) +BOOL win_is_gui_application() { static BOOL is_gui_frontend; static BOOL is_first_time = TRUE; @@ -101,17 +101,22 @@ BOOL win_is_gui_application(void) //============================================================ // osd_subst_env //============================================================ -void osd_subst_env(std::string &dst, const std::string &src) +std::string osd_subst_env(std::string_view src) { - TCHAR buffer[MAX_PATH]; - - osd::text::tstring t_src = osd::text::to_tstring(src); -#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP) - ExpandEnvironmentStrings(t_src.c_str(), buffer, ARRAY_LENGTH(buffer)); -#else - wcsncpy(buffer, t_src.c_str(), ARRAY_LENGTH(buffer)); -#endif - osd::text::from_tstring(dst, buffer); + std::wstring const w_src = osd::text::to_wstring(src); + std::vector<wchar_t> buffer(w_src.size() + 2); + DWORD length(ExpandEnvironmentStringsW(w_src.c_str(), &buffer[0], buffer.size())); + while (length && (buffer.size() < length)) + { + buffer.clear(); + buffer.resize(length + 1); + length = ExpandEnvironmentStringsW(w_src.c_str(), &buffer[0], buffer.size()); + } + + std::string dst; + if (length) + osd::text::from_wstring(dst, &buffer[0]); + return dst; } //------------------------------------------------- @@ -120,7 +125,75 @@ void osd_subst_env(std::string &dst, const std::string &src) HMODULE WINAPI GetModuleHandleUni() { - MEMORY_BASIC_INFORMATION mbi; - VirtualQuery((LPCVOID)GetModuleHandleUni, &mbi, sizeof(mbi)); - return (HMODULE)mbi.AllocationBase; + HMODULE result = nullptr; + BOOL const succeeded = GetModuleHandleEx( + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + LPCWSTR(uintptr_t(&GetModuleHandleUni)), + &result); + return succeeded ? result : nullptr; +} + + +//============================================================ +// win_error_to_error_condition +//============================================================ + +std::error_condition win_error_to_error_condition(DWORD error) noexcept +{ + // TODO: work out if there's a better way to do this + switch (error) + { + case ERROR_SUCCESS: + return std::error_condition(); + + case ERROR_INVALID_HANDLE: + return std::errc::bad_file_descriptor; + + case ERROR_OUTOFMEMORY: + return std::errc::not_enough_memory; + + case ERROR_NOT_SUPPORTED: + return std::errc::not_supported; + + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + case ERROR_INVALID_NAME: + return std::errc::no_such_file_or_directory; + + case ERROR_FILENAME_EXCED_RANGE: + return std::errc::filename_too_long; + + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + return std::errc::permission_denied; + + case ERROR_ALREADY_EXISTS: + return std::errc::file_exists; + + case ERROR_TOO_MANY_OPEN_FILES: + return std::errc::too_many_files_open; + + case ERROR_WRITE_FAULT: + case ERROR_READ_FAULT: + return std::errc::io_error; + + case ERROR_HANDLE_DISK_FULL: + case ERROR_DISK_FULL: + return std::errc::no_space_on_device; + + case ERROR_PATH_BUSY: + case ERROR_BUSY: + return std::errc::device_or_resource_busy; + + case ERROR_FILE_TOO_LARGE: + return std::errc::file_too_large; + + case ERROR_INVALID_ACCESS: + case ERROR_NEGATIVE_SEEK: + case ERROR_BAD_ARGUMENTS: + return std::errc::invalid_argument; + + default: + return std::error_condition(error, std::system_category()); + } } diff --git a/src/osd/windows/winutil.h b/src/osd/windows/winutil.h index 57470bf1372..85393b6b930 100644 --- a/src/osd/windows/winutil.h +++ b/src/osd/windows/winutil.h @@ -6,18 +6,25 @@ // //============================================================ -#ifndef __WINUTIL__ -#define __WINUTIL__ +#ifndef MAME_OSD_WINDOWS_WINUTIL_H +#define MAME_OSD_WINDOWS_WINUTIL_H + +#pragma once + +#include "osdfile.h" -#include "osdcore.h" -#include <string> -#include <vector> #include <chrono> +#include <system_error> + +#include <windows.h> + // Shared code osd::directory::entry::entry_type win_attributes_to_entry_type(DWORD attributes); std::chrono::system_clock::time_point win_time_point_from_filetime(LPFILETIME file_time); -BOOL win_is_gui_application(void); +BOOL win_is_gui_application(); HMODULE WINAPI GetModuleHandleUni(); -#endif // __WINUTIL__ +std::error_condition win_error_to_error_condition(DWORD error) noexcept; + +#endif // MAME_OSD_WINDOWS_WINUTIL_H |