mirror of
https://github.com/stenzek/duckstation.git
synced 2026-07-08 17:46:19 +00:00
InputManager: Move device notification from main window
Can use the new CM_Register_Notification() function since we don't have to care about Windows 7. Hopefully should stop a very rare race between window destruction and device unplugging. Also gets the Windows-specific stuff out of MainWindow which is nice.
This commit is contained in:
@@ -58,12 +58,6 @@
|
||||
|
||||
#include "moc_mainwindow.cpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "common/windows_headers.h"
|
||||
#include <Dbt.h>
|
||||
#include <VersionHelpers.h>
|
||||
#endif
|
||||
|
||||
LOG_CHANNEL(Host);
|
||||
|
||||
static constexpr std::array<std::pair<Qt::ToolBarArea, const char*>, 4> s_toolbar_areas = {{
|
||||
@@ -191,10 +185,6 @@ MainWindow::~MainWindow()
|
||||
// we compare here, since recreate destroys the window later
|
||||
if (g_main_window == this)
|
||||
g_main_window = nullptr;
|
||||
|
||||
#ifdef _WIN32
|
||||
unregisterForDeviceNotifications();
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::initialize()
|
||||
@@ -210,10 +200,6 @@ void MainWindow::initialize()
|
||||
connectSignals();
|
||||
|
||||
switchToGameListView();
|
||||
|
||||
#ifdef _WIN32
|
||||
registerForDeviceNotifications();
|
||||
#endif
|
||||
}
|
||||
|
||||
QMenu* MainWindow::createPopupMenu()
|
||||
@@ -231,49 +217,6 @@ void MainWindow::onStatusMessage(const QString& message)
|
||||
m_ui.statusBar->showMessage(message);
|
||||
}
|
||||
|
||||
void MainWindow::registerForDeviceNotifications()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// We use these notifications to detect when a controller is connected or disconnected.
|
||||
DEV_BROADCAST_DEVICEINTERFACE_W filter = {
|
||||
sizeof(DEV_BROADCAST_DEVICEINTERFACE_W), DBT_DEVTYP_DEVICEINTERFACE, 0u, {}, {}};
|
||||
m_device_notification_handle = RegisterDeviceNotificationW(
|
||||
(HANDLE)winId(), &filter, DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::unregisterForDeviceNotifications()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!m_device_notification_handle)
|
||||
return;
|
||||
|
||||
UnregisterDeviceNotification(static_cast<HDEVNOTIFY>(m_device_notification_handle));
|
||||
m_device_notification_handle = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
bool MainWindow::nativeEvent(const QByteArray& eventType, void* message, qintptr* result)
|
||||
{
|
||||
static constexpr const char win_type[] = "windows_generic_MSG";
|
||||
if (eventType == QByteArray(win_type, sizeof(win_type) - 1))
|
||||
{
|
||||
const MSG* msg = static_cast<const MSG*>(message);
|
||||
if (msg->message == WM_DEVICECHANGE && msg->wParam == DBT_DEVNODES_CHANGED)
|
||||
{
|
||||
g_emu_thread->reloadInputDevices();
|
||||
*result = 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return QMainWindow::nativeEvent(eventType, message, result);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
std::optional<WindowInfo> MainWindow::acquireRenderWindow(RenderAPI render_api, bool fullscreen,
|
||||
bool exclusive_fullscreen, Error* error)
|
||||
{
|
||||
|
||||
@@ -153,10 +153,6 @@ protected:
|
||||
void moveEvent(QMoveEvent* event) override;
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
|
||||
#ifdef _WIN32
|
||||
bool nativeEvent(const QByteArray& eventType, void* message, qintptr* result) override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
/// Initializes the window. Call once at startup.
|
||||
void initialize();
|
||||
@@ -205,8 +201,6 @@ private:
|
||||
void destroySubWindows();
|
||||
void showAutoUpdaterWindow();
|
||||
|
||||
void registerForDeviceNotifications();
|
||||
void unregisterForDeviceNotifications();
|
||||
void notifyRAIntegrationOfWindowChange();
|
||||
|
||||
/// Fills menu with save state info and handlers.
|
||||
@@ -359,10 +353,6 @@ private:
|
||||
bool m_was_disc_change_request = false;
|
||||
bool m_is_closing = false;
|
||||
|
||||
#ifdef _WIN32
|
||||
void* m_device_notification_handle = nullptr;
|
||||
#endif
|
||||
|
||||
#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION
|
||||
QMenu* m_raintegration_menu = nullptr;
|
||||
#endif
|
||||
|
||||
@@ -251,7 +251,7 @@ if(WIN32)
|
||||
xinput_source.h
|
||||
)
|
||||
target_link_libraries(util PRIVATE d3d12ma)
|
||||
target_link_libraries(util PRIVATE winmm.lib Dwmapi.lib winhttp.lib)
|
||||
target_link_libraries(util PRIVATE Cfgmgr32.lib Dwmapi.lib winhttp.lib)
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES "Debug|Devel")
|
||||
target_link_libraries(util PRIVATE WinPixEventRuntime::WinPixEventRuntime)
|
||||
|
||||
@@ -34,6 +34,11 @@
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "common/windows_headers.h"
|
||||
#include <cfgmgr32.h>
|
||||
#endif
|
||||
|
||||
LOG_CHANNEL(InputManager);
|
||||
|
||||
namespace InputManager {
|
||||
@@ -162,6 +167,13 @@ static void UpdateInputSourceState(const SettingsInterface& si, std::unique_lock
|
||||
|
||||
static const KeyCodeData* FindKeyCodeData(u32 usb_code);
|
||||
|
||||
#ifdef _WIN32
|
||||
static DWORD WINAPI DeviceNotificationCallback(HCMNOTIFICATION hNotify, PVOID Context, CM_NOTIFY_ACTION Action,
|
||||
PCM_NOTIFY_EVENT_DATA EventData, DWORD EventDataSize);
|
||||
static void RegisterDeviceNotificationHandle();
|
||||
static void UnregisterDeviceNotificationHandle();
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Tracking host mouse movement and turning into relative events
|
||||
// 4 axes: pointer left/right, wheel vertical/horizontal. Last/Next/Normalized.
|
||||
@@ -210,6 +222,12 @@ struct ALIGN_TO_CACHE_LINE State
|
||||
// Input sources. Keyboard/mouse don't exist here.
|
||||
std::array<std::unique_ptr<InputSource>, static_cast<u32>(InputSourceType::Count)> input_sources;
|
||||
|
||||
#ifdef _WIN32
|
||||
// Device notification handle for Windows.
|
||||
HCMNOTIFICATION device_notification_handle = nullptr;
|
||||
std::atomic_flag device_notification_reload_pending = ATOMIC_FLAG_INIT;
|
||||
#endif
|
||||
|
||||
ALIGN_TO_CACHE_LINE
|
||||
std::array<std::array<float, static_cast<u8>(InputPointerAxis::Count)>, InputManager::MAX_POINTER_DEVICES>
|
||||
host_pointer_positions;
|
||||
@@ -268,6 +286,8 @@ static constexpr const std::array s_legacy_key_names = {
|
||||
|
||||
} // namespace InputManager
|
||||
|
||||
ForceFeedbackDevice::~ForceFeedbackDevice() = default;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Binding Parsing
|
||||
// ------------------------------------------------------------------------
|
||||
@@ -2233,6 +2253,10 @@ void InputManager::CloseSources()
|
||||
s_state.input_sources[i].reset();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
UnregisterDeviceNotificationHandle();
|
||||
#endif
|
||||
}
|
||||
|
||||
void InputManager::PollSources()
|
||||
@@ -2428,6 +2452,19 @@ void InputManager::ReloadSourcesAndBindings(const SettingsInterface& si, const S
|
||||
UpdateInputSourceState(si, settings_lock, InputSourceType::DInput, &InputSource::CreateDInputSource);
|
||||
UpdateInputSourceState(si, settings_lock, InputSourceType::XInput, &InputSource::CreateXInputSource);
|
||||
UpdateInputSourceState(si, settings_lock, InputSourceType::RawInput, &InputSource::CreateWin32RawInputSource);
|
||||
|
||||
// Request device notifications when using raw input or dinput, as we need to manually handle device changes
|
||||
if (s_state.input_sources[static_cast<u32>(InputSourceType::RawInput)] ||
|
||||
s_state.input_sources[static_cast<u32>(InputSourceType::DInput)])
|
||||
{
|
||||
if (!s_state.device_notification_handle)
|
||||
RegisterDeviceNotificationHandle();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s_state.device_notification_handle)
|
||||
UnregisterDeviceNotificationHandle();
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_SDL
|
||||
UpdateInputSourceState(si, settings_lock, InputSourceType::SDL, &InputSource::CreateSDLSource);
|
||||
@@ -2442,6 +2479,52 @@ void InputManager::ReloadSourcesAndBindings(const SettingsInterface& si, const S
|
||||
UpdateRelativeMouseMode();
|
||||
}
|
||||
|
||||
ForceFeedbackDevice::~ForceFeedbackDevice()
|
||||
#ifdef _WIN32
|
||||
|
||||
DWORD InputManager::DeviceNotificationCallback(HCMNOTIFICATION hNotify, PVOID Context, CM_NOTIFY_ACTION Action,
|
||||
PCM_NOTIFY_EVENT_DATA EventData, DWORD EventDataSize)
|
||||
{
|
||||
if (Action != CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL && Action != CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
// This comes through on a thread pool worker, so we need to queue the reload on the core thread.
|
||||
// We tend to get a few of these in quick succession, so try to batch the reloads together.
|
||||
if (!s_state.device_notification_reload_pending.test_and_set(std::memory_order_acq_rel))
|
||||
{
|
||||
Host::RunOnCPUThread([]() {
|
||||
DEV_LOG("Reloading input devices due to device notification.");
|
||||
s_state.device_notification_reload_pending.clear(std::memory_order_release);
|
||||
ReloadDevices();
|
||||
});
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
void InputManager::RegisterDeviceNotificationHandle()
|
||||
{
|
||||
DebugAssert(!s_state.device_notification_handle);
|
||||
s_state.device_notification_reload_pending.clear(std::memory_order_release);
|
||||
|
||||
// We use these notifications to detect when a controller is connected or disconnected.
|
||||
CM_NOTIFY_FILTER filter = {};
|
||||
filter.cbSize = sizeof(CM_NOTIFY_FILTER);
|
||||
filter.FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE;
|
||||
filter.Flags = CM_NOTIFY_FILTER_FLAG_ALL_INTERFACE_CLASSES;
|
||||
|
||||
const CONFIGRET cr = CM_Register_Notification(&filter, nullptr, &InputManager::DeviceNotificationCallback,
|
||||
&s_state.device_notification_handle);
|
||||
if (cr != CR_SUCCESS)
|
||||
ERROR_LOG("CM_Register_Notification() failed: {}", cr);
|
||||
}
|
||||
|
||||
void InputManager::UnregisterDeviceNotificationHandle()
|
||||
{
|
||||
if (!s_state.device_notification_handle)
|
||||
return;
|
||||
|
||||
CM_Unregister_Notification(s_state.device_notification_handle);
|
||||
s_state.device_notification_handle = nullptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);Dwmapi.lib;winhttp.lib</AdditionalDependencies>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);Cfgmgr32.lib;Dwmapi.lib;winhttp.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user