mirror of https://github.com/PCSX2/pcsx2.git
Qt: Register for device notifications on Windows
That way we know when a controller is connected/disconnected, and don't have to poll unconnected XInput controllers.
This commit is contained in:
parent
b9dffcb069
commit
e8877daca3
|
@ -54,6 +54,11 @@
|
||||||
#include "svnrev.h"
|
#include "svnrev.h"
|
||||||
#include "Tools/InputRecording/NewInputRecordingDlg.h"
|
#include "Tools/InputRecording/NewInputRecordingDlg.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include "common/RedtapeWindows.h"
|
||||||
|
#include <Dbt.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_RAINTEGRATION
|
#ifdef ENABLE_RAINTEGRATION
|
||||||
#include "pcsx2/Frontend/Achievements.h"
|
#include "pcsx2/Frontend/Achievements.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -120,6 +125,9 @@ MainWindow::~MainWindow()
|
||||||
// we compare here, since recreate destroys the window later
|
// we compare here, since recreate destroys the window later
|
||||||
if (g_main_window == this)
|
if (g_main_window == this)
|
||||||
g_main_window = nullptr;
|
g_main_window = nullptr;
|
||||||
|
#ifdef _WIN32
|
||||||
|
unregisterForDeviceNotifications();
|
||||||
|
#endif
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
CocoaTools::RemoveThemeChangeHandler(this);
|
CocoaTools::RemoveThemeChangeHandler(this);
|
||||||
#endif
|
#endif
|
||||||
|
@ -145,6 +153,10 @@ void MainWindow::initialize()
|
||||||
switchToGameListView();
|
switchToGameListView();
|
||||||
updateWindowTitle();
|
updateWindowTitle();
|
||||||
updateSaveStateMenus(QString(), QString(), 0);
|
updateSaveStateMenus(QString(), QString(), 0);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
registerForDeviceNotifications();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Figure out how to set this in the .ui file
|
// TODO: Figure out how to set this in the .ui file
|
||||||
|
@ -421,6 +433,9 @@ void MainWindow::recreate()
|
||||||
if (s_vm_valid)
|
if (s_vm_valid)
|
||||||
requestShutdown(false, true, EmuConfig.SaveStateOnShutdown);
|
requestShutdown(false, true, EmuConfig.SaveStateOnShutdown);
|
||||||
|
|
||||||
|
// We need to close input sources, because e.g. DInput uses our window handle.
|
||||||
|
g_emu_thread->closeInputSources();
|
||||||
|
|
||||||
close();
|
close();
|
||||||
g_main_window = nullptr;
|
g_main_window = nullptr;
|
||||||
|
|
||||||
|
@ -429,6 +444,9 @@ void MainWindow::recreate()
|
||||||
new_main_window->refreshGameList(false);
|
new_main_window->refreshGameList(false);
|
||||||
new_main_window->show();
|
new_main_window->show();
|
||||||
deleteLater();
|
deleteLater();
|
||||||
|
|
||||||
|
// Reload the sources we just closed.
|
||||||
|
g_emu_thread->reloadInputSources();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::recreateSettings()
|
void MainWindow::recreateSettings()
|
||||||
|
@ -1808,6 +1826,48 @@ void MainWindow::dropEvent(QDropEvent* event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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};
|
||||||
|
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
|
||||||
|
|
||||||
DisplayWidget* MainWindow::createDisplay(bool fullscreen, bool render_to_main)
|
DisplayWidget* MainWindow::createDisplay(bool fullscreen, bool render_to_main)
|
||||||
{
|
{
|
||||||
DevCon.WriteLn("createDisplay(%u, %u)", static_cast<u32>(fullscreen), static_cast<u32>(render_to_main));
|
DevCon.WriteLn("createDisplay(%u, %u)", static_cast<u32>(fullscreen), static_cast<u32>(render_to_main));
|
||||||
|
|
|
@ -177,6 +177,10 @@ protected:
|
||||||
void dragEnterEvent(QDragEnterEvent* event) override;
|
void dragEnterEvent(QDragEnterEvent* event) override;
|
||||||
void dropEvent(QDropEvent* event) override;
|
void dropEvent(QDropEvent* event) override;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
bool nativeEvent(const QByteArray& eventType, void* message, qintptr* result) override;
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void setStyleFromSettings();
|
static void setStyleFromSettings();
|
||||||
static void setIconThemeFromStyle();
|
static void setIconThemeFromStyle();
|
||||||
|
@ -186,6 +190,9 @@ private:
|
||||||
void recreate();
|
void recreate();
|
||||||
void recreateSettings();
|
void recreateSettings();
|
||||||
|
|
||||||
|
void registerForDeviceNotifications();
|
||||||
|
void unregisterForDeviceNotifications();
|
||||||
|
|
||||||
void saveStateToConfig();
|
void saveStateToConfig();
|
||||||
void restoreStateFromConfig();
|
void restoreStateFromConfig();
|
||||||
|
|
||||||
|
@ -265,6 +272,10 @@ private:
|
||||||
bool m_is_closing = false;
|
bool m_is_closing = false;
|
||||||
|
|
||||||
QString m_last_fps_status;
|
QString m_last_fps_status;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
void* m_device_notification_handle = nullptr;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
extern MainWindow* g_main_window;
|
extern MainWindow* g_main_window;
|
||||||
|
|
|
@ -701,6 +701,28 @@ void EmuThread::reloadInputBindings()
|
||||||
InputManager::ReloadBindings(*si, *bindings_si);
|
InputManager::ReloadBindings(*si, *bindings_si);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmuThread::reloadInputDevices()
|
||||||
|
{
|
||||||
|
if (!isOnEmuThread())
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(this, &EmuThread::reloadInputDevices, Qt::QueuedConnection);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputManager::ReloadDevices();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmuThread::closeInputSources()
|
||||||
|
{
|
||||||
|
if (!isOnEmuThread())
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(this, &EmuThread::reloadInputDevices, Qt::BlockingQueuedConnection);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputManager::CloseSources();
|
||||||
|
}
|
||||||
|
|
||||||
void EmuThread::requestDisplaySize(float scale)
|
void EmuThread::requestDisplaySize(float scale)
|
||||||
{
|
{
|
||||||
if (!isOnEmuThread())
|
if (!isOnEmuThread())
|
||||||
|
|
|
@ -105,6 +105,8 @@ public Q_SLOTS:
|
||||||
void reloadPatches();
|
void reloadPatches();
|
||||||
void reloadInputSources();
|
void reloadInputSources();
|
||||||
void reloadInputBindings();
|
void reloadInputBindings();
|
||||||
|
void reloadInputDevices();
|
||||||
|
void closeInputSources();
|
||||||
void requestDisplaySize(float scale);
|
void requestDisplaySize(float scale);
|
||||||
void enumerateInputDevices();
|
void enumerateInputDevices();
|
||||||
void enumerateVibrationMotors();
|
void enumerateVibrationMotors();
|
||||||
|
|
|
@ -35,7 +35,7 @@ DInputSource::DInputSource() = default;
|
||||||
DInputSource::~DInputSource()
|
DInputSource::~DInputSource()
|
||||||
{
|
{
|
||||||
m_controllers.clear();
|
m_controllers.clear();
|
||||||
m_dinput.Reset();
|
m_dinput.reset();
|
||||||
if (m_dinput_module)
|
if (m_dinput_module)
|
||||||
FreeLibrary(m_dinput_module);
|
FreeLibrary(m_dinput_module);
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ bool DInputSource::Initialize(SettingsInterface& si, std::unique_lock<std::mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT hr = create(
|
HRESULT hr = create(
|
||||||
GetModuleHandleA(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8W, reinterpret_cast<LPVOID*>(m_dinput.GetAddressOf()), nullptr);
|
GetModuleHandleA(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8W, reinterpret_cast<LPVOID*>(m_dinput.put()), nullptr);
|
||||||
m_joystick_data_format = get_joystick_data_format();
|
m_joystick_data_format = get_joystick_data_format();
|
||||||
if (FAILED(hr) || !m_joystick_data_format)
|
if (FAILED(hr) || !m_joystick_data_format)
|
||||||
{
|
{
|
||||||
|
@ -96,12 +96,15 @@ bool DInputSource::Initialize(SettingsInterface& si, std::unique_lock<std::mutex
|
||||||
// need to release the lock while we're enumerating, because we call winId().
|
// need to release the lock while we're enumerating, because we call winId().
|
||||||
settings_lock.unlock();
|
settings_lock.unlock();
|
||||||
const std::optional<WindowInfo> toplevel_wi(Host::GetTopLevelWindowInfo());
|
const std::optional<WindowInfo> toplevel_wi(Host::GetTopLevelWindowInfo());
|
||||||
if (toplevel_wi.has_value() && toplevel_wi->type == WindowInfo::Type::Win32)
|
if (!toplevel_wi.has_value() || toplevel_wi->type != WindowInfo::Type::Win32)
|
||||||
AddDevices(static_cast<HWND>(toplevel_wi->window_handle));
|
{
|
||||||
else
|
|
||||||
Console.Error("Missing top level window, cannot add DInput devices.");
|
Console.Error("Missing top level window, cannot add DInput devices.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
settings_lock.lock();
|
settings_lock.lock();
|
||||||
|
|
||||||
|
m_toplevel_window = static_cast<HWND>(toplevel_wi->window_handle);
|
||||||
|
ReloadDevices();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +113,56 @@ void DInputSource::UpdateSettings(SettingsInterface& si, std::unique_lock<std::m
|
||||||
// noop
|
// noop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BOOL CALLBACK EnumCallback(LPCDIDEVICEINSTANCEW lpddi, LPVOID pvRef)
|
||||||
|
{
|
||||||
|
static_cast<std::vector<DIDEVICEINSTANCEW>*>(pvRef)->push_back(*lpddi);
|
||||||
|
return DIENUM_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DInputSource::ReloadDevices()
|
||||||
|
{
|
||||||
|
// detect any removals
|
||||||
|
PollEvents();
|
||||||
|
|
||||||
|
// look for new devices
|
||||||
|
std::vector<DIDEVICEINSTANCEW> devices;
|
||||||
|
m_dinput->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumCallback, &devices, DIEDFL_ATTACHEDONLY);
|
||||||
|
|
||||||
|
DevCon.WriteLn("Enumerated %zu devices", devices.size());
|
||||||
|
|
||||||
|
bool changed = false;
|
||||||
|
for (DIDEVICEINSTANCEW inst : devices)
|
||||||
|
{
|
||||||
|
// do we already have this one?
|
||||||
|
if (std::any_of(
|
||||||
|
m_controllers.begin(), m_controllers.end(), [&inst](const ControllerData& cd) { return inst.guidInstance == cd.guid; }))
|
||||||
|
{
|
||||||
|
// yup, so skip it
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ControllerData cd;
|
||||||
|
cd.guid = inst.guidInstance;
|
||||||
|
HRESULT hr = m_dinput->CreateDevice(inst.guidInstance, cd.device.put(), nullptr);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
Console.Warning("Failed to create instance of device [%s, %s]", inst.tszProductName, inst.tszInstanceName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string name(StringUtil::WideStringToUTF8String(inst.tszProductName));
|
||||||
|
if (AddDevice(cd, name))
|
||||||
|
{
|
||||||
|
const u32 index = static_cast<u32>(m_controllers.size());
|
||||||
|
m_controllers.push_back(std::move(cd));
|
||||||
|
Host::OnInputDeviceConnected(GetDeviceIdentifier(index), name);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
void DInputSource::Shutdown()
|
void DInputSource::Shutdown()
|
||||||
{
|
{
|
||||||
while (!m_controllers.empty())
|
while (!m_controllers.empty())
|
||||||
|
@ -119,45 +172,12 @@ void DInputSource::Shutdown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL CALLBACK EnumCallback(LPCDIDEVICEINSTANCEW lpddi, LPVOID pvRef)
|
bool DInputSource::AddDevice(ControllerData& cd, const std::string& name)
|
||||||
{
|
{
|
||||||
static_cast<std::vector<DIDEVICEINSTANCEW>*>(pvRef)->push_back(*lpddi);
|
HRESULT hr = cd.device->SetCooperativeLevel(m_toplevel_window, DISCL_BACKGROUND | DISCL_EXCLUSIVE);
|
||||||
return DIENUM_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DInputSource::AddDevices(HWND toplevel_window)
|
|
||||||
{
|
|
||||||
std::vector<DIDEVICEINSTANCEW> devices;
|
|
||||||
m_dinput->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumCallback, &devices, DIEDFL_ATTACHEDONLY);
|
|
||||||
|
|
||||||
DevCon.WriteLn("Enumerated %zu devices", devices.size());
|
|
||||||
|
|
||||||
for (DIDEVICEINSTANCEW inst : devices)
|
|
||||||
{
|
|
||||||
ControllerData cd;
|
|
||||||
HRESULT hr = m_dinput->CreateDevice(inst.guidInstance, cd.device.GetAddressOf(), nullptr);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
Console.Warning("Failed to create instance of device [%s, %s]", inst.tszProductName, inst.tszInstanceName);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string name(StringUtil::WideStringToUTF8String(inst.tszProductName));
|
|
||||||
if (AddDevice(cd, toplevel_window, name))
|
|
||||||
{
|
|
||||||
const u32 index = static_cast<u32>(m_controllers.size());
|
|
||||||
m_controllers.push_back(std::move(cd));
|
|
||||||
Host::OnInputDeviceConnected(GetDeviceIdentifier(index), name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DInputSource::AddDevice(ControllerData& cd, HWND toplevel_window, const std::string& name)
|
|
||||||
{
|
|
||||||
HRESULT hr = cd.device->SetCooperativeLevel(toplevel_window, DISCL_BACKGROUND | DISCL_EXCLUSIVE);
|
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
hr = cd.device->SetCooperativeLevel(toplevel_window, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE);
|
hr = cd.device->SetCooperativeLevel(m_toplevel_window, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
Console.Error("Failed to set cooperative level for '%s'", name.c_str());
|
Console.Error("Failed to set cooperative level for '%s'", name.c_str());
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <wrl/client.h>
|
#include <wil/com.h>
|
||||||
|
|
||||||
class DInputSource final : public InputSource
|
class DInputSource final : public InputSource
|
||||||
{
|
{
|
||||||
|
@ -46,6 +46,7 @@ public:
|
||||||
|
|
||||||
bool Initialize(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
|
bool Initialize(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
|
||||||
void UpdateSettings(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
|
void UpdateSettings(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
|
||||||
|
bool ReloadDevices() override;
|
||||||
void Shutdown() override;
|
void Shutdown() override;
|
||||||
|
|
||||||
void PollEvents() override;
|
void PollEvents() override;
|
||||||
|
@ -59,13 +60,11 @@ public:
|
||||||
std::string ConvertKeyToString(InputBindingKey key) override;
|
std::string ConvertKeyToString(InputBindingKey key) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename T>
|
|
||||||
using ComPtr = Microsoft::WRL::ComPtr<T>;
|
|
||||||
|
|
||||||
struct ControllerData
|
struct ControllerData
|
||||||
{
|
{
|
||||||
ComPtr<IDirectInputDevice8W> device;
|
wil::com_ptr_nothrow<IDirectInputDevice8W> device;
|
||||||
DIJOYSTATE last_state = {};
|
DIJOYSTATE last_state = {};
|
||||||
|
GUID guid = {};
|
||||||
std::vector<u32> axis_offsets;
|
std::vector<u32> axis_offsets;
|
||||||
u32 num_buttons = 0;
|
u32 num_buttons = 0;
|
||||||
|
|
||||||
|
@ -80,14 +79,14 @@ private:
|
||||||
static std::array<bool, NUM_HAT_DIRECTIONS> GetHatButtons(DWORD hat);
|
static std::array<bool, NUM_HAT_DIRECTIONS> GetHatButtons(DWORD hat);
|
||||||
static std::string GetDeviceIdentifier(u32 index);
|
static std::string GetDeviceIdentifier(u32 index);
|
||||||
|
|
||||||
void AddDevices(HWND toplevel_window);
|
bool AddDevice(ControllerData& cd, const std::string& name);
|
||||||
bool AddDevice(ControllerData& cd, HWND toplevel_window, const std::string& name);
|
|
||||||
|
|
||||||
void CheckForStateChanges(size_t index, const DIJOYSTATE& new_state);
|
void CheckForStateChanges(size_t index, const DIJOYSTATE& new_state);
|
||||||
|
|
||||||
ControllerDataArray m_controllers;
|
ControllerDataArray m_controllers;
|
||||||
|
|
||||||
HMODULE m_dinput_module{};
|
HMODULE m_dinput_module{};
|
||||||
|
wil::com_ptr_nothrow<IDirectInput8W> m_dinput;
|
||||||
LPCDIDATAFORMAT m_joystick_data_format{};
|
LPCDIDATAFORMAT m_joystick_data_format{};
|
||||||
ComPtr<IDirectInput8W> m_dinput;
|
HWND m_toplevel_window = NULL;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1024,6 +1024,19 @@ void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& bind
|
||||||
// Source Management
|
// Source Management
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool InputManager::ReloadDevices()
|
||||||
|
{
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
|
||||||
|
{
|
||||||
|
if (s_input_sources[i])
|
||||||
|
changed |= s_input_sources[i]->ReloadDevices();
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
void InputManager::CloseSources()
|
void InputManager::CloseSources()
|
||||||
{
|
{
|
||||||
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
|
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
|
||||||
|
|
|
@ -256,6 +256,10 @@ namespace InputManager
|
||||||
/// Re-parses the sources part of the config and initializes any backends.
|
/// Re-parses the sources part of the config and initializes any backends.
|
||||||
void ReloadSources(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock);
|
void ReloadSources(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock);
|
||||||
|
|
||||||
|
/// Called when a device change is triggered by the system (DBT_DEVNODES_CHANGED on Windows).
|
||||||
|
/// Returns true if any device changes are detected.
|
||||||
|
bool ReloadDevices();
|
||||||
|
|
||||||
/// Shuts down any enabled input sources.
|
/// Shuts down any enabled input sources.
|
||||||
void CloseSources();
|
void CloseSources();
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ public:
|
||||||
|
|
||||||
virtual bool Initialize(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) = 0;
|
virtual bool Initialize(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) = 0;
|
||||||
virtual void UpdateSettings(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) = 0;
|
virtual void UpdateSettings(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) = 0;
|
||||||
|
virtual bool ReloadDevices() = 0;
|
||||||
virtual void Shutdown() = 0;
|
virtual void Shutdown() = 0;
|
||||||
|
|
||||||
virtual void PollEvents() = 0;
|
virtual void PollEvents() = 0;
|
||||||
|
|
|
@ -129,6 +129,13 @@ void SDLInputSource::UpdateSettings(SettingsInterface& si, std::unique_lock<std:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SDLInputSource::ReloadDevices()
|
||||||
|
{
|
||||||
|
// We'll get a GC added/removed event here.
|
||||||
|
PollEvents();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void SDLInputSource::Shutdown()
|
void SDLInputSource::Shutdown()
|
||||||
{
|
{
|
||||||
ShutdownSubsystem();
|
ShutdownSubsystem();
|
||||||
|
|
|
@ -31,6 +31,7 @@ public:
|
||||||
|
|
||||||
bool Initialize(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
|
bool Initialize(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
|
||||||
void UpdateSettings(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
|
void UpdateSettings(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
|
||||||
|
bool ReloadDevices() override;
|
||||||
void Shutdown() override;
|
void Shutdown() override;
|
||||||
|
|
||||||
void PollEvents() override;
|
void PollEvents() override;
|
||||||
|
|
|
@ -132,6 +132,7 @@ bool XInputSource::Initialize(SettingsInterface& si, std::unique_lock<std::mutex
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReloadDevices();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,6 +140,38 @@ void XInputSource::UpdateSettings(SettingsInterface& si, std::unique_lock<std::m
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool XInputSource::ReloadDevices()
|
||||||
|
{
|
||||||
|
bool changed = false;
|
||||||
|
for (u32 i = 0; i < NUM_CONTROLLERS; i++)
|
||||||
|
{
|
||||||
|
XINPUT_STATE new_state;
|
||||||
|
SCP_EXTN new_state_scp;
|
||||||
|
DWORD result = m_xinput_get_extended ? m_xinput_get_extended(i, &new_state_scp) : ERROR_NOT_SUPPORTED;
|
||||||
|
if (result != ERROR_SUCCESS)
|
||||||
|
result = m_xinput_get_state(i, &new_state);
|
||||||
|
|
||||||
|
if (result == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
if (m_controllers[i].connected)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
HandleControllerConnection(i);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
else if (result == ERROR_DEVICE_NOT_CONNECTED)
|
||||||
|
{
|
||||||
|
if (!m_controllers[i].connected)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
HandleControllerDisconnection(i);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
void XInputSource::Shutdown()
|
void XInputSource::Shutdown()
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < NUM_CONTROLLERS; i++)
|
for (u32 i = 0; i < NUM_CONTROLLERS; i++)
|
||||||
|
@ -164,6 +197,8 @@ void XInputSource::PollEvents()
|
||||||
for (u32 i = 0; i < NUM_CONTROLLERS; i++)
|
for (u32 i = 0; i < NUM_CONTROLLERS; i++)
|
||||||
{
|
{
|
||||||
const bool was_connected = m_controllers[i].connected;
|
const bool was_connected = m_controllers[i].connected;
|
||||||
|
if (!was_connected)
|
||||||
|
continue;
|
||||||
|
|
||||||
SCP_EXTN new_state_scp;
|
SCP_EXTN new_state_scp;
|
||||||
DWORD result = m_xinput_get_extended ? m_xinput_get_extended(i, &new_state_scp) : ERROR_NOT_SUPPORTED;
|
DWORD result = m_xinput_get_extended ? m_xinput_get_extended(i, &new_state_scp) : ERROR_NOT_SUPPORTED;
|
||||||
|
|
|
@ -65,6 +65,7 @@ public:
|
||||||
|
|
||||||
bool Initialize(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
|
bool Initialize(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
|
||||||
void UpdateSettings(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
|
void UpdateSettings(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
|
||||||
|
bool ReloadDevices() override;
|
||||||
void Shutdown() override;
|
void Shutdown() override;
|
||||||
|
|
||||||
void PollEvents() override;
|
void PollEvents() override;
|
||||||
|
|
Loading…
Reference in New Issue