osd/modules/input: Always use DirectInput with desktop window in background mode.

There are multiple issues with what MAME was doing, but the most glaring
is that it violates the DirectInput interface contract that requires the
window associated with an open device must not be destroyed.  See
documentation for IDirectInputDevice8::SetCooperativeLevel: "This
parameter must be a valid top-level window handle that belongs to the
process. The window associated with the device must not be destroyed
while it is still active in a DirectInput device."

The previous code also prevented DirectInput controllers from working
when using multiple windows if any window other than the first window
had focus.

Also fixed SDL builds not correctly recognising when all windows lose
focus, and save state menu not appearing.
This commit is contained in:
Vas Crabb 2023-02-28 05:16:13 +11:00
parent 410a3dbeae
commit 42e759ade4
3 changed files with 17 additions and 18 deletions

View File

@ -53,18 +53,6 @@
#include <type_traits>
/***************************************************************************
CONSTANTS
***************************************************************************/
enum
{
LOADSAVE_NONE,
LOADSAVE_LOAD,
LOADSAVE_SAVE
};
/***************************************************************************
LOCAL VARIABLES
***************************************************************************/
@ -1376,15 +1364,17 @@ uint32_t mame_ui_manager::handler_ingame(render_container &container)
// handle a save state request
if (machine().ui_input().pressed(IPT_UI_SAVE_STATE))
{
osd_printf_info("Save requested\n");
start_save_state();
return LOADSAVE_SAVE;
return 0;
}
// handle a load state request
if (machine().ui_input().pressed(IPT_UI_LOAD_STATE))
{
osd_printf_info("Load requested\n");
start_load_state();
return LOADSAVE_LOAD;
return 0;
}
// handle a save snapshot request

View File

@ -1221,7 +1221,7 @@ std::pair<Microsoft::WRL::ComPtr<IDirectInputDevice8>, LPCDIDATAFORMAT> dinput_a
// attempt to create a device
Microsoft::WRL::ComPtr<IDirectInputDevice8> device;
result = m_dinput->CreateDevice(instance->guidInstance, device.GetAddressOf(), nullptr);
result = m_dinput->CreateDevice(instance->guidInstance, &device, nullptr);
if (result != DI_OK)
{
osd_printf_error("DirectInput: Unable to create device.\n");
@ -1245,7 +1245,13 @@ std::pair<Microsoft::WRL::ComPtr<IDirectInputDevice8>, LPCDIDATAFORMAT> dinput_a
}
// default window to the first window in the list
HWND window_handle;
// For now, we always use the desktop window due to multiple issues:
// * MAME recreates windows on toggling fullscreen. DirectInput really doesn't like this.
// * DirectInput doesn't like the window used for D3D fullscreen exclusive mode.
// * With multiple windows, the first window needs to have focus when using foreground mode.
// This makes it impossible to use force feedback as that requires foreground exclusive mode.
// The only way to get around this would be to reopen devices on focus changes.
[[maybe_unused]] HWND window_handle;
DWORD di_cooperative_level;
#if defined(OSD_WINDOWS)
auto const &window = dynamic_cast<win_window_info &>(*osd_common_t::window_list().front());
@ -1278,7 +1284,8 @@ std::pair<Microsoft::WRL::ComPtr<IDirectInputDevice8>, LPCDIDATAFORMAT> dinput_a
di_cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
break;
case dinput_cooperative_level::FOREGROUND:
di_cooperative_level = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE;
//di_cooperative_level = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE;
di_cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
break;
default:
throw false;
@ -1286,7 +1293,7 @@ std::pair<Microsoft::WRL::ComPtr<IDirectInputDevice8>, LPCDIDATAFORMAT> dinput_a
}
// set the cooperative level
result = device->SetCooperativeLevel(window_handle, di_cooperative_level);
result = device->SetCooperativeLevel(GetDesktopWindow(), di_cooperative_level);
if (result != DI_OK)
{
osd_printf_error("DirectInput: Unable to set cooperative level.\n");

View File

@ -654,6 +654,8 @@ void sdl_osd_interface::process_window_event(SDL_Event const &event)
break;
case SDL_WINDOWEVENT_FOCUS_LOST:
if (window == m_focus_window)
m_focus_window = nullptr;
machine().ui_input().push_window_defocus_event(window->target());
break;