summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/windows
diff options
context:
space:
mode:
Diffstat (limited to 'src/osd/windows')
-rw-r--r--src/osd/windows/ledutil.cpp6
-rw-r--r--src/osd/windows/main.cpp34
-rw-r--r--src/osd/windows/video.cpp129
-rw-r--r--src/osd/windows/window.cpp1555
-rw-r--r--src/osd/windows/window.h169
-rw-r--r--src/osd/windows/winmain.cpp423
-rw-r--r--src/osd/windows/winmain.h309
-rw-r--r--src/osd/windows/winmenu.cpp33
-rw-r--r--src/osd/windows/winopts.cpp157
-rw-r--r--src/osd/windows/winopts.h232
-rw-r--r--src/osd/windows/winutf8.cpp44
-rw-r--r--src/osd/windows/winutil.cpp117
-rw-r--r--src/osd/windows/winutil.h21
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