diff options
| author | Michael M <mchtly@gmail.com> | 2017-11-10 12:30:37 -0800 |
|---|---|---|
| committer | Jordan Woyak <jordan.woyak@gmail.com> | 2019-03-29 08:01:40 -0500 |
| commit | d26c1ce24d9108114d7eab97cfc2ab4f3eea28ee (patch) | |
| tree | 8bbc9de32bfea224eb11c33076996f56b4e9925a /Source/Core/InputCommon/ControllerInterface/Win32/Win32.cpp | |
| parent | 92ca6e124e82f63b61982a5ecfb26ca818f2fe47 (diff) | |
Add hotplug support to DInput and XInput controller backends
Diffstat (limited to 'Source/Core/InputCommon/ControllerInterface/Win32/Win32.cpp')
| -rw-r--r-- | Source/Core/InputCommon/ControllerInterface/Win32/Win32.cpp | 119 |
1 files changed, 114 insertions, 5 deletions
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(); } |
