More refactoring

This commit is contained in:
Henrik Rydgård
2025-06-28 14:05:20 +02:00
parent c311cb9fdf
commit f6aa92d635
7 changed files with 174 additions and 82 deletions
+7 -21
View File
@@ -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<std::unique_ptr<InputDevice>> 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_ptr<DX::DeviceResourc
ctx_->GetDrawContext()->HandleEvent(Draw::Event::GOT_BACKBUFFER, width, height, m_deviceResources->GetBackBufferRenderTargetView());
// add first XInput device to respond
g_input.push_back(std::make_unique<XinputDevice>());
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 &param1, const std::string &param2, int64_t param3, int64_t param4) {
switch (type) {
+1
View File
@@ -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 {
+26 -28
View File
@@ -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();
}
+38 -8
View File
@@ -19,20 +19,50 @@
#include <list>
#include <memory>
#include <atomic>
#include <thread>
#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<InputDevice>(device));
}
private:
void InputThread();
std::vector<std::unique_ptr<InputDevice>> devices_;
std::atomic<bool> runThread_;
std::thread inputThread_;
std::atomic<bool> focused_;
};
extern InputManager g_InputManager;
+10 -8
View File
@@ -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:
+82
View File
@@ -0,0 +1,82 @@
// 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 "ppsspp_config.h"
#include <algorithm>
// native stuff
#include "Common/System/Display.h"
#include "Common/System/NativeApp.h"
#include "Common/Input/InputState.h"
#include "Common/Input/KeyCodes.h"
#include "Common/StringUtils.h"
#include "Core/Core.h"
#include "Core/Config.h"
#include "Core/ConfigValues.h"
#include "Core/CoreParameter.h"
#include "Core/HLE/Plugins.h"
#include "Core/System.h"
#include "Core/Debugger/SymbolMap.h"
#include "Core/Instance.h"
#include "UI/OnScreenDisplay.h"
#include "Windows/EmuThread.h"
#include "Windows/WindowsHost.h"
#include "Windows/MainWindow.h"
#ifndef _M_ARM
#include "Windows/DinputDevice.h"
#endif
#include "Windows/XinputDevice.h"
#include "Windows/main.h"
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) {
#ifndef _M_ARM
size_t newCount = DinputDevice::getNumPads();
if (newCount > numDinputDevices_) {
INFO_LOG(Log::System, "New controller device detected");
for (size_t i = numDinputDevices_; i < newCount; i++) {
input.push_back(std::make_unique<DinputDevice>(static_cast<int>(i)));
}
numDinputDevices_ = newCount;
}
#endif
checkCounter_ = 0;
}
for (const auto &device : input) {
if (device->UpdateState() == InputDevice::UPDATESTATE_SKIP_PAD)
break;
}
// 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_;
}
+10 -17
View File
@@ -122,8 +122,6 @@ static std::string restartArgs;
int g_activeWindow = 0;
int g_lastNumInstances = 0;
std::list<std::unique_ptr<InputDevice>> g_inputDevices;
float mouseDeltaX_ = 0;
float mouseDeltaY_ = 0;
@@ -152,11 +150,6 @@ static void AddDebugRestartArgs() {
}
static void PollControllers() {
for (const auto &device : g_inputDevices) {
if (device->UpdateState() == InputDevice::UPDATESTATE_SKIP_PAD)
break;
}
// Disabled by default, needs a workaround to map to psp keys.
if (g_Config.bMouseControl) {
NativeMouseDelta(mouseDeltaX_, mouseDeltaY_);
@@ -1137,23 +1130,22 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
}
//add first XInput device to respond
g_inputDevices.push_back(std::make_unique<XinputDevice>());
g_inputDevices.push_back(std::make_unique<DInputMetaDevice>());
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();
@@ -1162,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;
@@ -1193,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);