summaryrefslogtreecommitdiff
path: root/Source/Core/InputCommon/ControllerInterface
diff options
context:
space:
mode:
authorMichael M <mchtly@gmail.com>2017-11-10 12:30:37 -0800
committerJordan Woyak <jordan.woyak@gmail.com>2019-03-29 08:01:40 -0500
commitd26c1ce24d9108114d7eab97cfc2ab4f3eea28ee (patch)
tree8bbc9de32bfea224eb11c33076996f56b4e9925a /Source/Core/InputCommon/ControllerInterface
parent92ca6e124e82f63b61982a5ecfb26ca818f2fe47 (diff)
Add hotplug support to DInput and XInput controller backends
Diffstat (limited to 'Source/Core/InputCommon/ControllerInterface')
-rw-r--r--Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp4
-rw-r--r--Source/Core/InputCommon/ControllerInterface/DInput/DInput.cpp2
-rw-r--r--Source/Core/InputCommon/ControllerInterface/Win32/Win32.cpp119
-rw-r--r--Source/Core/InputCommon/ControllerInterface/Win32/Win32.h6
-rw-r--r--Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp2
5 files changed, 123 insertions, 10 deletions
diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp
index 6eeb41e8b8..3a4f374c9d 100644
--- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp
@@ -46,7 +46,7 @@ void ControllerInterface::Initialize(const WindowSystemInfo& wsi)
m_is_populating_devices = true;
#ifdef CIFACE_USE_WIN32
- ciface::Win32::Init();
+ ciface::Win32::Init(wsi.render_surface);
#endif
#ifdef CIFACE_USE_XLIB
// nothing needed
@@ -154,7 +154,7 @@ void ControllerInterface::Shutdown()
ciface::Win32::DeInit();
#endif
#ifdef CIFACE_USE_XLIB
- // nothing needed
+// nothing needed
#endif
#ifdef CIFACE_USE_OSX
ciface::OSX::DeInit();
diff --git a/Source/Core/InputCommon/ControllerInterface/DInput/DInput.cpp b/Source/Core/InputCommon/ControllerInterface/DInput/DInput.cpp
index aacbcd55f8..e65da0eb78 100644
--- a/Source/Core/InputCommon/ControllerInterface/DInput/DInput.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/DInput/DInput.cpp
@@ -46,6 +46,8 @@ std::string GetDeviceName(const LPDIRECTINPUTDEVICE8 device)
void PopulateDevices(HWND hwnd)
{
+ g_controller_interface.RemoveDevice([](const auto* dev) { return dev->GetSource() == "DInput"; });
+
IDirectInput8* idi8;
if (FAILED(DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8,
(LPVOID*)&idi8, nullptr)))
diff --git a/Source/Core/InputCommon/ControllerInterface/Win32/Win32.cpp b/Source/Core/InputCommon/ControllerInterface/Win32/Win32.cpp
index 2ce583e608..6c78c6b2a0 100644
--- a/Source/Core/InputCommon/ControllerInterface/Win32/Win32.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/Win32/Win32.cpp
@@ -4,23 +4,132 @@
#include "InputCommon/ControllerInterface/Win32/Win32.h"
+#include <windows.h>
+
+#include <thread>
+
+#include "Common/Event.h"
+#include "Common/Logging/Log.h"
+#include "Common/ScopeGuard.h"
#include "InputCommon/ControllerInterface/DInput/DInput.h"
#include "InputCommon/ControllerInterface/XInput/XInput.h"
-void ciface::Win32::Init()
+constexpr UINT WM_DOLPHIN_STOP = WM_USER;
+
+static Common::Event s_done_populating;
+static std::atomic<HWND> s_hwnd;
+static HWND s_message_window;
+static std::thread s_thread;
+
+static LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
+{
+ if (message == WM_INPUT_DEVICE_CHANGE)
+ {
+ ciface::DInput::PopulateDevices(s_hwnd);
+ ciface::XInput::PopulateDevices();
+ s_done_populating.Set();
+ }
+
+ return DefWindowProc(hwnd, message, wparam, lparam);
+}
+
+void ciface::Win32::Init(void* hwnd)
{
- // DInput::Init();
+ s_hwnd = static_cast<HWND>(hwnd);
XInput::Init();
+
+ s_thread = std::thread([] {
+ if (FAILED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED)))
+ {
+ ERROR_LOG(SERIALINTERFACE, "CoInitializeEx failed: %i", GetLastError());
+ return;
+ }
+ Common::ScopeGuard uninit([] { CoUninitialize(); });
+
+ WNDCLASSEX window_class_info{};
+ window_class_info.cbSize = sizeof(window_class_info);
+ window_class_info.lpfnWndProc = WindowProc;
+ window_class_info.hInstance = GetModuleHandle(nullptr);
+ window_class_info.lpszClassName = L"Message";
+
+ ATOM window_class = RegisterClassEx(&window_class_info);
+ if (!window_class)
+ {
+ NOTICE_LOG(SERIALINTERFACE, "RegisterClassEx failed: %i", GetLastError());
+ return;
+ }
+ Common::ScopeGuard unregister([&window_class] {
+ if (!UnregisterClass(MAKEINTATOM(window_class), GetModuleHandle(nullptr)))
+ ERROR_LOG(SERIALINTERFACE, "UnregisterClass failed: %i", GetLastError());
+ });
+
+ s_message_window = CreateWindowEx(0, L"Message", nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr,
+ nullptr, nullptr);
+ if (!s_message_window)
+ {
+ ERROR_LOG(SERIALINTERFACE, "CreateWindowEx failed: %i", GetLastError());
+ return;
+ }
+ Common::ScopeGuard destroy([] {
+ if (!DestroyWindow(s_message_window))
+ ERROR_LOG(SERIALINTERFACE, "DestroyWindow failed: %i", GetLastError());
+ s_message_window = nullptr;
+ });
+
+ std::array<RAWINPUTDEVICE, 2> devices;
+ // game pad devices
+ devices[0].usUsagePage = 0x01;
+ devices[0].usUsage = 0x05;
+ devices[0].dwFlags = RIDEV_DEVNOTIFY;
+ devices[0].hwndTarget = s_message_window;
+ // joystick devices
+ devices[1].usUsagePage = 0x01;
+ devices[1].usUsage = 0x04;
+ devices[1].dwFlags = RIDEV_DEVNOTIFY;
+ devices[1].hwndTarget = s_message_window;
+
+ if (!RegisterRawInputDevices(devices.data(), static_cast<UINT>(devices.size()),
+ static_cast<UINT>(sizeof(decltype(devices)::value_type))))
+ {
+ ERROR_LOG(SERIALINTERFACE, "RegisterRawInputDevices failed: %i", GetLastError());
+ return;
+ }
+
+ MSG msg;
+ while (GetMessage(&msg, nullptr, 0, 0) > 0)
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ if (msg.message == WM_DOLPHIN_STOP)
+ break;
+ }
+ });
}
void ciface::Win32::PopulateDevices(void* hwnd)
{
- DInput::PopulateDevices(static_cast<HWND>(hwnd));
- XInput::PopulateDevices();
+ if (s_thread.joinable())
+ {
+ s_hwnd = static_cast<HWND>(hwnd);
+ s_done_populating.Reset();
+ PostMessage(s_message_window, WM_INPUT_DEVICE_CHANGE, 0, 0);
+ if (!s_done_populating.WaitFor(std::chrono::seconds(10)))
+ ERROR_LOG(SERIALINTERFACE, "win32 timed out when trying to populate devices");
+ }
+ else
+ {
+ ERROR_LOG(SERIALINTERFACE, "win32 asked to populate devices, but device thread isn't running");
+ }
}
void ciface::Win32::DeInit()
{
- // DInput::DeInit();
+ NOTICE_LOG(SERIALINTERFACE, "win32 DeInit");
+ if (s_thread.joinable())
+ {
+ PostMessage(s_message_window, WM_DOLPHIN_STOP, 0, 0);
+ s_thread.join();
+ }
+
XInput::DeInit();
}
diff --git a/Source/Core/InputCommon/ControllerInterface/Win32/Win32.h b/Source/Core/InputCommon/ControllerInterface/Win32/Win32.h
index 038a792e54..5f4a65c509 100644
--- a/Source/Core/InputCommon/ControllerInterface/Win32/Win32.h
+++ b/Source/Core/InputCommon/ControllerInterface/Win32/Win32.h
@@ -8,8 +8,8 @@ namespace ciface
{
namespace Win32
{
-void Init();
+void Init(void* hwnd);
void PopulateDevices(void* hwnd);
void DeInit();
-}
-}
+} // namespace Win32
+} // namespace ciface
diff --git a/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp b/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp
index 8c518335a0..f3e984d897 100644
--- a/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp
@@ -92,6 +92,8 @@ void PopulateDevices()
if (!hXInput)
return;
+ g_controller_interface.RemoveDevice([](const auto* dev) { return dev->GetSource() == "XInput"; });
+
XINPUT_CAPABILITIES caps;
for (int i = 0; i != 4; ++i)
if (ERROR_SUCCESS == PXInputGetCapabilities(i, 0, &caps))