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 + +#include + +#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 s_hwnd; +static HWND s_message_window; +static std::thread s_thread; + +static LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { - // DInput::Init(); + 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) +{ + s_hwnd = static_cast(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 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(devices.size()), + static_cast(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)); - XInput::PopulateDevices(); + if (s_thread.joinable()) + { + s_hwnd = static_cast(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))