Creating an -attach_window command line parameter on Windows to attach to an existing window (#5381)

* Creating an -attach_window command line parameter on Windows to attach
to an existing window

* Moved -attach_window option to Windows-specific code

* Created an osd_set_aggressive_input_focus() function and exposed to LUA

* Created a dummy implementation of osd_set_aggressive_input_focus() for
SDL
This commit is contained in:
npwoods 2019-08-04 15:49:31 -04:00 committed by R. Belmont
parent 16b1ed88f6
commit fe3caae2a4
10 changed files with 176 additions and 19 deletions

View File

@ -2278,6 +2278,7 @@ void lua_engine::initialize()
* ui:get_line_height() - current ui font height
* ui:get_string_width(str, scale) - get str width with ui font at scale factor of current font size
* ui:get_char_width(char) - get width of utf8 glyph char with ui font
* ui:set_aggressive_input_focus(bool)
*
* ui.single_step
* ui.show_fps - fps display enabled
@ -2293,7 +2294,8 @@ void lua_engine::initialize()
"get_line_height", &mame_ui_manager::get_line_height,
"get_string_width", &mame_ui_manager::get_string_width,
// sol converts char32_t to a string
"get_char_width", [](mame_ui_manager &m, uint32_t utf8char) { return m.get_char_width(utf8char); });
"get_char_width", [](mame_ui_manager &m, uint32_t utf8char) { return m.get_char_width(utf8char); },
"set_aggressive_input_focus", [](mame_ui_manager &m, bool aggressive_focus) { osd_set_aggressive_input_focus(aggressive_focus); });
/* device_state_entry library

View File

@ -300,7 +300,7 @@ public:
int keynum;
// allocate and link in a new device
devinfo = m_dinput_helper->create_device<dinput_keyboard_device>(machine, *this, instance, &c_dfDIKeyboard, nullptr, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
devinfo = m_dinput_helper->create_device<dinput_keyboard_device>(machine, *this, instance, &c_dfDIKeyboard, nullptr, dinput_cooperative_level::FOREGROUND);
if (devinfo == nullptr)
goto exit;
@ -372,7 +372,7 @@ public:
HRESULT result;
// allocate and link in a new device
devinfo = m_dinput_helper->create_device<dinput_mouse_device>(machine, *this, instance, &c_dfDIMouse2, &c_dfDIMouse, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
devinfo = m_dinput_helper->create_device<dinput_mouse_device>(machine, *this, instance, &c_dfDIMouse2, &c_dfDIMouse, dinput_cooperative_level::FOREGROUND);
if (devinfo == nullptr)
goto exit;
@ -572,13 +572,13 @@ public:
BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
{
DWORD cooperative_level = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE;
dinput_cooperative_level cooperative_level = dinput_cooperative_level::FOREGROUND;
running_machine &machine = *static_cast<running_machine *>(ref);
dinput_joystick_device *devinfo;
int result = 0;
if (!osd_common_t::s_window_list.empty() && osd_common_t::s_window_list.front()->win_has_menu())
cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
cooperative_level = dinput_cooperative_level::BACKGROUND;
// allocate and link in a new device
devinfo = m_dinput_helper->create_device<dinput_joystick_device>(machine, *this, instance, &c_dfDIJoystick, nullptr, cooperative_level);

View File

@ -50,6 +50,12 @@ typedef HRESULT (WINAPI *dinput_create_fn)(HINSTANCE, DWORD, LPDIRECTINPUT8 *, L
typedef HRESULT (WINAPI *dinput_create_fn)(HINSTANCE, DWORD, LPDIRECTINPUT *, LPUNKNOWN);
#endif
enum class dinput_cooperative_level
{
FOREGROUND,
BACKGROUND
};
class dinput_api_helper
{
private:
@ -74,9 +80,11 @@ public:
LPCDIDEVICEINSTANCE instance,
LPCDIDATAFORMAT format1,
LPCDIDATAFORMAT format2,
DWORD cooperative_level)
dinput_cooperative_level cooperative_level)
{
HRESULT result;
std::shared_ptr<win_window_info> window;
HWND hwnd;
// convert instance name to utf8
std::string utf8_instance_name = osd::text::from_tstring(instance->tszInstanceName);
@ -120,8 +128,33 @@ public:
goto error;
}
// default window to the first window in the list
window = std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front());
DWORD di_cooperative_level;
if (window->attached_mode())
{
// in attached mode we have to ignore the caller and hook up to the desktop window
hwnd = GetDesktopWindow();
di_cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
}
else
{
hwnd = window->platform_window();
switch (cooperative_level)
{
case dinput_cooperative_level::BACKGROUND:
di_cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
break;
case dinput_cooperative_level::FOREGROUND:
di_cooperative_level = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE;
break;
default:
throw false;
}
}
// set the cooperative level
result = devinfo->dinput.device->SetCooperativeLevel(std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window(), cooperative_level);
result = devinfo->dinput.device->SetCooperativeLevel(hwnd, di_cooperative_level);
if (result != DI_OK)
goto error;

View File

@ -186,7 +186,7 @@ public:
BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
{
DWORD cooperative_level = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE;
dinput_cooperative_level cooperative_level = dinput_cooperative_level::FOREGROUND;
running_machine &machine = *static_cast<running_machine *>(ref);
dinput_joystick_device *devinfo;
int result = 0;
@ -200,7 +200,7 @@ public:
}
if (!osd_common_t::s_window_list.empty() && osd_common_t::s_window_list.front()->win_has_menu())
cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
cooperative_level = dinput_cooperative_level::BACKGROUND;
// allocate and link in a new device
devinfo = m_dinput_helper->create_device<dinput_joystick_device>(machine, *this, instance, &c_dfDIJoystick, nullptr, cooperative_level);

View File

@ -1053,4 +1053,7 @@ std::vector<std::string> osd_get_command_line(int argc, char *argv[]);
#define printf !MUST_USE_osd_printf_*_CALLS_WITHIN_THE_CORE!
*/
// specifies "aggressive focus" - should MAME capture input for any windows co-habiting a MAME window?
void osd_set_aggressive_input_focus(bool aggressive_focus);
#endif // MAME_OSD_OSDCORE_H

