diff --git a/CMakeLists.txt b/CMakeLists.txt index 24ba6fd026..19a2ab8893 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2699,8 +2699,6 @@ set(WindowsFiles Windows/W32Util/DarkMode.cpp Windows/W32Util/UAHMenuBar.h Windows/W32Util/UAHMenuBar.cpp - Windows/WindowsHost.cpp - Windows/WindowsHost.h Windows/MainWindow.cpp Windows/MainWindow.h Windows/MainWindowMenu.cpp diff --git a/UWP/PPSSPP_UWPMain.cpp b/UWP/PPSSPP_UWPMain.cpp index 3e7e85e9dc..81a8bfba47 100644 --- a/UWP/PPSSPP_UWPMain.cpp +++ b/UWP/PPSSPP_UWPMain.cpp @@ -41,6 +41,7 @@ #include "UWPHelpers/StorageAsync.h" #include "UWPHelpers/LaunchItem.h" #include "UWPHelpers/InputHelpers.h" +#include "Windows/InputDevice.h" using namespace UWP; using namespace Windows::Foundation; @@ -51,8 +52,6 @@ using namespace Windows::ApplicationModel::DataTransfer; using namespace Windows::Devices::Enumeration; using namespace Concurrency; -std::list> g_input; - // TODO: Use Microsoft::WRL::ComPtr<> for D3D11 objects? // TODO: See https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/WindowsAudioSession for WASAPI with UWP // TODO: Low latency input: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/LowLatencyInput/cpp @@ -87,16 +86,17 @@ PPSSPP_UWPMain::PPSSPP_UWPMain(App ^app, const std::shared_ptrGetDrawContext()->HandleEvent(Draw::Event::GOT_BACKBUFFER, width, height, m_deviceResources->GetBackBufferRenderTargetView()); // add first XInput device to respond - g_input.push_back(std::make_unique()); - - InputDevice::BeginPolling(); + g_InputManager.AddDevice(new XinputDevice()); + g_InputManager.BeginPolling(); // Prepare input pane (for Xbox & touch devices) PrepareInputPane(); } PPSSPP_UWPMain::~PPSSPP_UWPMain() { - InputDevice::StopPolling(); + g_InputManager.StopPolling(); + g_InputManager.Shutdown(); + ctx_->GetDrawContext()->HandleEvent(Draw::Event::LOST_BACKBUFFER, 0, 0, nullptr); NativeShutdownGraphics(); NativeShutdown(); @@ -453,21 +453,7 @@ bool System_GetPropertyBool(SystemProperty prop) { } } -void System_Notify(SystemNotification notification) { - switch (notification) { - case SystemNotification::POLL_CONTROLLERS: - { - for (const auto &device : g_input) - { - if (device->UpdateState() == InputDevice::UPDATESTATE_SKIP_PAD) - break; - } - break; - } - default: - break; - } -} +void System_Notify(SystemNotification notification) {} bool System_MakeRequest(SystemRequestType type, int requestId, const std::string ¶m1, const std::string ¶m2, int64_t param3, int64_t param4) { switch (type) { diff --git a/UWP/PPSSPP_UWPMain.h b/UWP/PPSSPP_UWPMain.h index 09cdfbff3b..96d1a015ea 100644 --- a/UWP/PPSSPP_UWPMain.h +++ b/UWP/PPSSPP_UWPMain.h @@ -7,6 +7,7 @@ #include "Common/GraphicsContext.h" #include "Common/DeviceResources.h" +#include "Windows/InputDevice.h" // Renders Direct2D and 3D content on the screen. namespace UWP { diff --git a/Windows/DinputDevice.cpp b/Windows/DinputDevice.cpp index d1ab4ab610..f09ede548d 100644 --- a/Windows/DinputDevice.cpp +++ b/Windows/DinputDevice.cpp @@ -241,7 +241,7 @@ int DinputDevice::UpdateState() { || js.lVX != 0 || js.lVY != 0 || js.lVZ != 0 || js.lVRx != 0 || js.lVRy != 0 || js.lVRz != 0) { pPrevState = js; - return UPDATESTATE_SKIP_PAD; + return InputDevice::UPDATESTATE_SKIP_PAD; } return -1; } @@ -312,12 +312,6 @@ size_t DinputDevice::getNumPads() static std::set DetectXInputVIDPIDs() { std::set xinputVidPids; - /* - if (FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED))) { - return xinputVidPids; - } - */ - IWbemLocator* pIWbemLocator = nullptr; if (FAILED(CoCreateInstance(__uuidof(WbemLocator), nullptr, CLSCTX_INPROC_SERVER, __uuidof(IWbemLocator), (void**)&pIWbemLocator))) @@ -340,10 +334,10 @@ static std::set DetectXInputVIDPIDs() { return xinputVidPids; } - IWbemClassObject* pDevices[20] = { 0 }; + IWbemClassObject* pDevices[32] = { 0 }; ULONG uReturned = 0; - while (SUCCEEDED(pEnumDevices->Next(10000, 20, pDevices, &uReturned)) && uReturned > 0) { + while (SUCCEEDED(pEnumDevices->Next(10000, 32, pDevices, &uReturned)) && uReturned > 0) { for (ULONG i = 0; i < uReturned; i++) { VARIANT var; if (SUCCEEDED(pDevices[i]->Get(L"DeviceID", 0, &var, nullptr, nullptr))) @@ -369,7 +363,35 @@ static std::set DetectXInputVIDPIDs() { pEnumDevices->Release(); pIWbemServices->Release(); pIWbemLocator->Release(); - // CoUninitialize(); return xinputVidPids; } + +DInputMetaDevice::DInputMetaDevice() { + //find all connected DInput devices of class GamePad + numDinputDevices_ = DinputDevice::getNumPads(); + for (size_t i = 0; i < numDinputDevices_; i++) { + devices_.push_back(std::make_unique(static_cast(i))); + } +} + +int DInputMetaDevice::UpdateState() { + static const int CHECK_FREQUENCY = 71; // Just an arbitrary prime to try to not collide with other periodic checks. + if (checkCounter_++ > CHECK_FREQUENCY) { + const size_t newCount = DinputDevice::getNumPads(); + if (newCount > numDinputDevices_) { + INFO_LOG(Log::System, "New controller device detected"); + for (size_t i = numDinputDevices_; i < newCount; i++) { + devices_.push_back(std::make_unique(static_cast(i))); + } + numDinputDevices_ = newCount; + } + checkCounter_ = 0; + } + + for (const auto &device : devices_) { + if (device->UpdateState() == InputDevice::UPDATESTATE_SKIP_PAD) + return InputDevice::UPDATESTATE_SKIP_PAD; + } + return 0; +} diff --git a/Windows/DinputDevice.h b/Windows/DinputDevice.h index ead15f017f..a83d73d766 100644 --- a/Windows/DinputDevice.h +++ b/Windows/DinputDevice.h @@ -28,15 +28,13 @@ // TODO: This needs a major refactor into a DinputManager and individual devices inside. -class DinputDevice final : - public InputDevice -{ +class DinputDevice { public: //instantiates device number devnum as explored by the first call to //getDevices(), enumerates all devices if not done yet DinputDevice(int devnum); ~DinputDevice(); - int UpdateState() override; + int UpdateState(); static size_t getNumPads(); static void CheckDevices() { needsCheck_ = true; @@ -76,3 +74,13 @@ private: int last_lRy_; int last_lRz_; }; + +struct DInputMetaDevice : public InputDevice { +public: + DInputMetaDevice(); + int UpdateState() override; +private: + std::vector> devices_; + size_t numDinputDevices_ = 0; + int checkCounter_ = 0; +}; diff --git a/Windows/EmuThread.cpp b/Windows/EmuThread.cpp index 00901a3ba8..d5b6ec23fb 100644 --- a/Windows/EmuThread.cpp +++ b/Windows/EmuThread.cpp @@ -18,7 +18,6 @@ #include "Windows/W32Util/Misc.h" #include "Windows/MainWindow.h" #include "Windows/resource.h" -#include "Windows/WindowsHost.h" #include "Core/Reporting.h" #include "Core/MemMap.h" #include "Core/Core.h" diff --git a/Windows/InputDevice.cpp b/Windows/InputDevice.cpp index 46cbd5782a..59126714a7 100644 --- a/Windows/InputDevice.cpp +++ b/Windows/InputDevice.cpp @@ -25,45 +25,43 @@ #include "Core/Config.h" #include "Windows/InputDevice.h" -static std::atomic_flag threadRunningFlag; -static std::thread inputThread; -static std::atomic_bool focused = ATOMIC_VAR_INIT(true); +InputManager g_InputManager; -inline static void ExecuteInputPoll() { - if (focused.load(std::memory_order_relaxed) || !g_Config.bGamepadOnlyFocused) { - System_Notify(SystemNotification::POLL_CONTROLLERS); - } -} - -static void RunInputThread() { +void InputManager::InputThread() { SetCurrentThreadName("Input"); + for (auto &device : devices_) { + device->Init(); + } + // NOTE: The keyboard and mouse buttons are handled via raw input, not here. // This is mainly for controllers which need to be polled, instead of generating events. - - while (threadRunningFlag.test_and_set(std::memory_order_relaxed)) { - ExecuteInputPoll(); + while (runThread_.load(std::memory_order_relaxed)) { + if (focused_.load(std::memory_order_relaxed) || !g_Config.bGamepadOnlyFocused) { + System_Notify(SystemNotification::POLL_CONTROLLERS); + for (const auto &device : devices_) { + if (device->UpdateState() == InputDevice::UPDATESTATE_SKIP_PAD) + break; + } + } // Try to update 250 times per second. Sleep(4); } + + for (auto &device : devices_) { + device->Shutdown(); + } } -void InputDevice::BeginPolling() { - threadRunningFlag.test_and_set(std::memory_order_relaxed); - inputThread = std::thread(&RunInputThread); +void InputManager::BeginPolling() { + runThread_.store(true, std::memory_order_relaxed); + inputThread_ = std::thread([this]() { + InputThread(); + }); } -void InputDevice::StopPolling() { - threadRunningFlag.clear(std::memory_order_relaxed); - - inputThread.join(); -} - -void InputDevice::GainFocus() { - focused.store(true, std::memory_order_relaxed); -} - -void InputDevice::LoseFocus() { - focused.store(false, std::memory_order_relaxed); +void InputManager::StopPolling() { + runThread_.store(false, std::memory_order_relaxed); + inputThread_.join(); } diff --git a/Windows/InputDevice.h b/Windows/InputDevice.h index eaf6577214..ff28e65155 100644 --- a/Windows/InputDevice.h +++ b/Windows/InputDevice.h @@ -19,20 +19,50 @@ #include #include +#include +#include #include "Common/CommonTypes.h" class InputDevice { public: - virtual ~InputDevice() { - } + virtual ~InputDevice() {} + + virtual void Init() {} + virtual void Shutdown() {} enum { UPDATESTATE_SKIP_PAD = 0x1234}; virtual int UpdateState() = 0; - - static void BeginPolling(); - static void StopPolling(); - - static void GainFocus(); - static void LoseFocus(); }; + +class InputManager { +public: + void BeginPolling(); + void StopPolling(); + + void Shutdown() { + devices_.clear(); + } + + void GainFocus() { + focused_.store(true, std::memory_order_relaxed); + } + void LoseFocus() { + focused_.store(false, std::memory_order_relaxed); + } + + void AddDevice(InputDevice *device) { + devices_.emplace_back(std::unique_ptr(device)); + } + +private: + void InputThread(); + + std::vector> devices_; + + std::atomic runThread_; + std::thread inputThread_; + std::atomic focused_; +}; + +extern InputManager g_InputManager; diff --git a/Windows/MainWindow.cpp b/Windows/MainWindow.cpp index 65c8045f77..d225c2a1d4 100644 --- a/Windows/MainWindow.cpp +++ b/Windows/MainWindow.cpp @@ -403,7 +403,7 @@ namespace MainWindow void Minimize() { ShowWindow(hwndMain, SW_MINIMIZE); - InputDevice::LoseFocus(); + g_InputManager.LoseFocus(); } RECT DetermineWindowRectangle() { @@ -926,7 +926,7 @@ namespace MainWindow if (wParam == WA_ACTIVE || wParam == WA_CLICKACTIVE) { WindowsRawInput::GainFocus(); if (!IsIconic(GetHWND())) { - InputDevice::GainFocus(); + g_InputManager.GainFocus(); } g_activeWindow = WINDOW_MAINWINDOW; pause = false; @@ -956,7 +956,7 @@ namespace MainWindow if (wParam == WA_INACTIVE) { System_PostUIMessage(UIMessage::LOST_FOCUS); WindowsRawInput::LoseFocus(); - InputDevice::LoseFocus(); + g_InputManager.LoseFocus(); hasFocus = false; trapMouse = false; } @@ -994,7 +994,7 @@ namespace MainWindow HandleSizeChange(wParam); } if (hasFocus) { - InputDevice::GainFocus(); + g_InputManager.GainFocus(); } break; @@ -1003,7 +1003,7 @@ namespace MainWindow if (!g_Config.bPauseWhenMinimized) { System_PostUIMessage(UIMessage::WINDOW_MINIMIZED, "true"); } - InputDevice::LoseFocus(); + g_InputManager.LoseFocus(); break; default: break; @@ -1133,7 +1133,9 @@ namespace MainWindow } case WM_DESTROY: - InputDevice::StopPolling(); + g_InputManager.StopPolling(); + g_InputManager.Shutdown(); + MainThread_Stop(); WindowsRawInput::Shutdown(); KillTimer(hWnd, TIMER_CURSORUPDATE); @@ -1164,11 +1166,11 @@ namespace MainWindow case WM_USER_RESTART_EMUTHREAD: NativeSetRestarting(); - InputDevice::StopPolling(); + g_InputManager.StopPolling(); MainThread_Stop(); UpdateUIState(UISTATE_MENU); MainThread_Start(g_Config.iGPUBackend == (int)GPUBackend::OPENGL); - InputDevice::BeginPolling(); + g_InputManager.BeginPolling(); break; case WM_USER_SWITCHUMD_UPDATED: diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj index c52a62c76e..d39a9ea087 100644 --- a/Windows/PPSSPP.vcxproj +++ b/Windows/PPSSPP.vcxproj @@ -720,7 +720,6 @@ - Create @@ -1168,7 +1167,6 @@ - diff --git a/Windows/PPSSPP.vcxproj.filters b/Windows/PPSSPP.vcxproj.filters index 10cd3c39bc..7618b385c0 100644 --- a/Windows/PPSSPP.vcxproj.filters +++ b/Windows/PPSSPP.vcxproj.filters @@ -94,9 +94,6 @@ Windows\UI - - Windows\System - Windows\Debugger @@ -303,9 +300,6 @@ Windows\UI - - Windows\System - diff --git a/Windows/RawInput.cpp b/Windows/RawInput.cpp index 6872129716..028155438c 100644 --- a/Windows/RawInput.cpp +++ b/Windows/RawInput.cpp @@ -25,7 +25,6 @@ #include "Common/Log.h" #include "Windows/RawInput.h" #include "Windows/MainWindow.h" -#include "Windows/WindowsHost.h" #include "Common/CommonFuncs.h" #include "Common/SysError.h" #include "Core/Config.h" diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index b5972f3832..96975a0638 100644 --- a/Windows/WindowsHost.cpp +++ b/Windows/WindowsHost.cpp @@ -48,19 +48,6 @@ #include "Windows/main.h" -void WindowsInputManager::Init() { - //add first XInput device to respond - input.push_back(std::make_unique()); -#ifndef _M_ARM - - //find all connected DInput devices of class GamePad - numDinputDevices_ = DinputDevice::getNumPads(); - for (size_t i = 0; i < numDinputDevices_; i++) { - input.push_back(std::make_unique(static_cast(i))); - } -#endif -} - void WindowsInputManager::PollControllers() { static const int CHECK_FREQUENCY = 71; // Just an arbitrary prime to try to not collide with other periodic checks. if (checkCounter_++ > CHECK_FREQUENCY) { diff --git a/Windows/WindowsHost.h b/Windows/WindowsHost.h deleted file mode 100644 index f49d26d7e1..0000000000 --- a/Windows/WindowsHost.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2012- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#include -#include - -#include "Common/CommonWindows.h" -#include "Windows/InputDevice.h" - -class WindowsInputManager { -public: - void Init(); - void PollControllers(); - -private: - size_t numDinputDevices_ = 0; - std::list> input; - - float mouseDeltaX_ = 0; - float mouseDeltaY_ = 0; - - int checkCounter_ = 0; -}; - -extern WindowsInputManager g_inputManager; diff --git a/Windows/main.cpp b/Windows/main.cpp index 19e6ee35e6..674c1fa388 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -23,23 +23,22 @@ #include #include -#include "Common/CommonWindows.h" -#include "Common/File/FileUtil.h" -#include "Common/OSVersion.h" -#include "Common/GPU/Vulkan/VulkanLoader.h" -#include "ppsspp_config.h" - #include #include #include #include #include +#include "Common/CommonWindows.h" +#include "Common/File/FileUtil.h" +#include "Common/OSVersion.h" +#include "Common/GPU/Vulkan/VulkanLoader.h" +#include "ppsspp_config.h" + #include "Common/System/Display.h" #include "Common/System/NativeApp.h" #include "Common/System/System.h" #include "Common/System/Request.h" -#include "Common/File/FileUtil.h" #include "Common/File/VFS/VFS.h" #include "Common/File/VFS/DirectoryReader.h" #include "Common/Data/Text/I18n.h" @@ -55,6 +54,7 @@ #include "Core/ConfigValues.h" #include "Core/SaveState.h" #include "Core/Instance.h" +#include "Core/HLE/Plugins.h" #include "Windows/EmuThread.h" #include "Windows/WindowsAudio.h" #include "ext/disarm.h" @@ -67,7 +67,8 @@ #include "UI/GameInfoCache.h" #include "Windows/resource.h" - +#include "Windows/DinputDevice.h" +#include "Windows/XinputDevice.h" #include "Windows/MainWindow.h" #include "Windows/Debugger/Debugger_Disasm.h" #include "Windows/Debugger/Debugger_MemoryDlg.h" @@ -84,8 +85,6 @@ #include "Windows/Debugger/CtrlRegisterList.h" #include "Windows/Debugger/DebuggerShared.h" #include "Windows/InputBox.h" - -#include "Windows/WindowsHost.h" #include "Windows/main.h" #ifdef _MSC_VER @@ -121,11 +120,11 @@ static std::string gpuDriverVersion; static std::string restartArgs; int g_activeWindow = 0; - -WindowsInputManager g_inputManager; - int g_lastNumInstances = 0; +float mouseDeltaX_ = 0; +float mouseDeltaY_ = 0; + static double g_lastActivity = 0.0; static double g_lastKeepAwake = 0.0; // Time until we stop considering the core active without user input. @@ -150,6 +149,19 @@ static void AddDebugRestartArgs() { restartArgs += " -l"; } +static void PollControllers() { + // Disabled by default, needs a workaround to map to psp keys. + if (g_Config.bMouseControl) { + NativeMouseDelta(mouseDeltaX_, mouseDeltaY_); + } + + mouseDeltaX_ *= g_Config.fMouseSmoothing; + mouseDeltaY_ *= g_Config.fMouseSmoothing; + + HLEPlugins::PluginDataAxis[JOYSTICK_AXIS_MOUSE_REL_X] = mouseDeltaX_; + HLEPlugins::PluginDataAxis[JOYSTICK_AXIS_MOUSE_REL_Y] = mouseDeltaY_; +} + // Adapted mostly as-is from http://www.gamedev.net/topic/495075-how-to-retrieve-info-about-videocard/?view=findpost&p=4229170 // so credit goes to that post's author, and in turn, the author of the site mentioned in that post (which seems to be down?). std::string GetVideoCardDriverVersion() { @@ -488,7 +500,7 @@ void System_Notify(SystemNotification notification) { break; case SystemNotification::POLL_CONTROLLERS: - g_inputManager.PollControllers(); + PollControllers(); // Also poll the audio backend for changes. break; @@ -1117,22 +1129,23 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin MainWindow::Minimize(); } - g_inputManager.Init(); + //add first XInput device to respond + g_InputManager.AddDevice(new XinputDevice()); + g_InputManager.AddDevice(new DInputMetaDevice()); // Emu thread (and render thread, if any) is always running! // Only OpenGL uses an externally managed render thread (due to GL's single-threaded context design). Vulkan // manages its own render thread. MainThread_Start(g_Config.iGPUBackend == (int)GPUBackend::OPENGL); - InputDevice::BeginPolling(); + + g_InputManager.BeginPolling(); HACCEL hAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_ACCELS); HACCEL hDebugAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_DEBUGACCELS); //so.. we're at the message pump of the GUI thread - for (MSG msg; GetMessage(&msg, NULL, 0, 0); ) // for no quit - { - if (msg.message == WM_KEYDOWN) - { + for (MSG msg; GetMessage(&msg, NULL, 0, 0); ) { // for no quit + if (msg.message == WM_KEYDOWN) { //hack to enable/disable menu command accelerate keys MainWindow::UpdateCommands(); @@ -1141,11 +1154,10 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin BringWindowToTop(hwndMain); } - //Translate accelerators and dialog messages... + // Translate accelerators and dialog messages... HWND wnd; HACCEL accel; - switch (g_activeWindow) - { + switch (g_activeWindow) { case WINDOW_MAINWINDOW: wnd = hwndMain; accel = g_Config.bSystemControls ? hAccelTable : NULL; @@ -1172,6 +1184,8 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin g_VFS.Clear(); + // g_InputManager.StopPolling() is called in WM_DESTROY + MainWindow::DestroyDebugWindows(); DialogManager::DestroyAll(); timeEndPeriod(1);