From de3277c6799e27bc54fcd411dbec48a90ebc0f79 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 18 Jan 2021 16:58:34 -0800 Subject: [PATCH 1/3] Debugger: Add API to trigger buttons. --- CMakeLists.txt | 2 + Core/Core.vcxproj | 2 + Core/Core.vcxproj.filters | 6 + Core/Debugger/WebSocket.cpp | 2 + Core/Debugger/WebSocket/InputSubscriber.cpp | 256 ++++++++++++++++++++ Core/Debugger/WebSocket/InputSubscriber.h | 22 ++ UWP/CoreUWP/CoreUWP.vcxproj | 2 + UWP/CoreUWP/CoreUWP.vcxproj.filters | 6 + android/jni/Android.mk | 1 + 9 files changed, 299 insertions(+) create mode 100644 Core/Debugger/WebSocket/InputSubscriber.cpp create mode 100644 Core/Debugger/WebSocket/InputSubscriber.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 21a2332eebf2..81b943386e5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1492,6 +1492,8 @@ add_library(${CoreLibName} ${CoreLinkType} Core/Debugger/WebSocket/GPURecordSubscriber.h Core/Debugger/WebSocket/HLESubscriber.cpp Core/Debugger/WebSocket/HLESubscriber.h + Core/Debugger/WebSocket/InputSubscriber.cpp + Core/Debugger/WebSocket/InputSubscriber.h Core/Debugger/WebSocket/LogBroadcaster.cpp Core/Debugger/WebSocket/LogBroadcaster.h Core/Debugger/WebSocket/MemorySubscriber.cpp diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index e91c514383a6..d899148602c4 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -437,6 +437,7 @@ + @@ -981,6 +982,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 76fac1fe8871..bb8f2bcfc57f 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -965,6 +965,9 @@ Core + + Debugger\WebSocket + @@ -1649,6 +1652,9 @@ Core + + Debugger\WebSocket + diff --git a/Core/Debugger/WebSocket.cpp b/Core/Debugger/WebSocket.cpp index 9c4cdeef3caa..4dad585e715f 100644 --- a/Core/Debugger/WebSocket.cpp +++ b/Core/Debugger/WebSocket.cpp @@ -55,6 +55,7 @@ #include "Core/Debugger/WebSocket/GPUBufferSubscriber.h" #include "Core/Debugger/WebSocket/GPURecordSubscriber.h" #include "Core/Debugger/WebSocket/HLESubscriber.h" +#include "Core/Debugger/WebSocket/InputSubscriber.h" #include "Core/Debugger/WebSocket/MemorySubscriber.h" #include "Core/Debugger/WebSocket/SteppingSubscriber.h" @@ -67,6 +68,7 @@ static const std::vector subscribers({ &WebSocketGPUBufferInit, &WebSocketGPURecordInit, &WebSocketHLEInit, + &WebSocketInputInit, &WebSocketMemoryInit, &WebSocketSteppingInit, }); diff --git a/Core/Debugger/WebSocket/InputSubscriber.cpp b/Core/Debugger/WebSocket/InputSubscriber.cpp new file mode 100644 index 000000000000..9e6276c68cf1 --- /dev/null +++ b/Core/Debugger/WebSocket/InputSubscriber.cpp @@ -0,0 +1,256 @@ +// Copyright (c) 2021- 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/StringUtils.h" +#include "Core/Debugger/WebSocket/InputSubscriber.h" +#include "Core/Debugger/WebSocket/WebSocketUtils.h" +#include "Core/HLE/sceCtrl.h" +#include "Core/HLE/sceDisplay.h" + +static const std::unordered_map buttonLookup = { + { "cross", CTRL_CROSS }, + { "circle", CTRL_CIRCLE }, + { "triangle", CTRL_TRIANGLE }, + { "square", CTRL_SQUARE }, + { "up", CTRL_UP }, + { "down", CTRL_DOWN }, + { "left", CTRL_LEFT }, + { "right", CTRL_RIGHT }, + { "start", CTRL_START }, + { "select", CTRL_SELECT }, + { "home", CTRL_HOME }, + { "screen", CTRL_SCREEN }, + { "note", CTRL_NOTE }, + { "ltrigger", CTRL_LTRIGGER }, + { "rtrigger", CTRL_RTRIGGER }, + { "hold", CTRL_HOLD }, + { "wlan", CTRL_WLAN }, + { "remote_hold", CTRL_REMOTE_HOLD }, + { "vol_up", CTRL_VOL_UP }, + { "vol_down", CTRL_VOL_DOWN }, + { "disc", CTRL_DISC }, + { "memstick", CTRL_MEMSTICK }, + { "forward", CTRL_FORWARD }, + { "back", CTRL_BACK }, + { "playpause", CTRL_PLAYPAUSE }, +}; + +struct WebSocketInputState : public DebuggerSubscriber { + void Buttons(DebuggerRequest &req); + void Press(DebuggerRequest &req); + void Analog(DebuggerRequest &req); + + void Broadcast(net::WebSocketServer *ws) override; + +protected: + struct PressInfo { + std::string ticket; + uint32_t button; + uint32_t duration; + + std::string Event(); + }; + + std::vector pressTickets_; + int lastCounter_ = -1; +}; + +std::string WebSocketInputState::PressInfo::Event() { + JsonWriter j; + j.begin(); + j.writeString("event", "input.press"); + if (!ticket.empty()) { + j.writeRaw("ticket", ticket); + } + j.end(); + return j.str(); +} + +DebuggerSubscriber *WebSocketInputInit(DebuggerEventHandlerMap &map) { + auto p = new WebSocketInputState(); + map["input.buttons"] = std::bind(&WebSocketInputState::Buttons, p, std::placeholders::_1); + map["input.press"] = std::bind(&WebSocketInputState::Press, p, std::placeholders::_1); + map["input.analog"] = std::bind(&WebSocketInputState::Analog, p, std::placeholders::_1); + + return p; +} + +// Alter PSP button press flags (input.buttons) +// +// Parameters: +// - buttons: object containing button names as string keys, boolean press state as value. +// +// Button names (some are not respected by PPSSPP): +// - cross: button on bottom side of right pad. +// - circle: button on right side of right pad. +// - triangle: button on top side of right pad. +// - square: button on left side of right pad. +// - up: d-pad up button. +// - down: d-pad down button. +// - left: d-pad left button. +// - right: d-pad right button. +// - start: rightmost button at bottom of device. +// - select: second to the right at bottom of device. +// - home: leftmost button at bottom of device. +// - screen: brightness control button at bottom of device. +// - note: mute control button at bottom of device. +// - ltrigger: left shoulder trigger button. +// - rtrigger: right shoulder trigger button. +// - hold: hold setting of power switch. +// - wlan: wireless networking switch. +// - remote_hold: hold switch on headset. +// - vol_up: volume up button next to home at bottom of device. +// - vol_down: volume down button next to home at bottom of device. +// - disc: UMD disc sensor. +// - memstick: memory stick sensor. +// - forward: forward button on headset. +// - back: back button on headset. +// - playpause: play/pause button on headset. +// +// Empty response. +void WebSocketInputState::Buttons(DebuggerRequest &req) { + const JsonNode *jsonButtons = req.data.get("buttons"); + if (!jsonButtons) { + return req.Fail("Missing 'buttons' parameter"); + } + if (jsonButtons->value.getTag() != JSON_OBJECT) { + return req.Fail("Invalid 'buttons' parameter type"); + } + + uint32_t downFlags = 0; + uint32_t upFlags = 0; + + for (const JsonNode *button : jsonButtons->value) { + auto info = buttonLookup.find(button->key); + if (info == buttonLookup.end()) { + return req.Fail(StringFromFormat("Unsupported 'buttons' object key '%s'", button->key)); + } + if (button->value.getTag() == JSON_TRUE) { + downFlags |= info->second; + } else if (button->value.getTag() == JSON_FALSE) { + upFlags |= info->second; + } else if (button->value.getTag() != JSON_NULL) { + return req.Fail(StringFromFormat("Unsupported 'buttons' object type for key '%s'", button->key)); + } + } + + if (downFlags) { + __CtrlButtonDown(downFlags); + } + if (upFlags) { + __CtrlButtonUp(upFlags); + } + + req.Respond(); +} + +// Press and release a button (input.press) +// +// Parameters: +// - button: required string indicating button name (see input.buttons.) +// - duration: optional integer indicating frames to press for, defaults to 1. +// +// Empty response once released. +void WebSocketInputState::Press(DebuggerRequest &req) { + std::string button; + if (!req.ParamString("button", &button)) + return; + + PressInfo press; + press.duration = 1; + if (!req.ParamU32("duration", &press.duration, false, DebuggerParamType::OPTIONAL)) + return; + if (press.duration < 0) + return req.Fail("Parameter 'duration' must not be negative"); + const JsonNode *value = req.data.get("ticket"); + press.ticket = value ? json_stringify(value) : ""; + + auto info = buttonLookup.find(button); + if (info == buttonLookup.end()) { + return req.Fail(StringFromFormat("Unsupported button value '%s'", button.c_str())); + } + press.button = info->second; + + __CtrlButtonDown(press.button); + pressTickets_.push_back(press); +} + +void WebSocketInputState::Broadcast(net::WebSocketServer *ws) { + int counter = __DisplayGetNumVblanks(); + if (pressTickets_.empty() || lastCounter_ == counter) + return; + lastCounter_ = counter; + + for (PressInfo &press : pressTickets_) { + press.duration--; + if (press.duration == -1) { + __CtrlButtonUp(press.button); + ws->Send(press.Event()); + } + } + auto negative = [](const PressInfo &press) -> bool { + return press.duration < 0; + }; + pressTickets_.erase(std::remove_if(pressTickets_.begin(), pressTickets_.end(), negative), pressTickets_.end()); +} + +static bool AnalogValue(DebuggerRequest &req, float *value, const char *name) { + const JsonNode *node = req.data.get(name); + if (!node) { + req.Fail(StringFromFormat("Missing '%s' parameter", name)); + return false; + } + if (node->value.getTag() != JSON_NUMBER) { + req.Fail(StringFromFormat("Invalid '%s' parameter type", name)); + return false; + } + + double val = node->value.toNumber(); + if (val < 1.0 || val > 1.0) { + req.Fail(StringFromFormat("Parameter '%s' must be between -1.0 and 1.0", name)); + return false; + } + + *value = (float)val; + return true; +} + +// Set coordinates of analog stick (input.analog) +// +// Parameters: +// - x: required number from -1.0 to 1.0. +// - y: required number from -1.0 to 1.0. +// - stick: optional string, either "left" (default) or "right". +// +// Empty response. +void WebSocketInputState::Analog(DebuggerRequest &req) { + std::string stick = "left"; + if (!req.ParamString("stick", &stick, DebuggerParamType::OPTIONAL)) + return; + if (stick != "left" && stick != "right") + return req.Fail(StringFromFormat("Parameter 'stick' must be 'left' or 'right', not '%s'", stick.c_str())); + float x, y; + if (!AnalogValue(req, &x, "x") || !AnalogValue(req, &y, "y")) + return; + + __CtrlSetAnalogX(x, stick == "left" ? CTRL_STICK_LEFT : CTRL_STICK_RIGHT); + __CtrlSetAnalogY(y, stick == "left" ? CTRL_STICK_LEFT : CTRL_STICK_RIGHT); + + req.Respond(); +} diff --git a/Core/Debugger/WebSocket/InputSubscriber.h b/Core/Debugger/WebSocket/InputSubscriber.h new file mode 100644 index 000000000000..ed67ae659dff --- /dev/null +++ b/Core/Debugger/WebSocket/InputSubscriber.h @@ -0,0 +1,22 @@ +// Copyright (c) 2021- 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/. + +#pragma once + +#include "Core/Debugger/WebSocket/WebSocketUtils.h" + +DebuggerSubscriber *WebSocketInputInit(DebuggerEventHandlerMap &map); diff --git a/UWP/CoreUWP/CoreUWP.vcxproj b/UWP/CoreUWP/CoreUWP.vcxproj index 2e46086a0b93..77fff29b398d 100644 --- a/UWP/CoreUWP/CoreUWP.vcxproj +++ b/UWP/CoreUWP/CoreUWP.vcxproj @@ -399,6 +399,7 @@ + @@ -629,6 +630,7 @@ + diff --git a/UWP/CoreUWP/CoreUWP.vcxproj.filters b/UWP/CoreUWP/CoreUWP.vcxproj.filters index ea66a385985a..06db4d5876ba 100644 --- a/UWP/CoreUWP/CoreUWP.vcxproj.filters +++ b/UWP/CoreUWP/CoreUWP.vcxproj.filters @@ -682,6 +682,9 @@ Debugger\WebSocket + + Debugger\WebSocket + Debugger\WebSocket @@ -1488,6 +1491,9 @@ Debugger\WebSocket + + Debugger\WebSocket + Debugger\WebSocket diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 4579fd9b7701..ef935455d6a3 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -413,6 +413,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/Debugger/WebSocket/GPUBufferSubscriber.cpp \ $(SRC)/Core/Debugger/WebSocket/GPURecordSubscriber.cpp \ $(SRC)/Core/Debugger/WebSocket/HLESubscriber.cpp \ + $(SRC)/Core/Debugger/WebSocket/InputSubscriber.cpp \ $(SRC)/Core/Debugger/WebSocket/LogBroadcaster.cpp \ $(SRC)/Core/Debugger/WebSocket/MemorySubscriber.cpp \ $(SRC)/Core/Debugger/WebSocket/SteppingBroadcaster.cpp \ From f97df5d1537535f0af84298cc8f1ab82f351d0be Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 18 Jan 2021 17:51:35 -0800 Subject: [PATCH 2/3] Debugger: Broadcast ctrl input events. This can be useful to trigger debugging functionality on button press. --- CMakeLists.txt | 2 + Core/Core.vcxproj | 2 + Core/Core.vcxproj.filters | 6 ++ Core/Debugger/WebSocket.cpp | 5 +- Core/Debugger/WebSocket/InputBroadcaster.cpp | 96 ++++++++++++++++++++ Core/Debugger/WebSocket/InputBroadcaster.h | 48 ++++++++++ Core/Debugger/WebSocket/InputSubscriber.cpp | 35 ++++--- Core/Debugger/WebSocket/InputSubscriber.h | 3 + UWP/CoreUWP/CoreUWP.vcxproj | 2 + UWP/CoreUWP/CoreUWP.vcxproj.filters | 6 ++ android/jni/Android.mk | 1 + 11 files changed, 190 insertions(+), 16 deletions(-) create mode 100644 Core/Debugger/WebSocket/InputBroadcaster.cpp create mode 100644 Core/Debugger/WebSocket/InputBroadcaster.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 81b943386e5f..9be8dfd629fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1492,6 +1492,8 @@ add_library(${CoreLibName} ${CoreLinkType} Core/Debugger/WebSocket/GPURecordSubscriber.h Core/Debugger/WebSocket/HLESubscriber.cpp Core/Debugger/WebSocket/HLESubscriber.h + Core/Debugger/WebSocket/InputBroadcaster.cpp + Core/Debugger/WebSocket/InputBroadcaster.h Core/Debugger/WebSocket/InputSubscriber.cpp Core/Debugger/WebSocket/InputSubscriber.h Core/Debugger/WebSocket/LogBroadcaster.cpp diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index d899148602c4..060eeb4ddbb4 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -437,6 +437,7 @@ + @@ -982,6 +983,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index bb8f2bcfc57f..93b6b137effd 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -968,6 +968,9 @@ Debugger\WebSocket + + Debugger\WebSocket + @@ -1655,6 +1658,9 @@ Debugger\WebSocket + + Debugger\WebSocket + diff --git a/Core/Debugger/WebSocket.cpp b/Core/Debugger/WebSocket.cpp index 4dad585e715f..c609e08698ef 100644 --- a/Core/Debugger/WebSocket.cpp +++ b/Core/Debugger/WebSocket.cpp @@ -45,6 +45,7 @@ // For other events, look inside Core/Debugger/WebSocket/ for details on each event. #include "Core/Debugger/WebSocket/GameBroadcaster.h" +#include "Core/Debugger/WebSocket/InputBroadcaster.h" #include "Core/Debugger/WebSocket/LogBroadcaster.h" #include "Core/Debugger/WebSocket/SteppingBroadcaster.h" @@ -127,8 +128,9 @@ void HandleDebuggerRequest(const http::Request &request) { UpdateConnected(1); SetupDebuggerLock(); - LogBroadcaster logger; GameBroadcaster game; + LogBroadcaster logger; + InputBroadcaster input; SteppingBroadcaster stepping; std::unordered_map eventHandlers; @@ -177,6 +179,7 @@ void HandleDebuggerRequest(const http::Request &request) { logger.Broadcast(ws); game.Broadcast(ws); stepping.Broadcast(ws); + input.Broadcast(ws); for (size_t i = 0; i < subscribers.size(); ++i) { if (subscriberData[i]) { diff --git a/Core/Debugger/WebSocket/InputBroadcaster.cpp b/Core/Debugger/WebSocket/InputBroadcaster.cpp new file mode 100644 index 000000000000..1502c6702f43 --- /dev/null +++ b/Core/Debugger/WebSocket/InputBroadcaster.cpp @@ -0,0 +1,96 @@ +// Copyright (c) 2018- 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 "Core/Debugger/WebSocket/InputBroadcaster.h" +#include "Core/Debugger/WebSocket/InputSubscriber.h" +#include "Core/Debugger/WebSocket/WebSocketUtils.h" +#include "Core/HLE/sceCtrl.h" +#include "Core/HLE/sceDisplay.h" + +// Button press state change (input.buttons) +// +// Sent unexpectedly with these properties: +// - buttons: an object with button names as keys and bool press state as values. +// +// See input.buttons.send in InputSubscriber for button names. Only changed buttons are sent. + +// Analog position change (input.analog) +// +// Sent unexpectedly with these properties: +// - stick: "left" or "right". +// - x: number between -1.0 and 1.0, representing horizontal position in a square. +// - y: number between -1.0 and 1.0, representing vertical position in a square. + +std::string InputBroadcaster::Analog::Event(const char *stick) { + JsonWriter j; + j.begin(); + j.writeString("event", "input.analog"); + j.writeString("stick", stick); + j.writeFloat("x", x); + j.writeFloat("y", y); + j.end(); + return j.str(); +} + +static std::string ButtonsEvent(uint32_t lastButtons, uint32_t newButtons) { + uint32_t pressed = newButtons & ~lastButtons; + uint32_t released = ~newButtons & lastButtons; + + JsonWriter j; + j.begin(); + j.writeString("event", "input.buttons"); + j.pushDict("buttons"); + for (auto it : WebSocketInputButtonLookup()) { + if (pressed & it.second) { + j.writeBool(it.first, true); + } else if (released & it.second) { + j.writeBool(it.first, false); + } + } + j.pop(); + j.end(); + return j.str(); +} + +void InputBroadcaster::Broadcast(net::WebSocketServer *ws) { + int counter = __DisplayGetNumVblanks(); + if (lastCounter_ == counter) + return; + lastCounter_ = counter; + + uint32_t newButtons = __CtrlPeekButtons(); + if (newButtons != lastButtons_) { + ws->Send(ButtonsEvent(lastButtons_, newButtons)); + lastButtons_ = newButtons; + } + + Analog newAnalog; + __CtrlPeekAnalog(CTRL_STICK_LEFT, &newAnalog.x, &newAnalog.y); + if (!lastAnalog_[0].Equals(newAnalog)) { + ws->Send(newAnalog.Event("left")); + lastAnalog_[0].x = newAnalog.x; + lastAnalog_[0].y = newAnalog.y; + } + + __CtrlPeekAnalog(CTRL_STICK_RIGHT, &newAnalog.x, &newAnalog.y); + if (!lastAnalog_[1].Equals(newAnalog)) { + ws->Send(newAnalog.Event("right")); + lastAnalog_[1].x = newAnalog.x; + lastAnalog_[1].y = newAnalog.y; + } +} diff --git a/Core/Debugger/WebSocket/InputBroadcaster.h b/Core/Debugger/WebSocket/InputBroadcaster.h new file mode 100644 index 000000000000..dd8031d90249 --- /dev/null +++ b/Core/Debugger/WebSocket/InputBroadcaster.h @@ -0,0 +1,48 @@ +// Copyright (c) 2018- 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/. + +#pragma once + +#include +#include + +namespace net { +class WebSocketServer; +} + +struct InputBroadcaster { +public: + InputBroadcaster() { + } + + void Broadcast(net::WebSocketServer *ws); + +private: + struct Analog { + float x = 0.0f; + float y = 0.0f; + + bool Equals(const Analog &other) const { + return x == other.x && y == other.y; + } + std::string Event(const char *stick); + }; + + int lastCounter_ = -1; + uint32_t lastButtons_ = 0; + Analog lastAnalog_[2]; +}; diff --git a/Core/Debugger/WebSocket/InputSubscriber.cpp b/Core/Debugger/WebSocket/InputSubscriber.cpp index 9e6276c68cf1..b35c8413e7ef 100644 --- a/Core/Debugger/WebSocket/InputSubscriber.cpp +++ b/Core/Debugger/WebSocket/InputSubscriber.cpp @@ -23,7 +23,8 @@ #include "Core/HLE/sceCtrl.h" #include "Core/HLE/sceDisplay.h" -static const std::unordered_map buttonLookup = { +// This is also used in InputBroadcaster. +const std::unordered_map buttonLookup = { { "cross", CTRL_CROSS }, { "circle", CTRL_CIRCLE }, { "triangle", CTRL_TRIANGLE }, @@ -52,9 +53,9 @@ static const std::unordered_map buttonLookup = { }; struct WebSocketInputState : public DebuggerSubscriber { - void Buttons(DebuggerRequest &req); - void Press(DebuggerRequest &req); - void Analog(DebuggerRequest &req); + void ButtonsSend(DebuggerRequest &req); + void ButtonsPress(DebuggerRequest &req); + void AnalogSend(DebuggerRequest &req); void Broadcast(net::WebSocketServer *ws) override; @@ -74,7 +75,7 @@ struct WebSocketInputState : public DebuggerSubscriber { std::string WebSocketInputState::PressInfo::Event() { JsonWriter j; j.begin(); - j.writeString("event", "input.press"); + j.writeString("event", "input.buttons.press"); if (!ticket.empty()) { j.writeRaw("ticket", ticket); } @@ -82,16 +83,20 @@ std::string WebSocketInputState::PressInfo::Event() { return j.str(); } +const std::unordered_map &WebSocketInputButtonLookup() { + return buttonLookup; +} + DebuggerSubscriber *WebSocketInputInit(DebuggerEventHandlerMap &map) { auto p = new WebSocketInputState(); - map["input.buttons"] = std::bind(&WebSocketInputState::Buttons, p, std::placeholders::_1); - map["input.press"] = std::bind(&WebSocketInputState::Press, p, std::placeholders::_1); - map["input.analog"] = std::bind(&WebSocketInputState::Analog, p, std::placeholders::_1); + map["input.buttons.send"] = std::bind(&WebSocketInputState::ButtonsSend, p, std::placeholders::_1); + map["input.buttons.press"] = std::bind(&WebSocketInputState::ButtonsPress, p, std::placeholders::_1); + map["input.analog.send"] = std::bind(&WebSocketInputState::AnalogSend, p, std::placeholders::_1); return p; } -// Alter PSP button press flags (input.buttons) +// Alter PSP button press flags (input.buttons.send) // // Parameters: // - buttons: object containing button names as string keys, boolean press state as value. @@ -124,7 +129,7 @@ DebuggerSubscriber *WebSocketInputInit(DebuggerEventHandlerMap &map) { // - playpause: play/pause button on headset. // // Empty response. -void WebSocketInputState::Buttons(DebuggerRequest &req) { +void WebSocketInputState::ButtonsSend(DebuggerRequest &req) { const JsonNode *jsonButtons = req.data.get("buttons"); if (!jsonButtons) { return req.Fail("Missing 'buttons' parameter"); @@ -160,14 +165,14 @@ void WebSocketInputState::Buttons(DebuggerRequest &req) { req.Respond(); } -// Press and release a button (input.press) +// Press and release a button (input.buttons.press) // // Parameters: -// - button: required string indicating button name (see input.buttons.) +// - button: required string indicating button name (see input.buttons.send.) // - duration: optional integer indicating frames to press for, defaults to 1. // // Empty response once released. -void WebSocketInputState::Press(DebuggerRequest &req) { +void WebSocketInputState::ButtonsPress(DebuggerRequest &req) { std::string button; if (!req.ParamString("button", &button)) return; @@ -231,7 +236,7 @@ static bool AnalogValue(DebuggerRequest &req, float *value, const char *name) { return true; } -// Set coordinates of analog stick (input.analog) +// Set coordinates of analog stick (input.analog.send) // // Parameters: // - x: required number from -1.0 to 1.0. @@ -239,7 +244,7 @@ static bool AnalogValue(DebuggerRequest &req, float *value, const char *name) { // - stick: optional string, either "left" (default) or "right". // // Empty response. -void WebSocketInputState::Analog(DebuggerRequest &req) { +void WebSocketInputState::AnalogSend(DebuggerRequest &req) { std::string stick = "left"; if (!req.ParamString("stick", &stick, DebuggerParamType::OPTIONAL)) return; diff --git a/Core/Debugger/WebSocket/InputSubscriber.h b/Core/Debugger/WebSocket/InputSubscriber.h index ed67ae659dff..65acbe9efe2b 100644 --- a/Core/Debugger/WebSocket/InputSubscriber.h +++ b/Core/Debugger/WebSocket/InputSubscriber.h @@ -17,6 +17,9 @@ #pragma once +#include +#include #include "Core/Debugger/WebSocket/WebSocketUtils.h" DebuggerSubscriber *WebSocketInputInit(DebuggerEventHandlerMap &map); +const std::unordered_map &WebSocketInputButtonLookup(); diff --git a/UWP/CoreUWP/CoreUWP.vcxproj b/UWP/CoreUWP/CoreUWP.vcxproj index 77fff29b398d..8b40a36f2e1d 100644 --- a/UWP/CoreUWP/CoreUWP.vcxproj +++ b/UWP/CoreUWP/CoreUWP.vcxproj @@ -399,6 +399,7 @@ + @@ -630,6 +631,7 @@ + diff --git a/UWP/CoreUWP/CoreUWP.vcxproj.filters b/UWP/CoreUWP/CoreUWP.vcxproj.filters index 06db4d5876ba..c688cd49f595 100644 --- a/UWP/CoreUWP/CoreUWP.vcxproj.filters +++ b/UWP/CoreUWP/CoreUWP.vcxproj.filters @@ -682,6 +682,9 @@ Debugger\WebSocket + + Debugger\WebSocket + Debugger\WebSocket @@ -1491,6 +1494,9 @@ Debugger\WebSocket + + Debugger\WebSocket + Debugger\WebSocket diff --git a/android/jni/Android.mk b/android/jni/Android.mk index ef935455d6a3..e3e9ba19ff25 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -413,6 +413,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/Debugger/WebSocket/GPUBufferSubscriber.cpp \ $(SRC)/Core/Debugger/WebSocket/GPURecordSubscriber.cpp \ $(SRC)/Core/Debugger/WebSocket/HLESubscriber.cpp \ + $(SRC)/Core/Debugger/WebSocket/InputBroadcaster.cpp \ $(SRC)/Core/Debugger/WebSocket/InputSubscriber.cpp \ $(SRC)/Core/Debugger/WebSocket/LogBroadcaster.cpp \ $(SRC)/Core/Debugger/WebSocket/MemorySubscriber.cpp \ From 1148e6e4ba2df61421aebdf7f4546b1c768af3be Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 18 Jan 2021 17:59:58 -0800 Subject: [PATCH 3/3] Debugger: Include all press states for convenience. In case of a multi-button shortcut, which might be common for debugging. --- Core/Debugger/WebSocket/InputBroadcaster.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Core/Debugger/WebSocket/InputBroadcaster.cpp b/Core/Debugger/WebSocket/InputBroadcaster.cpp index 1502c6702f43..388000dbbc7a 100644 --- a/Core/Debugger/WebSocket/InputBroadcaster.cpp +++ b/Core/Debugger/WebSocket/InputBroadcaster.cpp @@ -26,8 +26,9 @@ // // Sent unexpectedly with these properties: // - buttons: an object with button names as keys and bool press state as values. +// - changed: same as buttons, but only including changed states. // -// See input.buttons.send in InputSubscriber for button names. Only changed buttons are sent. +// See input.buttons.send in InputSubscriber for button names. // Analog position change (input.analog) // @@ -55,6 +56,11 @@ static std::string ButtonsEvent(uint32_t lastButtons, uint32_t newButtons) { j.begin(); j.writeString("event", "input.buttons"); j.pushDict("buttons"); + for (auto it : WebSocketInputButtonLookup()) { + j.writeBool(it.first, (newButtons & it.second) != 0); + } + j.pop(); + j.pushDict("changed"); for (auto it : WebSocketInputButtonLookup()) { if (pressed & it.second) { j.writeBool(it.first, true);