View File

@ -1158,3 +1158,13 @@ sdl_window_info::~sdl_window_info()
{
global_free(m_original_mode);
}
//============================================================
// osd_set_aggressive_input_focus
//============================================================
void osd_set_aggressive_input_focus(bool aggressive_focus)
{
// dummy implementation for now
}

View File

@ -32,6 +32,7 @@
#include "winutf8.h"
#include "winutil.h"
#include "strconv.h"
#include "modules/monitor/monitor_common.h"
@ -110,6 +111,8 @@ static DWORD last_update_time;
static HANDLE ui_pause_event;
static bool s_aggressive_focus;
//============================================================
@ -315,7 +318,8 @@ win_window_info::win_window_info(
m_lastclicktime(std::chrono::system_clock::time_point::min()),
m_lastclickx(0),
m_lastclicky(0),
m_machine(machine)
m_machine(machine),
m_attached_mode(false)
{
memset(m_title,0,sizeof(m_title));
m_non_fullscreen_bounds.left = 0;
@ -660,17 +664,40 @@ void winwindow_toggle_full_screen(void)
bool winwindow_has_focus(void)
{
HWND focuswnd = GetFocus();
// see if one of the video windows has focus
for (auto window : osd_common_t::s_window_list)
if (focuswnd == std::static_pointer_cast<win_window_info>(window)->platform_window())
{
switch (std::static_pointer_cast<win_window_info>(window)->focus())
{
case win_window_focus::NONE:
break;
case win_window_focus::THREAD:
if (s_aggressive_focus)
return true;
break;
case win_window_focus::WINDOW:
return true;
default:
throw false;
}
}
return false;
}
//============================================================
// osd_set_aggressive_input_focus
//============================================================
void osd_set_aggressive_input_focus(bool aggressive_focus)
{
s_aggressive_focus = aggressive_focus;
}
//============================================================
// winwindow_update_cursor_state
// (main thread)
@ -885,7 +912,19 @@ void win_window_info::update()
// post a redraw request with the primitive list as a parameter
last_update_time = timeGetTime();
SendMessage(platform_window(), WM_USER_REDRAW, 0, (LPARAM)primlist);
if (attached_mode())
{
HDC hdc = GetDC(platform_window());
m_primlist = primlist;
draw_video_contents(hdc, FALSE);
ReleaseDC(platform_window(), hdc);
}
else
{
SendMessage(platform_window(), WM_USER_REDRAW, 0, (LPARAM)primlist);
}
}
}
}
@ -1058,8 +1097,21 @@ int win_window_info::complete_create()
return 1;
}
// create the window, but don't show it yet
HWND hwnd = win_create_window_ex_utf8(
// are we in worker UI mode?
HWND hwnd;
const char *attach_window_name = downcast<windows_options &>(machine().options()).attach_window();
m_attached_mode = attach_window_name && *attach_window_name ? true : false;
if (m_attached_mode)
{
// we are in worker UI mode; either this value is an HWND or a window name
hwnd = (HWND)atoll(attach_window_name);
if (!hwnd)
hwnd = FindWindowEx(nullptr, nullptr, nullptr, osd::text::to_tstring(attach_window_name).c_str());
}
else
{
// 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,
@ -1070,6 +1122,7 @@ int win_window_info::complete_create()
menu,
GetModuleHandleUni(),
nullptr);
}
if (hwnd == nullptr)
return 1;
@ -1077,10 +1130,11 @@ int win_window_info::complete_create()
set_platform_window(hwnd);
// set a pointer back to us
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);
if (!attached_mode())
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);
// skip the positioning stuff for -video none */
if (video_config.mode == VIDEO_MODE_NONE)
// skip the positioning stuff for '-video none' or '-attach_window'
if (video_config.mode == VIDEO_MODE_NONE || attached_mode())
{
set_renderer(osd_renderer::make_for_type(video_config.mode, shared_from_this()));
renderer().create();
@ -1835,6 +1889,47 @@ void win_window_info::set_fullscreen(int fullscreen)
adjust_window_position_after_major_change();
}
//============================================================
// focus
// (main or window thread)
//============================================================
win_window_focus win_window_info::focus() const
{
HWND focuswnd = nullptr;
if (attached_mode())
{
// if this window is in attached mode, we need to see if it has
// focus in its context; first find out what thread owns it
DWORD window_thread_id = GetWindowThreadProcessId(platform_window(), nullptr);
// and then identify which window has focus in that thread's context
GUITHREADINFO gti;
gti.cbSize = sizeof(gti);
focuswnd = GetGUIThreadInfo(window_thread_id, &gti)
? gti.hwndFocus
: nullptr;
}
else
{
// life is simpler in non-attached mode
focuswnd = GetFocus();
}
if (focuswnd == platform_window())
return win_window_focus::WINDOW;
else if (focuswnd)
return win_window_focus::THREAD;
else
return win_window_focus::NONE;
}
//============================================================
// winwindow_qt_filter
//============================================================
#if (USE_QTDEBUG)
bool winwindow_qt_filter(void *message)
{

View File

@ -42,6 +42,14 @@
// TYPE DEFINITIONS
//============================================================
enum class win_window_focus
{
NONE, // neither this window nor this thread have focus
THREAD, // a window in this thread has focus
WINDOW // this window has focus directly
};
class win_window_info : public osd_window_t<HWND>
{
public:
@ -51,6 +59,8 @@ public:
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;
@ -144,6 +154,7 @@ private:
#endif
running_machine & m_machine;
bool m_attached_mode;
};
struct osd_draw_callbacks

View File

@ -165,6 +165,7 @@ const options_entry windows_options::s_option_entries[] =
// 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" },

View File

@ -24,6 +24,7 @@
// video options
#define WINOPTION_MENU "menu"
#define WINOPTION_ATTACH_WINDOW "attach_window"
// core post-processing options
#define WINOPTION_HLSLPATH "hlslpath"
@ -135,6 +136,7 @@ public:
// video options
bool menu() const { return bool_value(WINOPTION_MENU); }
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); }