From 0ff228e1faaefb2b91eddc0a80c7a1a1ad17ebee Mon Sep 17 00:00:00 2001 From: jw098 Date: Wed, 10 Sep 2025 21:57:48 -0700 Subject: [PATCH 01/34] add KeyboardEventHandler class --- SerialPrograms/CMakeLists.txt | 2 + .../KeyboardInput/KeyboardEventHandler.cpp | 34 +++++++++++++++++ .../KeyboardInput/KeyboardEventHandler.h | 37 +++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.cpp create mode 100644 SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h diff --git a/SerialPrograms/CMakeLists.txt b/SerialPrograms/CMakeLists.txt index 3870f6d30d..e82b798643 100644 --- a/SerialPrograms/CMakeLists.txt +++ b/SerialPrograms/CMakeLists.txt @@ -701,6 +701,8 @@ file(GLOB MAIN_SOURCES Source/Controllers/JoystickTools.h Source/Controllers/KeyboardInput/GlobalQtKeyMap.cpp Source/Controllers/KeyboardInput/GlobalQtKeyMap.h + Source/Controllers/KeyboardInput/KeyboardEventHandler.cpp + Source/Controllers/KeyboardInput/KeyboardEventHandler.h Source/Controllers/KeyboardInput/KeyboardInput.cpp Source/Controllers/KeyboardInput/KeyboardInput.h Source/Controllers/KeyboardInput/KeyboardStateTracker.cpp diff --git a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.cpp b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.cpp new file mode 100644 index 0000000000..6a191ab2af --- /dev/null +++ b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.cpp @@ -0,0 +1,34 @@ +/* Keyboard Event Handler + * + */ +#include "Common/Cpp/ListenerSet.h" +#include "Common/Cpp/Containers/Pimpl.tpp" +#include "KeyboardEventHandler.h" + +namespace PokemonAutomation{ + + + +struct KeyboardEventHandler::Data{ + ListenerSet m_listeners; +}; + +KeyboardEventHandler::KeyboardEventHandler() + : m_data(CONSTRUCT_TOKEN) +{} + +KeyboardEventHandler::~KeyboardEventHandler() = default; + +void KeyboardEventHandler::add_listener(KeyboardListener& listener){ + auto scope = m_lifetime_sanitizer.check_scope(); + Data& data = *m_data; + data.m_listeners.add(listener); +} +void KeyboardEventHandler::remove_listener(KeyboardListener& listener){ + auto scope = m_lifetime_sanitizer.check_scope(); + Data& data = *m_data; + data.m_listeners.remove(listener); +} + + +} \ No newline at end of file diff --git a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h new file mode 100644 index 0000000000..4230c6c165 --- /dev/null +++ b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h @@ -0,0 +1,37 @@ +/* Keyboard Event Handler + * + * From: https://github.com/PokemonAutomation/ + * + */ + + +#ifndef PokemonAutomation_Controllers_KeyboardEventHandler_H +#define PokemonAutomation_Controllers_KeyboardEventHandler_H + +#include "Common/Cpp/Containers/Pimpl.h" +#include "Common/Cpp/Time.h" +#include "Common/Cpp/LifetimeSanitizer.h" +#include "NintendoSwitch/Controllers/NintendoSwitch_VirtualControllerState.h" + +namespace PokemonAutomation{ + +class KeyboardEventHandler{ +public: + KeyboardEventHandler(); + virtual ~KeyboardEventHandler(); + + struct KeyboardListener{ + virtual void on_keyboard_control_state_change(Milliseconds duration, const NintendoSwitch::ProControllerState& state){} + }; + void add_listener(KeyboardListener& listener); + void remove_listener(KeyboardListener& listener); + +private: + struct Data; + Pimpl m_data; + + LifetimeSanitizer m_lifetime_sanitizer; +}; + +} +#endif \ No newline at end of file From f9c8bdb403bf6bb89e358ab1043cfd2a821be1a7 Mon Sep 17 00:00:00 2001 From: jw098 Date: Wed, 10 Sep 2025 22:25:58 -0700 Subject: [PATCH 02/34] KeyboardManager inherits KeyboardEventHandler --- .../Source/Controllers/KeyboardInput/KeyboardEventHandler.h | 5 ++++- .../Source/Controllers/KeyboardInput/KeyboardInput.h | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h index 4230c6c165..1e271c31bd 100644 --- a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h +++ b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h @@ -11,10 +11,13 @@ #include "Common/Cpp/Containers/Pimpl.h" #include "Common/Cpp/Time.h" #include "Common/Cpp/LifetimeSanitizer.h" -#include "NintendoSwitch/Controllers/NintendoSwitch_VirtualControllerState.h" namespace PokemonAutomation{ +namespace NintendoSwitch{ + class ProControllerState; // forward declaration to avoid circular dependency +} + class KeyboardEventHandler{ public: KeyboardEventHandler(); diff --git a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardInput.h b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardInput.h index 553f9eea90..91e692633a 100644 --- a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardInput.h +++ b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardInput.h @@ -14,6 +14,7 @@ #include "Common/Cpp/Concurrency/SpinLock.h" #include "Controllers/Controller.h" #include "Controllers/KeyboardInput/GlobalQtKeyMap.h" +#include "KeyboardEventHandler.h" #include "KeyboardStateTracker.h" class QKeyEvent; @@ -86,7 +87,7 @@ class KeyboardInputController{ template -class KeyboardManager : public KeyboardInputController{ +class KeyboardManager : public KeyboardInputController, public KeyboardEventHandler{ public: KeyboardManager(Logger& logger, AbstractController& controller) : KeyboardInputController(logger, true) From a23f5cd8ff1dc4e38fcea67a63892dcdc09f04b2 Mon Sep 17 00:00:00 2001 From: jw098 Date: Wed, 10 Sep 2025 22:33:33 -0700 Subject: [PATCH 03/34] ProController inherits KeyboardEventHandler::KeyboardListener --- .../Controllers/NintendoSwitch_ProController.cpp | 2 ++ .../NintendoSwitch/Controllers/NintendoSwitch_ProController.h | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp index d011727ee8..43623bcd4c 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp @@ -102,7 +102,9 @@ void ProController::keyboard_release(const QKeyEvent& event){ } +void ProController::on_keyboard_control_state_change(Milliseconds duration, const ProControllerState& state) { +} diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h index 0fa51b7d7d..bb05732a2a 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h @@ -53,13 +53,15 @@ constexpr Button VALID_PRO_CONTROLLER_BUTTONS = // // This is the generic interface to a Switch pro controller. // -class ProController : public AbstractController{ +class ProController : public AbstractController, public KeyboardEventHandler::KeyboardListener{ public: using ContextType = ProControllerContext; ProController(Logger& logger); virtual ~ProController(); +private: + virtual void on_keyboard_control_state_change(Milliseconds duration, const ProControllerState& state) override; public: static const char NAME[]; From b486acebcef184bb2a34893588e05205516e6601 Mon Sep 17 00:00:00 2001 From: jw098 Date: Wed, 10 Sep 2025 22:59:15 -0700 Subject: [PATCH 04/34] add KeyboardEventHandler::report_keyboard_state_changed --- .../Controllers/KeyboardInput/KeyboardEventHandler.cpp | 6 ++++++ .../Source/Controllers/KeyboardInput/KeyboardEventHandler.h | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.cpp b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.cpp index 6a191ab2af..5b3c76bdb7 100644 --- a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.cpp +++ b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.cpp @@ -30,5 +30,11 @@ void KeyboardEventHandler::remove_listener(KeyboardListener& listener){ data.m_listeners.remove(listener); } +void KeyboardEventHandler::report_keyboard_state_changed(Milliseconds duration, const NintendoSwitch::ProControllerState& state){ + auto scope = m_lifetime_sanitizer.check_scope(); + Data& data = *m_data; + data.m_listeners.run_method_unique(&KeyboardListener::on_keyboard_control_state_change, duration, state); +} + } \ No newline at end of file diff --git a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h index 1e271c31bd..2f21a2a93b 100644 --- a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h +++ b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h @@ -29,6 +29,11 @@ class KeyboardEventHandler{ void add_listener(KeyboardListener& listener); void remove_listener(KeyboardListener& listener); +protected: + // Report that the keyboard state has changed. This will be pushed to + // all listeners. + void report_keyboard_state_changed(Milliseconds duration, const NintendoSwitch::ProControllerState& state); + private: struct Data; Pimpl m_data; From c329ead8c67a92d19a17c5aeed4499118b4363ef Mon Sep 17 00:00:00 2001 From: jw098 Date: Thu, 11 Sep 2025 20:33:27 -0700 Subject: [PATCH 05/34] KeyboardListener prints whenever it detects a send or stop command. --- .../KeyboardInput/KeyboardEventHandler.cpp | 10 ++++++++-- .../KeyboardInput/KeyboardEventHandler.h | 7 +++++-- .../Controllers/KeyboardInput/KeyboardInput.h | 2 ++ .../NintendoSwitch_ProController.cpp | 19 +++++++++++++++++-- .../NintendoSwitch_ProController.h | 4 +++- .../DevPrograms/TestProgramSwitch.cpp | 13 +++++++++++-- 6 files changed, 46 insertions(+), 9 deletions(-) diff --git a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.cpp b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.cpp index 5b3c76bdb7..e0757853aa 100644 --- a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.cpp +++ b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.cpp @@ -30,10 +30,16 @@ void KeyboardEventHandler::remove_listener(KeyboardListener& listener){ data.m_listeners.remove(listener); } -void KeyboardEventHandler::report_keyboard_state_changed(Milliseconds duration, const NintendoSwitch::ProControllerState& state){ +void KeyboardEventHandler::report_keyboard_command_sent(const NintendoSwitch::ProControllerState& state){ auto scope = m_lifetime_sanitizer.check_scope(); Data& data = *m_data; - data.m_listeners.run_method_unique(&KeyboardListener::on_keyboard_control_state_change, duration, state); + data.m_listeners.run_method_unique(&KeyboardListener::on_keyboard_command_sent, state); +} + +void KeyboardEventHandler::report_keyboard_command_stopped(){ + auto scope = m_lifetime_sanitizer.check_scope(); + Data& data = *m_data; + data.m_listeners.run_method_unique(&KeyboardListener::on_keyboard_command_stopped); } diff --git a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h index 2f21a2a93b..05d9c5a090 100644 --- a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h +++ b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h @@ -24,7 +24,8 @@ class KeyboardEventHandler{ virtual ~KeyboardEventHandler(); struct KeyboardListener{ - virtual void on_keyboard_control_state_change(Milliseconds duration, const NintendoSwitch::ProControllerState& state){} + virtual void on_keyboard_command_sent(const NintendoSwitch::ProControllerState& state){} + virtual void on_keyboard_command_stopped(){} }; void add_listener(KeyboardListener& listener); void remove_listener(KeyboardListener& listener); @@ -32,7 +33,9 @@ class KeyboardEventHandler{ protected: // Report that the keyboard state has changed. This will be pushed to // all listeners. - void report_keyboard_state_changed(Milliseconds duration, const NintendoSwitch::ProControllerState& state); + void report_keyboard_command_sent(const NintendoSwitch::ProControllerState& state); + + void report_keyboard_command_stopped(); private: struct Data; diff --git a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardInput.h b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardInput.h index 91e692633a..6f71d03500 100644 --- a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardInput.h +++ b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardInput.h @@ -128,6 +128,7 @@ class KeyboardManager : public KeyboardInputController, public KeyboardEventHand return; } m_controller->cancel_all_commands(); + report_keyboard_command_stopped(); } virtual void replace_on_next_command() override{ WriteSpinLock lg(m_lock); @@ -135,6 +136,7 @@ class KeyboardManager : public KeyboardInputController, public KeyboardEventHand return; } m_controller->replace_on_next_command(); + report_keyboard_command_stopped(); } diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp index 43623bcd4c..ac24631954 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp @@ -12,6 +12,10 @@ #include "NintendoSwitch_VirtualControllerState.h" #include "NintendoSwitch_ProController.h" +#include +using std::cout; +using std::endl; + namespace PokemonAutomation{ // Instantiate some template helper classes. @@ -73,7 +77,11 @@ class ProController::KeyboardManager final : switch_state.right_x, switch_state.right_y ); + + report_keyboard_command_sent(switch_state); } + + }; @@ -84,7 +92,7 @@ ProController::ProController(Logger& logger) } ProController::~ProController(){ - + m_keyboard_manager->remove_listener(*this); } void ProController::stop() noexcept{ m_keyboard_manager->stop(); @@ -101,9 +109,16 @@ void ProController::keyboard_release(const QKeyEvent& event){ m_keyboard_manager->on_key_release(event); } +void ProController::on_keyboard_command_sent(const ProControllerState& state) { + cout << "keyboard_command_sent" << endl; +} -void ProController::on_keyboard_control_state_change(Milliseconds duration, const ProControllerState& state) { +void ProController::on_keyboard_command_stopped() { + cout << "keyboard_command_stopped" << endl; +} +void ProController::monitor_keyboard_events(){ + m_keyboard_manager->add_listener(*this); } diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h index bb05732a2a..679c9b2660 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h @@ -61,7 +61,8 @@ class ProController : public AbstractController, public KeyboardEventHandler::Ke virtual ~ProController(); private: - virtual void on_keyboard_control_state_change(Milliseconds duration, const ProControllerState& state) override; + virtual void on_keyboard_command_sent(const ProControllerState& state) override; + virtual void on_keyboard_command_stopped() override; public: static const char NAME[]; @@ -220,6 +221,7 @@ class ProController : public AbstractController, public KeyboardEventHandler::Ke DpadPosition direction // Diagonals not allowed. ) = 0; + void monitor_keyboard_events(); public: // Keyboard Input diff --git a/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp b/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp index a2c9f0676a..98ef5af416 100644 --- a/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp +++ b/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp @@ -264,12 +264,21 @@ void TestProgram::program(MultiSwitchProgramEnvironment& env, CancellableScope& ProControllerContext context(scope, console.controller()); VideoOverlaySet overlays(overlay); +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// - HomeMenuDetector detector(console); - detector.make_overlays(overlays); +#if 1 + context.controller().monitor_keyboard_events(); +#endif +#if 0 + + HomeMenuDetector detector(console); + detector.make_overlays(overlays); +#endif + #if 0 // auto screenshot = feed.snapshot(); From 1b6249b1034b9989baa22b47f8a4f724b01b082c Mon Sep 17 00:00:00 2001 From: jw098 Date: Thu, 11 Sep 2025 21:37:39 -0700 Subject: [PATCH 06/34] Callbacks triggered at the beginning of function, instead of at the end. --- .../Source/Controllers/KeyboardInput/KeyboardInput.h | 4 ++-- .../Controllers/NintendoSwitch_ProController.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardInput.h b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardInput.h index 6f71d03500..c5d7a7e002 100644 --- a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardInput.h +++ b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardInput.h @@ -123,20 +123,20 @@ class KeyboardManager : public KeyboardInputController, public KeyboardEventHand deltas.to_state(static_cast(state)); } virtual void cancel_all_commands() override{ + report_keyboard_command_stopped(); WriteSpinLock lg(m_lock); if (m_controller == nullptr){ return; } m_controller->cancel_all_commands(); - report_keyboard_command_stopped(); } virtual void replace_on_next_command() override{ + report_keyboard_command_stopped(); WriteSpinLock lg(m_lock); if (m_controller == nullptr){ return; } m_controller->replace_on_next_command(); - report_keyboard_command_stopped(); } diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp index ac24631954..b03b72271b 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp @@ -52,6 +52,7 @@ class ProController::KeyboardManager final : } virtual void send_state(const ControllerState& state) override{ const ProControllerState& switch_state = static_cast(state); + report_keyboard_command_sent(switch_state); #if 0 m_controller.logger().log( "VirtualController: (" + button_to_string(switch_state.buttons) + @@ -78,7 +79,6 @@ class ProController::KeyboardManager final : switch_state.right_y ); - report_keyboard_command_sent(switch_state); } From c35db68ae680aa7e8e7ce3ffa3ff9b733ad78887 Mon Sep 17 00:00:00 2001 From: jw098 Date: Fri, 12 Sep 2025 18:32:31 -0700 Subject: [PATCH 07/34] add new program RecordKeyboardController --- SerialPrograms/CMakeLists.txt | 2 + .../NintendoSwitch_ProController.cpp | 19 +---- .../NintendoSwitch_ProController.h | 9 +-- .../DevPrograms/TestProgramSwitch.cpp | 2 +- .../NintendoSwitch/NintendoSwitch_Panels.cpp | 2 + ...intendoSwitch_RecordKeyboardController.cpp | 73 +++++++++++++++++++ .../NintendoSwitch_RecordKeyboardController.h | 49 +++++++++++++ 7 files changed, 132 insertions(+), 24 deletions(-) create mode 100644 SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp create mode 100644 SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h diff --git a/SerialPrograms/CMakeLists.txt b/SerialPrograms/CMakeLists.txt index e82b798643..c3fb86e5f9 100644 --- a/SerialPrograms/CMakeLists.txt +++ b/SerialPrograms/CMakeLists.txt @@ -1121,6 +1121,8 @@ file(GLOB MAIN_SOURCES Source/NintendoSwitch/Programs/NintendoSwitch_PreventSleep.h Source/NintendoSwitch/Programs/NintendoSwitch_PushJoySticks.cpp Source/NintendoSwitch/Programs/NintendoSwitch_PushJoySticks.h + Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp + Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h Source/NintendoSwitch/Programs/NintendoSwitch_SnapshotDumper.cpp Source/NintendoSwitch/Programs/NintendoSwitch_SnapshotDumper.h Source/NintendoSwitch/Programs/NintendoSwitch_SwitchViewer.cpp diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp index b03b72271b..2f4048c1bb 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp @@ -12,9 +12,9 @@ #include "NintendoSwitch_VirtualControllerState.h" #include "NintendoSwitch_ProController.h" -#include -using std::cout; -using std::endl; +// #include +// using std::cout; +// using std::endl; namespace PokemonAutomation{ @@ -92,7 +92,6 @@ ProController::ProController(Logger& logger) } ProController::~ProController(){ - m_keyboard_manager->remove_listener(*this); } void ProController::stop() noexcept{ m_keyboard_manager->stop(); @@ -109,18 +108,6 @@ void ProController::keyboard_release(const QKeyEvent& event){ m_keyboard_manager->on_key_release(event); } -void ProController::on_keyboard_command_sent(const ProControllerState& state) { - cout << "keyboard_command_sent" << endl; -} - -void ProController::on_keyboard_command_stopped() { - cout << "keyboard_command_stopped" << endl; -} - -void ProController::monitor_keyboard_events(){ - m_keyboard_manager->add_listener(*this); -} - diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h index 679c9b2660..f493e6fbc1 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h @@ -53,17 +53,13 @@ constexpr Button VALID_PRO_CONTROLLER_BUTTONS = // // This is the generic interface to a Switch pro controller. // -class ProController : public AbstractController, public KeyboardEventHandler::KeyboardListener{ +class ProController : public AbstractController{ public: using ContextType = ProControllerContext; ProController(Logger& logger); virtual ~ProController(); -private: - virtual void on_keyboard_command_sent(const ProControllerState& state) override; - virtual void on_keyboard_command_stopped() override; - public: static const char NAME[]; virtual const char* name() override{ @@ -221,7 +217,6 @@ class ProController : public AbstractController, public KeyboardEventHandler::Ke DpadPosition direction // Diagonals not allowed. ) = 0; - void monitor_keyboard_events(); public: // Keyboard Input @@ -231,7 +226,7 @@ class ProController : public AbstractController, public KeyboardEventHandler::Ke virtual void keyboard_release(const QKeyEvent& event) override; -private: +public: class KeyboardManager; Pimpl m_keyboard_manager; }; diff --git a/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp b/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp index 98ef5af416..520d7334c8 100644 --- a/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp +++ b/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp @@ -269,7 +269,7 @@ void TestProgram::program(MultiSwitchProgramEnvironment& env, CancellableScope& #if 1 - context.controller().monitor_keyboard_events(); + // context.controller().monitor_keyboard_events(); #endif diff --git a/SerialPrograms/Source/NintendoSwitch/NintendoSwitch_Panels.cpp b/SerialPrograms/Source/NintendoSwitch/NintendoSwitch_Panels.cpp index dba29f1f55..820609ba67 100644 --- a/SerialPrograms/Source/NintendoSwitch/NintendoSwitch_Panels.cpp +++ b/SerialPrograms/Source/NintendoSwitch/NintendoSwitch_Panels.cpp @@ -19,6 +19,7 @@ #include "Programs/NintendoSwitch_PreventSleep.h" #include "Programs/NintendoSwitch_FriendCodeAdder.h" #include "Programs/NintendoSwitch_FriendDelete.h" +#include "Programs/NintendoSwitch_RecordKeyboardController.h" #include "DevPrograms/BoxDraw.h" #include "Programs/NintendoSwitch_SnapshotDumper.h" @@ -61,6 +62,7 @@ std::vector PanelListFactory::make_panels() const{ ret.emplace_back(make_single_switch_program()); ret.emplace_back(make_single_switch_program()); ret.emplace_back(make_single_switch_program()); + ret.emplace_back(make_single_switch_program()); // ret.emplace_back("---- " + STRING_POKEMON + " Home ----"); diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp new file mode 100644 index 0000000000..2995b09633 --- /dev/null +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp @@ -0,0 +1,73 @@ +/* Record Keyboard Controller + * + * From: https://github.com/PokemonAutomation/ + * + */ + +// #include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" +// #include "NintendoSwitch/Commands/NintendoSwitch_Commands_Superscalar.h" +// #include "NintendoSwitch/NintendoSwitch_Settings.h" +#include "NintendoSwitch/Controllers/NintendoSwitch_ProController.h" +#include "NintendoSwitch_RecordKeyboardController.h" + +#include +using std::cout; +using std::endl; + +namespace PokemonAutomation{ +namespace NintendoSwitch{ + + +RecordKeyboardController_Descriptor::RecordKeyboardController_Descriptor() + : SingleSwitchProgramDescriptor( + "NintendoSwitch:RecordKeyboardController", + "Nintendo Switch", "Record Keyboard Controller", + "ComputerControl/blob/master/Wiki/Programs/NintendoSwitch/RecordKeyboardController.md", + "Record actions from the keyboard controller, then play it back.", + ProgramControllerClass::StandardController_NoRestrictions, + FeedbackType::NONE, + AllowCommandsWhenRunning::DISABLE_COMMANDS + ) +{} + + + +RecordKeyboardController::~RecordKeyboardController(){ + + // m_keyboard_manager->remove_listener(*this); +} + +RecordKeyboardController::RecordKeyboardController(){ +} + + + +void RecordKeyboardController::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ + + +} + +void RecordKeyboardController::monitor_keyboard_events(ProControllerContext& context){ + // ProController::KeyboardManager& keyboard_manager = *context.controller().m_keyboard_manager; + // keyboard_manager.add_listener(*this); + + + // context.controller().m_keyboard_manager ->m_keyboard_manager->add_listener(*this); + // keyboard_manager +} + + // m_keyboard_manager->remove_listener(*this); + + +// void RecordKeyboardController::on_keyboard_command_sent(const NintendoSwitch::ProControllerState& state){ +// cout << "keyboard_command_sent" << endl; +// } +// void RecordKeyboardController::on_keyboard_command_stopped(){ +// cout << "keyboard_command_stopped" << endl; +// } + + + +} +} + diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h new file mode 100644 index 0000000000..dca7fd9260 --- /dev/null +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h @@ -0,0 +1,49 @@ +/* Record Keyboard Controller + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_NintendoSwitch_RecordKeyboardController_H +#define PokemonAutomation_NintendoSwitch_RecordKeyboardController_H + +#include "Controllers/KeyboardInput/KeyboardEventHandler.h" +#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ + +class ProControllerState; + +class RecordKeyboardController_Descriptor : public SingleSwitchProgramDescriptor{ +public: + RecordKeyboardController_Descriptor(); +}; + + + +class RecordKeyboardController : public SingleSwitchProgramInstance{ //, public KeyboardEventHandler::KeyboardListener +public: + ~RecordKeyboardController(); + RecordKeyboardController(); + + + virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override; + +private: + // virtual void on_keyboard_command_sent(const NintendoSwitch::ProControllerState& state){} override; + // virtual void on_keyboard_command_stopped(){} override; + + void monitor_keyboard_events(ProControllerContext& context); + +}; + + + + +} +} +#endif + + + From 6502b3f9ff6ead353314e05209459abce585b3e9 Mon Sep 17 00:00:00 2001 From: jw098 Date: Fri, 12 Sep 2025 18:58:53 -0700 Subject: [PATCH 08/34] KeyboardEventHandler: use ControllerState instead of ProControllerState --- .../Controllers/KeyboardInput/KeyboardEventHandler.cpp | 3 ++- .../Controllers/KeyboardInput/KeyboardEventHandler.h | 8 +++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.cpp b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.cpp index e0757853aa..d88d29499f 100644 --- a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.cpp +++ b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.cpp @@ -3,6 +3,7 @@ */ #include "Common/Cpp/ListenerSet.h" #include "Common/Cpp/Containers/Pimpl.tpp" +#include "Controllers/KeyboardInput/KeyboardInput.h" #include "KeyboardEventHandler.h" namespace PokemonAutomation{ @@ -30,7 +31,7 @@ void KeyboardEventHandler::remove_listener(KeyboardListener& listener){ data.m_listeners.remove(listener); } -void KeyboardEventHandler::report_keyboard_command_sent(const NintendoSwitch::ProControllerState& state){ +void KeyboardEventHandler::report_keyboard_command_sent(const ControllerState& state){ auto scope = m_lifetime_sanitizer.check_scope(); Data& data = *m_data; data.m_listeners.run_method_unique(&KeyboardListener::on_keyboard_command_sent, state); diff --git a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h index 05d9c5a090..aa76d6af29 100644 --- a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h +++ b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h @@ -14,9 +14,7 @@ namespace PokemonAutomation{ -namespace NintendoSwitch{ - class ProControllerState; // forward declaration to avoid circular dependency -} +class ControllerState; // forward declaration to avoid circular dependency class KeyboardEventHandler{ public: @@ -24,7 +22,7 @@ class KeyboardEventHandler{ virtual ~KeyboardEventHandler(); struct KeyboardListener{ - virtual void on_keyboard_command_sent(const NintendoSwitch::ProControllerState& state){} + virtual void on_keyboard_command_sent(const ControllerState& state){} virtual void on_keyboard_command_stopped(){} }; void add_listener(KeyboardListener& listener); @@ -33,7 +31,7 @@ class KeyboardEventHandler{ protected: // Report that the keyboard state has changed. This will be pushed to // all listeners. - void report_keyboard_command_sent(const NintendoSwitch::ProControllerState& state); + void report_keyboard_command_sent(const ControllerState& state); void report_keyboard_command_stopped(); From 717aea61ba004b3d26fc932feace24d938ac8c31 Mon Sep 17 00:00:00 2001 From: jw098 Date: Fri, 12 Sep 2025 19:08:17 -0700 Subject: [PATCH 09/34] add timestamp to Keyboard event callbacks --- .../Controllers/KeyboardInput/KeyboardEventHandler.cpp | 8 ++++---- .../Controllers/KeyboardInput/KeyboardEventHandler.h | 8 ++++---- .../Source/Controllers/KeyboardInput/KeyboardInput.h | 6 ++++-- .../NintendoSwitch/Controllers/NintendoSwitch_Joycon.cpp | 2 ++ .../Controllers/NintendoSwitch_ProController.cpp | 4 +++- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.cpp b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.cpp index d88d29499f..5b91e9b325 100644 --- a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.cpp +++ b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.cpp @@ -31,16 +31,16 @@ void KeyboardEventHandler::remove_listener(KeyboardListener& listener){ data.m_listeners.remove(listener); } -void KeyboardEventHandler::report_keyboard_command_sent(const ControllerState& state){ +void KeyboardEventHandler::report_keyboard_command_sent(WallClock time_stamp, const ControllerState& state){ auto scope = m_lifetime_sanitizer.check_scope(); Data& data = *m_data; - data.m_listeners.run_method_unique(&KeyboardListener::on_keyboard_command_sent, state); + data.m_listeners.run_method_unique(&KeyboardListener::on_keyboard_command_sent, time_stamp, state); } -void KeyboardEventHandler::report_keyboard_command_stopped(){ +void KeyboardEventHandler::report_keyboard_command_stopped(WallClock time_stamp){ auto scope = m_lifetime_sanitizer.check_scope(); Data& data = *m_data; - data.m_listeners.run_method_unique(&KeyboardListener::on_keyboard_command_stopped); + data.m_listeners.run_method_unique(&KeyboardListener::on_keyboard_command_stopped, time_stamp); } diff --git a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h index aa76d6af29..bfac5ec015 100644 --- a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h +++ b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h @@ -22,8 +22,8 @@ class KeyboardEventHandler{ virtual ~KeyboardEventHandler(); struct KeyboardListener{ - virtual void on_keyboard_command_sent(const ControllerState& state){} - virtual void on_keyboard_command_stopped(){} + virtual void on_keyboard_command_sent(WallClock time_stamp, const ControllerState& state){} + virtual void on_keyboard_command_stopped(WallClock time_stamp){} }; void add_listener(KeyboardListener& listener); void remove_listener(KeyboardListener& listener); @@ -31,9 +31,9 @@ class KeyboardEventHandler{ protected: // Report that the keyboard state has changed. This will be pushed to // all listeners. - void report_keyboard_command_sent(const ControllerState& state); + void report_keyboard_command_sent(WallClock time_stamp, const ControllerState& state); - void report_keyboard_command_stopped(); + void report_keyboard_command_stopped(WallClock time_stamp); private: struct Data; diff --git a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardInput.h b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardInput.h index c5d7a7e002..a36fe75ff8 100644 --- a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardInput.h +++ b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardInput.h @@ -123,20 +123,22 @@ class KeyboardManager : public KeyboardInputController, public KeyboardEventHand deltas.to_state(static_cast(state)); } virtual void cancel_all_commands() override{ - report_keyboard_command_stopped(); + WallClock time_stamp = current_time(); WriteSpinLock lg(m_lock); if (m_controller == nullptr){ return; } m_controller->cancel_all_commands(); + report_keyboard_command_stopped(time_stamp); } virtual void replace_on_next_command() override{ - report_keyboard_command_stopped(); + WallClock time_stamp = current_time(); WriteSpinLock lg(m_lock); if (m_controller == nullptr){ return; } m_controller->replace_on_next_command(); + // report_keyboard_command_stopped(time_stamp); } diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.cpp b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.cpp index 9b3fb427bd..c9bc058ec7 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.cpp @@ -57,6 +57,7 @@ class JoyconController::KeyboardManager final : stop(); } virtual void send_state(const ControllerState& state) override{ + WallClock time_stamp = current_time(); const JoyconState& switch_state = static_cast(state); #if 0 m_controller->logger().log( @@ -78,6 +79,7 @@ class JoyconController::KeyboardManager final : switch_state.joystick_y, ticksize == Milliseconds::zero() ? 2000ms : ticksize * 255 ); + report_keyboard_command_sent(time_stamp, switch_state); } }; diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp index 2f4048c1bb..b59176c47d 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp @@ -51,8 +51,9 @@ class ProController::KeyboardManager final : stop(); } virtual void send_state(const ControllerState& state) override{ + WallClock time_stamp = current_time(); const ProControllerState& switch_state = static_cast(state); - report_keyboard_command_sent(switch_state); + #if 0 m_controller.logger().log( "VirtualController: (" + button_to_string(switch_state.buttons) + @@ -79,6 +80,7 @@ class ProController::KeyboardManager final : switch_state.right_y ); + report_keyboard_command_sent(time_stamp, switch_state); } From 0ed91cfc52fc932b819f20887598fed1ceabd186 Mon Sep 17 00:00:00 2001 From: jw098 Date: Fri, 12 Sep 2025 19:19:38 -0700 Subject: [PATCH 10/34] RecordKeyboardController inherits KeyboardEventHandler::KeyboardListener --- .../Controllers/KeyboardInput/KeyboardEventHandler.h | 4 ++-- .../NintendoSwitch_RecordKeyboardController.cpp | 12 ++++++------ .../NintendoSwitch_RecordKeyboardController.h | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h index bfac5ec015..144083c815 100644 --- a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h +++ b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardEventHandler.h @@ -22,8 +22,8 @@ class KeyboardEventHandler{ virtual ~KeyboardEventHandler(); struct KeyboardListener{ - virtual void on_keyboard_command_sent(WallClock time_stamp, const ControllerState& state){} - virtual void on_keyboard_command_stopped(WallClock time_stamp){} + virtual void on_keyboard_command_sent(WallClock time_stamp, const ControllerState& state) = 0; + virtual void on_keyboard_command_stopped(WallClock time_stamp) = 0; }; void add_listener(KeyboardListener& listener); void remove_listener(KeyboardListener& listener); diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp index 2995b09633..3ea5ff2d31 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp @@ -59,12 +59,12 @@ void RecordKeyboardController::monitor_keyboard_events(ProControllerContext& con // m_keyboard_manager->remove_listener(*this); -// void RecordKeyboardController::on_keyboard_command_sent(const NintendoSwitch::ProControllerState& state){ -// cout << "keyboard_command_sent" << endl; -// } -// void RecordKeyboardController::on_keyboard_command_stopped(){ -// cout << "keyboard_command_stopped" << endl; -// } +void RecordKeyboardController::on_keyboard_command_sent(WallClock time_stamp, const ControllerState& state){ + cout << "keyboard_command_sent" << endl; +} +void RecordKeyboardController::on_keyboard_command_stopped(WallClock time_stamp){ + cout << "keyboard_command_stopped" << endl; +} diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h index dca7fd9260..c5b0bb3a71 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h @@ -7,7 +7,7 @@ #ifndef PokemonAutomation_NintendoSwitch_RecordKeyboardController_H #define PokemonAutomation_NintendoSwitch_RecordKeyboardController_H -#include "Controllers/KeyboardInput/KeyboardEventHandler.h" +#include "Controllers/KeyboardInput/KeyboardInput.h" #include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" namespace PokemonAutomation{ @@ -22,7 +22,7 @@ class RecordKeyboardController_Descriptor : public SingleSwitchProgramDescriptor -class RecordKeyboardController : public SingleSwitchProgramInstance{ //, public KeyboardEventHandler::KeyboardListener +class RecordKeyboardController : public SingleSwitchProgramInstance, public KeyboardEventHandler::KeyboardListener{ public: ~RecordKeyboardController(); RecordKeyboardController(); @@ -31,8 +31,8 @@ class RecordKeyboardController : public SingleSwitchProgramInstance{ //, public virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override; private: - // virtual void on_keyboard_command_sent(const NintendoSwitch::ProControllerState& state){} override; - // virtual void on_keyboard_command_stopped(){} override; + virtual void on_keyboard_command_sent(WallClock time_stamp, const ControllerState& state) override; + virtual void on_keyboard_command_stopped(WallClock time_stamp) override; void monitor_keyboard_events(ProControllerContext& context); From 5cf9bfbe01c04d72d5353e1ad5c668a03acbfc4f Mon Sep 17 00:00:00 2001 From: jw098 Date: Fri, 12 Sep 2025 21:50:31 -0700 Subject: [PATCH 11/34] added AbstractController::monitor_keyboard_events(), which allows us to add KeyboardListeners. --- SerialPrograms/Source/Controllers/Controller.h | 4 ++++ .../Controllers/NintendoSwitch_Joycon.cpp | 4 +++- .../Controllers/NintendoSwitch_Joycon.h | 2 ++ .../NintendoSwitch_ProController.cpp | 4 ++++ .../Controllers/NintendoSwitch_ProController.h | 3 ++- ...NintendoSwitch_RecordKeyboardController.cpp | 18 ++++++------------ .../NintendoSwitch_RecordKeyboardController.h | 4 +--- 7 files changed, 22 insertions(+), 17 deletions(-) diff --git a/SerialPrograms/Source/Controllers/Controller.h b/SerialPrograms/Source/Controllers/Controller.h index b411423ba9..190b1845ce 100644 --- a/SerialPrograms/Source/Controllers/Controller.h +++ b/SerialPrograms/Source/Controllers/Controller.h @@ -10,6 +10,7 @@ #include "Common/Compiler.h" #include "Common/Cpp/AbstractLogger.h" #include "Common/Cpp/Time.h" +#include "Controllers/KeyboardInput/KeyboardEventHandler.h" #include "Common/Cpp/CancellableScope.h" class QKeyEvent; @@ -203,6 +204,8 @@ class AbstractController{ virtual void keyboard_release_all(){} virtual void keyboard_press(const QKeyEvent& event){} virtual void keyboard_release(const QKeyEvent& event){} + + virtual void monitor_keyboard_events(KeyboardEventHandler::KeyboardListener& keyboard_listener) = 0; }; @@ -294,6 +297,7 @@ class ControllerContext final : public CancellableScope{ }; +using AbstractControllerContext = ControllerContext; using AbstractControllerContext = ControllerContext; diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.cpp b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.cpp index c9bc058ec7..0572342cdc 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.cpp @@ -108,7 +108,9 @@ void JoyconController::keyboard_release(const QKeyEvent& event){ m_keyboard_manager->on_key_release(event); } - +void JoyconController::monitor_keyboard_events(KeyboardEventHandler::KeyboardListener& keyboard_listener){ + m_keyboard_manager->add_listener(keyboard_listener); +} diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.h b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.h index c69b22c636..735d4c1642 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.h +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.h @@ -171,6 +171,8 @@ class JoyconController : public AbstractController{ virtual void keyboard_press(const QKeyEvent& event) override; virtual void keyboard_release(const QKeyEvent& event) override; + virtual void monitor_keyboard_events(KeyboardEventHandler::KeyboardListener& keyboard_listener) override; + private: class KeyboardManager; diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp index b59176c47d..77bca3d485 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp @@ -110,6 +110,10 @@ void ProController::keyboard_release(const QKeyEvent& event){ m_keyboard_manager->on_key_release(event); } +void ProController::monitor_keyboard_events(KeyboardEventHandler::KeyboardListener& keyboard_listener){ + m_keyboard_manager->add_listener(keyboard_listener); +} + diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h index f493e6fbc1..2505c6b5c3 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h @@ -225,8 +225,9 @@ class ProController : public AbstractController{ virtual void keyboard_press(const QKeyEvent& event) override; virtual void keyboard_release(const QKeyEvent& event) override; + virtual void monitor_keyboard_events(KeyboardEventHandler::KeyboardListener& keyboard_listener) override; -public: +private: class KeyboardManager; Pimpl m_keyboard_manager; }; diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp index 3ea5ff2d31..b2b102a906 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp @@ -42,22 +42,16 @@ RecordKeyboardController::RecordKeyboardController(){ -void RecordKeyboardController::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ +void RecordKeyboardController::program(SingleSwitchProgramEnvironment& env, CancellableScope& scope){ + AbstractControllerContext context(scope, env.console.controller()); + // ProControllerContext context(scope, env.console.controller()); + context.controller().monitor_keyboard_events(*this); + // context->start_recording(); + // env.console.controller() } -void RecordKeyboardController::monitor_keyboard_events(ProControllerContext& context){ - // ProController::KeyboardManager& keyboard_manager = *context.controller().m_keyboard_manager; - // keyboard_manager.add_listener(*this); - - - // context.controller().m_keyboard_manager ->m_keyboard_manager->add_listener(*this); - // keyboard_manager -} - - // m_keyboard_manager->remove_listener(*this); - void RecordKeyboardController::on_keyboard_command_sent(WallClock time_stamp, const ControllerState& state){ cout << "keyboard_command_sent" << endl; diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h index c5b0bb3a71..b5db99e42d 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h @@ -28,14 +28,12 @@ class RecordKeyboardController : public SingleSwitchProgramInstance, public Keyb RecordKeyboardController(); - virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override; + virtual void program(SingleSwitchProgramEnvironment& env, CancellableScope& scope) override; private: virtual void on_keyboard_command_sent(WallClock time_stamp, const ControllerState& state) override; virtual void on_keyboard_command_stopped(WallClock time_stamp) override; - void monitor_keyboard_events(ProControllerContext& context); - }; From 1da91fc2f989526b099f061b8a3d804ac0d12ed4 Mon Sep 17 00:00:00 2001 From: jw098 Date: Sat, 13 Sep 2025 20:58:16 -0700 Subject: [PATCH 12/34] add ControllerState::serialize_state(). Save the serialized state along with the timestamp, on_keyboard_command_sent/stopped. --- .../Controllers/KeyboardInput/KeyboardInput.h | 3 ++ .../NintendoSwitch_VirtualControllerState.cpp | 22 +++++++++++++ .../NintendoSwitch_VirtualControllerState.h | 4 +++ ...intendoSwitch_RecordKeyboardController.cpp | 15 +++++++++ .../NintendoSwitch_RecordKeyboardController.h | 31 +++++++++++++++++++ 5 files changed, 75 insertions(+) diff --git a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardInput.h b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardInput.h index a36fe75ff8..e8900c9285 100644 --- a/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardInput.h +++ b/SerialPrograms/Source/Controllers/KeyboardInput/KeyboardInput.h @@ -11,6 +11,7 @@ #include #include #include +#include "Common/Cpp/Json/JsonObject.h" #include "Common/Cpp/Concurrency/SpinLock.h" #include "Controllers/Controller.h" #include "Controllers/KeyboardInput/GlobalQtKeyMap.h" @@ -37,6 +38,8 @@ class ControllerState{ virtual bool operator!=(const ControllerState& x) const{ return !(*this == x); } virtual bool is_neutral() const = 0; + + virtual JsonObject serialize_state() const = 0; }; diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_VirtualControllerState.cpp b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_VirtualControllerState.cpp index 6a82c41331..acc2a175d5 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_VirtualControllerState.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_VirtualControllerState.cpp @@ -63,6 +63,19 @@ bool ProControllerState::is_neutral() const{ && right_y == 128; } +JsonObject ProControllerState::serialize_state() const { + JsonObject obj; + obj["is_neutral"] = is_neutral(); + obj["buttons"] = button_to_string(buttons); + obj["dpad"] = dpad_to_string(dpad); + obj["left_x"] = std::to_string(left_x); + obj["left_y"] = std::to_string(left_y); + obj["right_x"] = std::to_string(right_x); + obj["right_y"] = std::to_string(right_y); + + return obj; +} + void ProControllerDeltas::operator+=(const ProControllerDeltas& x){ buttons |= x.buttons; @@ -169,6 +182,15 @@ bool JoyconState::is_neutral() const{ && joystick_y == 128; } +JsonObject JoyconState::serialize_state() const { + JsonObject obj; + obj["is_neutral"] = is_neutral(); + obj["buttons"] = button_to_string(buttons); + obj["joystick_x"] = std::to_string(joystick_x); + obj["joystick_y"] = std::to_string(joystick_y); + + return obj; +} void JoyconDeltas::operator+=(const JoyconDeltas& x){ buttons |= x.buttons; diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_VirtualControllerState.h b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_VirtualControllerState.h index ce09e9d59b..4c71de6268 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_VirtualControllerState.h +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_VirtualControllerState.h @@ -20,6 +20,8 @@ class ProControllerState : public ControllerState{ virtual bool operator==(const ControllerState& x) const override; virtual bool is_neutral() const override; + virtual JsonObject serialize_state() const override; + public: Button buttons = BUTTON_NONE; DpadPosition dpad = DPAD_NONE; @@ -52,6 +54,8 @@ class JoyconState : public ControllerState{ virtual bool operator==(const ControllerState& x) const override; virtual bool is_neutral() const override; + virtual JsonObject serialize_state() const override; + public: Button buttons = BUTTON_NONE; uint8_t joystick_x = 128; diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp index b2b102a906..eefe83a772 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp @@ -55,9 +55,24 @@ void RecordKeyboardController::program(SingleSwitchProgramEnvironment& env, Canc void RecordKeyboardController::on_keyboard_command_sent(WallClock time_stamp, const ControllerState& state){ cout << "keyboard_command_sent" << endl; + JsonObject serialized_state = state.serialize_state(); + + ControllerStateSnapshot state_snapshot = { + time_stamp, + std::move(serialized_state) + }; + m_controller_history.emplace_back(std::move(state_snapshot)); } void RecordKeyboardController::on_keyboard_command_stopped(WallClock time_stamp){ cout << "keyboard_command_stopped" << endl; + JsonObject obj; + obj["is_neutral"] = true; + + ControllerStateSnapshot state_snapshot = { + time_stamp, + std::move(obj) + }; + m_controller_history.emplace_back(std::move(state_snapshot)); } diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h index b5db99e42d..257c5bc109 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h @@ -7,6 +7,7 @@ #ifndef PokemonAutomation_NintendoSwitch_RecordKeyboardController_H #define PokemonAutomation_NintendoSwitch_RecordKeyboardController_H +#include "Common/Cpp/Json/JsonObject.h" #include "Controllers/KeyboardInput/KeyboardInput.h" #include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" @@ -34,6 +35,36 @@ class RecordKeyboardController : public SingleSwitchProgramInstance, public Keyb virtual void on_keyboard_command_sent(WallClock time_stamp, const ControllerState& state) override; virtual void on_keyboard_command_stopped(WallClock time_stamp) override; + + // Examples for JsonObject controller_state: + // ProControllerState: + // { + // “is_neutral”: false + // "buttons": "L R", + // "dpad": "none", + // "left_x": 100, + // "left_y": 200, + // "right_x": 128, + // "right_y": 128, + // } + // JoyconState + // { + // “is_neutral”: false + // "buttons": "L R", + // "joystick_x": 100, + // "joystick_x": 200, + // } + // Neutral controller: we know the controller is neutral, so no need for all the other button info + // { + // “is_neutral”: true + // } + struct ControllerStateSnapshot { + WallClock time_stamp; + JsonObject controller_state; + }; + + std::vector m_controller_history; + }; From 4be7d675f1489aed37f69f598670a4a6498ae904 Mon Sep 17 00:00:00 2001 From: jw098 Date: Sat, 13 Sep 2025 21:14:44 -0700 Subject: [PATCH 13/34] rename AbstractController::monitor_keyboard_events() to add_keyboard_listener(). added remove_keyboard_listener() --- SerialPrograms/Source/Controllers/Controller.h | 3 ++- .../Controllers/NintendoSwitch_Joycon.cpp | 6 +++++- .../Controllers/NintendoSwitch_Joycon.h | 3 ++- .../Controllers/NintendoSwitch_ProController.cpp | 6 +++++- .../Controllers/NintendoSwitch_ProController.h | 3 ++- .../NintendoSwitch_RecordKeyboardController.cpp | 16 +++++++++++++--- 6 files changed, 29 insertions(+), 8 deletions(-) diff --git a/SerialPrograms/Source/Controllers/Controller.h b/SerialPrograms/Source/Controllers/Controller.h index 190b1845ce..3ab136eb2c 100644 --- a/SerialPrograms/Source/Controllers/Controller.h +++ b/SerialPrograms/Source/Controllers/Controller.h @@ -205,7 +205,8 @@ class AbstractController{ virtual void keyboard_press(const QKeyEvent& event){} virtual void keyboard_release(const QKeyEvent& event){} - virtual void monitor_keyboard_events(KeyboardEventHandler::KeyboardListener& keyboard_listener) = 0; + virtual void add_keyboard_listener(KeyboardEventHandler::KeyboardListener& keyboard_listener) = 0; + virtual void remove_keyboard_listener(KeyboardEventHandler::KeyboardListener& keyboard_listener) = 0; }; diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.cpp b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.cpp index 0572342cdc..3e2685b9c4 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.cpp @@ -108,10 +108,14 @@ void JoyconController::keyboard_release(const QKeyEvent& event){ m_keyboard_manager->on_key_release(event); } -void JoyconController::monitor_keyboard_events(KeyboardEventHandler::KeyboardListener& keyboard_listener){ +void JoyconController::add_keyboard_listener(KeyboardEventHandler::KeyboardListener& keyboard_listener){ m_keyboard_manager->add_listener(keyboard_listener); } +void JoyconController::remove_keyboard_listener(KeyboardEventHandler::KeyboardListener& keyboard_listener){ + m_keyboard_manager->remove_listener(keyboard_listener); +} + diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.h b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.h index 735d4c1642..91e77b712b 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.h +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.h @@ -171,7 +171,8 @@ class JoyconController : public AbstractController{ virtual void keyboard_press(const QKeyEvent& event) override; virtual void keyboard_release(const QKeyEvent& event) override; - virtual void monitor_keyboard_events(KeyboardEventHandler::KeyboardListener& keyboard_listener) override; + virtual void add_keyboard_listener(KeyboardEventHandler::KeyboardListener& keyboard_listener) override; + virtual void remove_keyboard_listener(KeyboardEventHandler::KeyboardListener& keyboard_listener) override; private: diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp index 77bca3d485..953930a5a4 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.cpp @@ -110,10 +110,14 @@ void ProController::keyboard_release(const QKeyEvent& event){ m_keyboard_manager->on_key_release(event); } -void ProController::monitor_keyboard_events(KeyboardEventHandler::KeyboardListener& keyboard_listener){ +void ProController::add_keyboard_listener(KeyboardEventHandler::KeyboardListener& keyboard_listener){ m_keyboard_manager->add_listener(keyboard_listener); } +void ProController::remove_keyboard_listener(KeyboardEventHandler::KeyboardListener& keyboard_listener){ + m_keyboard_manager->remove_listener(keyboard_listener); +} + diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h index 2505c6b5c3..9a749057da 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h @@ -225,7 +225,8 @@ class ProController : public AbstractController{ virtual void keyboard_press(const QKeyEvent& event) override; virtual void keyboard_release(const QKeyEvent& event) override; - virtual void monitor_keyboard_events(KeyboardEventHandler::KeyboardListener& keyboard_listener) override; + virtual void add_keyboard_listener(KeyboardEventHandler::KeyboardListener& keyboard_listener) override; + virtual void remove_keyboard_listener(KeyboardEventHandler::KeyboardListener& keyboard_listener) override; private: class KeyboardManager; diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp index eefe83a772..0cc0e3b334 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp @@ -45,9 +45,19 @@ RecordKeyboardController::RecordKeyboardController(){ void RecordKeyboardController::program(SingleSwitchProgramEnvironment& env, CancellableScope& scope){ AbstractControllerContext context(scope, env.console.controller()); // ProControllerContext context(scope, env.console.controller()); - context.controller().monitor_keyboard_events(*this); - // context->start_recording(); - // env.console.controller() + context.controller().add_keyboard_listener(*this); + + + try{ + context.wait_until_cancel(); + }catch (ProgramCancelledException&){ + + // JsonObject json = context->get_keyboard_recording(); + // json.save("recording.json"); + context.controller().remove_keyboard_listener(*this); + throw; + } + } From d17908d7ec276a9bcae3ffad906c8434f2d80207 Mon Sep 17 00:00:00 2001 From: jw098 Date: Sun, 14 Sep 2025 23:09:20 -0700 Subject: [PATCH 14/34] convert m_controller_history to json --- Common/Cpp/Json/JsonObject.h | 7 +++ ...intendoSwitch_RecordKeyboardController.cpp | 52 ++++++++++++++++--- .../NintendoSwitch_RecordKeyboardController.h | 10 ++-- 3 files changed, 59 insertions(+), 10 deletions(-) diff --git a/Common/Cpp/Json/JsonObject.h b/Common/Cpp/Json/JsonObject.h index 4fe2765c65..d5356cfc50 100644 --- a/Common/Cpp/Json/JsonObject.h +++ b/Common/Cpp/Json/JsonObject.h @@ -18,6 +18,13 @@ class JsonObject{ JsonObject() = default; JsonObject(JsonObject&& x) = default; JsonObject& operator=(JsonObject&& x) = default; + + bool operator==(const JsonObject& x){ // TODO: implement == properly. For JsonValue as well. + return dump() == x.dump(); + } + bool operator!=(const JsonObject& x){ + return dump() != x.dump(); + } private: // Private to avoid accidental copying. JsonObject(const JsonObject& x); diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp index 0cc0e3b334..53d2f93e25 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp @@ -4,9 +4,8 @@ * */ -// #include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" -// #include "NintendoSwitch/Commands/NintendoSwitch_Commands_Superscalar.h" -// #include "NintendoSwitch/NintendoSwitch_Settings.h" + +#include "Common/Cpp/Json/JsonArray.h" #include "NintendoSwitch/Controllers/NintendoSwitch_ProController.h" #include "NintendoSwitch_RecordKeyboardController.h" @@ -26,7 +25,7 @@ RecordKeyboardController_Descriptor::RecordKeyboardController_Descriptor() "Record actions from the keyboard controller, then play it back.", ProgramControllerClass::StandardController_NoRestrictions, FeedbackType::NONE, - AllowCommandsWhenRunning::DISABLE_COMMANDS + AllowCommandsWhenRunning::ENABLE_COMMANDS ) {} @@ -46,26 +45,65 @@ void RecordKeyboardController::program(SingleSwitchProgramEnvironment& env, Canc AbstractControllerContext context(scope, env.console.controller()); // ProControllerContext context(scope, env.console.controller()); context.controller().add_keyboard_listener(*this); - + // CONTROLLER_TYPE_STRINGS.get_string(connection.current_controller()); try{ context.wait_until_cancel(); }catch (ProgramCancelledException&){ - // JsonObject json = context->get_keyboard_recording(); - // json.save("recording.json"); + JsonValue json = controller_history_to_json(env.console.logger()); + json.dump("recording.json"); + m_controller_history.clear(); context.controller().remove_keyboard_listener(*this); throw; } +} + +JsonValue RecordKeyboardController::controller_history_to_json(Logger& logger){ + if (m_controller_history.size() < 2){ + throw InternalProgramError(&logger, PA_CURRENT_FUNCTION, "RecordKeyboardController:: m_controller_history should have at least two entries, start and stop."); + } + + JsonArray json; + ControllerStateSnapshot* prev_snapshot = &m_controller_history[0]; // the previous non-duplicate snapshot + + for (size_t i = 1; i < m_controller_history.size(); i++){ // start at index i = 1, since prev_snapshot starts at i=0 and we continue when current == previous. + ControllerStateSnapshot& snapshot = m_controller_history[i]; + WallClock time_stamp = snapshot.time_stamp; + JsonObject& controller_state = snapshot.controller_state; + + WallClock prev_time_stamp = prev_snapshot->time_stamp; + JsonObject& prev_controller_state = prev_snapshot->controller_state; + + if (controller_state == prev_controller_state){ + continue; + } + + // cout << time_stamp << endl; + // cout << prev_time_stamp << endl; + auto elapsed_time = std::chrono::duration_cast(time_stamp - prev_time_stamp); // might need to figure out how rounding works. + int64_t duration = elapsed_time.count(); + // cout << std::to_string(duration) << endl; + // cout << prev_controller_state.dump() << endl; + JsonObject recording = prev_controller_state.clone(); + recording["duration_in_ms"] = duration; + json.push_back(std::move(recording)); + prev_snapshot = &snapshot; // update the previous non-duplicate snapshot + } + + + return json; + } void RecordKeyboardController::on_keyboard_command_sent(WallClock time_stamp, const ControllerState& state){ cout << "keyboard_command_sent" << endl; JsonObject serialized_state = state.serialize_state(); + cout << serialized_state.dump(0) << endl; ControllerStateSnapshot state_snapshot = { time_stamp, diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h index 257c5bc109..88820d767c 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h @@ -35,11 +35,15 @@ class RecordKeyboardController : public SingleSwitchProgramInstance, public Keyb virtual void on_keyboard_command_sent(WallClock time_stamp, const ControllerState& state) override; virtual void on_keyboard_command_stopped(WallClock time_stamp) override; + // convert m_controller_history to json + // remove adjacent duplicate controller states. + JsonValue controller_history_to_json(Logger& logger); + // Examples for JsonObject controller_state: // ProControllerState: // { - // “is_neutral”: false + // "is_neutral": false // "buttons": "L R", // "dpad": "none", // "left_x": 100, @@ -49,14 +53,14 @@ class RecordKeyboardController : public SingleSwitchProgramInstance, public Keyb // } // JoyconState // { - // “is_neutral”: false + // "is_neutral": false // "buttons": "L R", // "joystick_x": 100, // "joystick_x": 200, // } // Neutral controller: we know the controller is neutral, so no need for all the other button info // { - // “is_neutral”: true + // "is_neutral": true // } struct ControllerStateSnapshot { WallClock time_stamp; From 0c41a029e997c4cfa0fd687ada08d0950d2bc98d Mon Sep 17 00:00:00 2001 From: jw098 Date: Mon, 15 Sep 2025 18:07:28 -0700 Subject: [PATCH 15/34] add enum class ControllerCategory --- SerialPrograms/Source/Controllers/Controller.h | 2 ++ .../Source/Controllers/ControllerTypeStrings.cpp | 7 +++++++ SerialPrograms/Source/Controllers/ControllerTypeStrings.h | 1 + SerialPrograms/Source/Controllers/ControllerTypes.h | 7 +++++++ .../NintendoSwitch/Controllers/NintendoSwitch_Joycon.h | 8 ++++++++ .../Controllers/NintendoSwitch_ProController.h | 5 +++++ 6 files changed, 30 insertions(+) diff --git a/SerialPrograms/Source/Controllers/Controller.h b/SerialPrograms/Source/Controllers/Controller.h index 3ab136eb2c..6e86cad18e 100644 --- a/SerialPrograms/Source/Controllers/Controller.h +++ b/SerialPrograms/Source/Controllers/Controller.h @@ -20,6 +20,7 @@ namespace PokemonAutomation{ class RecursiveThrottler; enum class ControllerType; enum class ControllerPerformanceClass; +enum class ControllerCategory; @@ -65,6 +66,7 @@ class AbstractController{ virtual const char* name() = 0; virtual ControllerType controller_type() const = 0; + virtual ControllerCategory controller_category() const = 0; virtual ControllerPerformanceClass performance_class() const = 0; // If the controller is polled at a fixed interval, this is that interval. diff --git a/SerialPrograms/Source/Controllers/ControllerTypeStrings.cpp b/SerialPrograms/Source/Controllers/ControllerTypeStrings.cpp index 32dabd8766..0042d0c1b4 100644 --- a/SerialPrograms/Source/Controllers/ControllerTypeStrings.cpp +++ b/SerialPrograms/Source/Controllers/ControllerTypeStrings.cpp @@ -32,6 +32,13 @@ const EnumStringMap CONTROLLER_TYPE_STRINGS{ {ControllerType::NintendoSwitch2_RightJoycon, "NS2: Right Joycon"}, }; +const EnumStringMap CONTROLLER_CATEGORY_STRINGS{ + {ControllerCategory::NONE, "none"}, + {ControllerCategory::LEFT_JOYCON, "left-joycon"}, + {ControllerCategory::RIGHT_JOYCON, "right-joycon"}, + {ControllerCategory::PRO_CONTROLLER, "pro-controller"}, +}; + diff --git a/SerialPrograms/Source/Controllers/ControllerTypeStrings.h b/SerialPrograms/Source/Controllers/ControllerTypeStrings.h index 49ea1b08b9..31d73f31a9 100644 --- a/SerialPrograms/Source/Controllers/ControllerTypeStrings.h +++ b/SerialPrograms/Source/Controllers/ControllerTypeStrings.h @@ -16,6 +16,7 @@ namespace PokemonAutomation{ extern const EnumStringMap CONTROLLER_INTERFACE_STRINGS; extern const EnumStringMap CONTROLLER_TYPE_STRINGS; +extern const EnumStringMap CONTROLLER_CATEGORY_STRINGS; diff --git a/SerialPrograms/Source/Controllers/ControllerTypes.h b/SerialPrograms/Source/Controllers/ControllerTypes.h index b1beab859e..6261b91321 100644 --- a/SerialPrograms/Source/Controllers/ControllerTypes.h +++ b/SerialPrograms/Source/Controllers/ControllerTypes.h @@ -44,6 +44,13 @@ enum class ControllerPerformanceClass{ SysbotBase, }; +enum class ControllerCategory{ + NONE, + LEFT_JOYCON, + RIGHT_JOYCON, + PRO_CONTROLLER, +}; + diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.h b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.h index 91e77b712b..a482e2e7b3 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.h +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_Joycon.h @@ -9,6 +9,8 @@ #include "Common/Cpp/Containers/Pimpl.h" #include "NintendoSwitch_ControllerButtons.h" +#include "NintendoSwitch_ControllerState.h" +#include "Controllers/ControllerTypes.h" #include "Controllers/Controller.h" namespace PokemonAutomation{ @@ -190,6 +192,9 @@ class LeftJoycon : public JoyconController{ virtual const char* name() override{ return NAME; }; + virtual ControllerCategory controller_category() const override{ + return ControllerCategory::LEFT_JOYCON; + } }; class RightJoycon : public JoyconController{ public: @@ -199,6 +204,9 @@ class RightJoycon : public JoyconController{ virtual const char* name() override{ return NAME; }; + virtual ControllerCategory controller_category() const override{ + return ControllerCategory::RIGHT_JOYCON; + } }; diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h index 9a749057da..1dc8e46a35 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ProController.h @@ -10,6 +10,8 @@ #define PokemonAutomation_NintendoSwitch_Controller_H #include "Common/Cpp/Containers/Pimpl.h" +#include "NintendoSwitch_ControllerState.h" +#include "Controllers/ControllerTypes.h" #include "Controllers/Controller.h" #include "NintendoSwitch_ControllerButtons.h" @@ -65,6 +67,9 @@ class ProController : public AbstractController{ virtual const char* name() override{ return NAME; }; + virtual ControllerCategory controller_category() const override{ + return ControllerCategory::PRO_CONTROLLER; + } protected: From 34a5b09ca6363c14f8dffb463c3b7f111c3908df Mon Sep 17 00:00:00 2001 From: jw098 Date: Mon, 15 Sep 2025 18:24:43 -0700 Subject: [PATCH 16/34] add ControllerCategory to controller recording Json --- ...intendoSwitch_RecordKeyboardController.cpp | 32 +++++++++++++------ .../NintendoSwitch_RecordKeyboardController.h | 7 +++- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp index 53d2f93e25..819381e162 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp @@ -8,6 +8,7 @@ #include "Common/Cpp/Json/JsonArray.h" #include "NintendoSwitch/Controllers/NintendoSwitch_ProController.h" #include "NintendoSwitch_RecordKeyboardController.h" +#include "Controllers/ControllerTypeStrings.h" #include using std::cout; @@ -43,31 +44,38 @@ RecordKeyboardController::RecordKeyboardController(){ void RecordKeyboardController::program(SingleSwitchProgramEnvironment& env, CancellableScope& scope){ AbstractControllerContext context(scope, env.console.controller()); - // ProControllerContext context(scope, env.console.controller()); context.controller().add_keyboard_listener(*this); - // CONTROLLER_TYPE_STRINGS.get_string(connection.current_controller()); + ControllerCategory controller_category = env.console.controller().controller_category(); try{ context.wait_until_cancel(); }catch (ProgramCancelledException&){ - JsonValue json = controller_history_to_json(env.console.logger()); + JsonValue json = controller_history_to_json(env.console.logger(), controller_category); json.dump("recording.json"); m_controller_history.clear(); + + json_to_cpp_code(json, controller_category); + context.controller().remove_keyboard_listener(*this); throw; } +} - - + +std::string RecordKeyboardController::json_to_cpp_code(const JsonValue& json, ControllerCategory controller_category){ + + return ""; } -JsonValue RecordKeyboardController::controller_history_to_json(Logger& logger){ +JsonValue RecordKeyboardController::controller_history_to_json(Logger& logger, ControllerCategory controller_category){ if (m_controller_history.size() < 2){ - throw InternalProgramError(&logger, PA_CURRENT_FUNCTION, "RecordKeyboardController:: m_controller_history should have at least two entries, start and stop."); + // throw InternalProgramError(&logger, PA_CURRENT_FUNCTION, "RecordKeyboardController:: m_controller_history should have at least two entries, start and stop."); + logger.log("RecordKeyboardController:: We expected m_controller_history to have at least two entries, start and stop. Aborting.", COLOR_RED); + return JsonValue(); } - JsonArray json; + JsonArray json_array; ControllerStateSnapshot* prev_snapshot = &m_controller_history[0]; // the previous non-duplicate snapshot for (size_t i = 1; i < m_controller_history.size(); i++){ // start at index i = 1, since prev_snapshot starts at i=0 and we continue when current == previous. @@ -90,12 +98,16 @@ JsonValue RecordKeyboardController::controller_history_to_json(Logger& logger){ // cout << prev_controller_state.dump() << endl; JsonObject recording = prev_controller_state.clone(); recording["duration_in_ms"] = duration; - json.push_back(std::move(recording)); + json_array.push_back(std::move(recording)); prev_snapshot = &snapshot; // update the previous non-duplicate snapshot } + + JsonObject json_result; + json_result["controller_category"] = CONTROLLER_CATEGORY_STRINGS.get_string(controller_category); + json_result["history"] = JsonValue(std::move(json_array)); - return json; + return json_result; } diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h index 88820d767c..dccdd89cd0 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h @@ -32,12 +32,17 @@ class RecordKeyboardController : public SingleSwitchProgramInstance, public Keyb virtual void program(SingleSwitchProgramEnvironment& env, CancellableScope& scope) override; private: + // whenever a keyboard command is sent/stopped: + // add to m_controller_history the time_stamp and the ControllerState serialized to JSON. virtual void on_keyboard_command_sent(WallClock time_stamp, const ControllerState& state) override; virtual void on_keyboard_command_stopped(WallClock time_stamp) override; // convert m_controller_history to json // remove adjacent duplicate controller states. - JsonValue controller_history_to_json(Logger& logger); + JsonValue controller_history_to_json(Logger& logger, ControllerCategory controller_category); + + // convert the json, with the controller history, to a string, which represents C++ code. + std::string json_to_cpp_code(const JsonValue& json, ControllerCategory controller_category); // Examples for JsonObject controller_state: From 3db52bef7beb71736dca049aba324b9be3d68d9e Mon Sep 17 00:00:00 2001 From: jw098 Date: Mon, 15 Sep 2025 18:49:46 -0700 Subject: [PATCH 17/34] add MODE and JSON_FILE_NAME to UI --- ...intendoSwitch_RecordKeyboardController.cpp | 47 +++++++++++++++---- .../NintendoSwitch_RecordKeyboardController.h | 13 ++++- 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp index 819381e162..9a8a68d139 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp @@ -37,33 +37,64 @@ RecordKeyboardController::~RecordKeyboardController(){ // m_keyboard_manager->remove_listener(*this); } -RecordKeyboardController::RecordKeyboardController(){ +RecordKeyboardController::RecordKeyboardController() + : MODE( + "Mode:", + { + {Mode::RECORD, "record", "Record "}, + {Mode::REPLAY, "replay", "Replay"}, + {Mode::CONVERT_JSON_TO_CODE, "convert-to-code", "[For Developers] Convert json to code."}, + }, + LockMode::LOCK_WHILE_RUNNING, + Mode::RECORD + ) + , JSON_FILE_NAME( + false, + "Name of the JSON file to read/write.", + LockMode::LOCK_WHILE_RUNNING, + "recording", + "" + ) +{ + PA_ADD_OPTION(MODE); } void RecordKeyboardController::program(SingleSwitchProgramEnvironment& env, CancellableScope& scope){ AbstractControllerContext context(scope, env.console.controller()); - context.controller().add_keyboard_listener(*this); ControllerCategory controller_category = env.console.controller().controller_category(); + if (MODE == Mode::RECORD){ + context.controller().add_keyboard_listener(*this); + + }else if (MODE == Mode::REPLAY){ + + }else if (MODE == Mode::CONVERT_JSON_TO_CODE){ + + } + + try{ context.wait_until_cancel(); }catch (ProgramCancelledException&){ - JsonValue json = controller_history_to_json(env.console.logger(), controller_category); - json.dump("recording.json"); - m_controller_history.clear(); + if (MODE == Mode::RECORD){ + JsonValue json = controller_history_to_json(env.console.logger(), controller_category); + json.dump(std::string(JSON_FILE_NAME) + ".json"); + m_controller_history.clear(); - json_to_cpp_code(json, controller_category); + json_to_cpp_code(json); - context.controller().remove_keyboard_listener(*this); + context.controller().remove_keyboard_listener(*this); + } throw; } } -std::string RecordKeyboardController::json_to_cpp_code(const JsonValue& json, ControllerCategory controller_category){ +std::string RecordKeyboardController::json_to_cpp_code(const JsonValue& json){ + // std::string controller_category = json[] return ""; } diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h index dccdd89cd0..4717850ae8 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h @@ -8,6 +8,7 @@ #define PokemonAutomation_NintendoSwitch_RecordKeyboardController_H #include "Common/Cpp/Json/JsonObject.h" +#include "Common/Cpp/Options/StringOption.h" #include "Controllers/KeyboardInput/KeyboardInput.h" #include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" @@ -42,7 +43,7 @@ class RecordKeyboardController : public SingleSwitchProgramInstance, public Keyb JsonValue controller_history_to_json(Logger& logger, ControllerCategory controller_category); // convert the json, with the controller history, to a string, which represents C++ code. - std::string json_to_cpp_code(const JsonValue& json, ControllerCategory controller_category); + std::string json_to_cpp_code(const JsonValue& json); // Examples for JsonObject controller_state: @@ -72,7 +73,17 @@ class RecordKeyboardController : public SingleSwitchProgramInstance, public Keyb JsonObject controller_state; }; +private: + enum class Mode{ + RECORD, + REPLAY, + CONVERT_JSON_TO_CODE, + }; + EnumDropdownOption MODE; + StringOption JSON_FILE_NAME; + std::vector m_controller_history; + }; From bd84b792ed74fefa696dd6296d63085de78b2f91 Mon Sep 17 00:00:00 2001 From: jw098 Date: Mon, 15 Sep 2025 22:51:03 -0700 Subject: [PATCH 18/34] initial implementation of json_to_cpp_code_pro_controller, with placeholders for button and dpad. --- .../NintendoSwitch_VirtualControllerState.cpp | 12 +-- ...intendoSwitch_RecordKeyboardController.cpp | 89 ++++++++++++++++--- .../NintendoSwitch_RecordKeyboardController.h | 4 +- 3 files changed, 84 insertions(+), 21 deletions(-) diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_VirtualControllerState.cpp b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_VirtualControllerState.cpp index acc2a175d5..cf1be91660 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_VirtualControllerState.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_VirtualControllerState.cpp @@ -68,10 +68,10 @@ JsonObject ProControllerState::serialize_state() const { obj["is_neutral"] = is_neutral(); obj["buttons"] = button_to_string(buttons); obj["dpad"] = dpad_to_string(dpad); - obj["left_x"] = std::to_string(left_x); - obj["left_y"] = std::to_string(left_y); - obj["right_x"] = std::to_string(right_x); - obj["right_y"] = std::to_string(right_y); + obj["left_x"] = left_x; + obj["left_y"] = left_y; + obj["right_x"] = right_x; + obj["right_y"] = right_y; return obj; } @@ -186,8 +186,8 @@ JsonObject JoyconState::serialize_state() const { JsonObject obj; obj["is_neutral"] = is_neutral(); obj["buttons"] = button_to_string(buttons); - obj["joystick_x"] = std::to_string(joystick_x); - obj["joystick_y"] = std::to_string(joystick_y); + obj["joystick_x"] = joystick_x; + obj["joystick_y"] = joystick_y; return obj; } diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp index 9a8a68d139..71f6b6dce4 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp @@ -4,7 +4,6 @@ * */ - #include "Common/Cpp/Json/JsonArray.h" #include "NintendoSwitch/Controllers/NintendoSwitch_ProController.h" #include "NintendoSwitch_RecordKeyboardController.h" @@ -34,7 +33,6 @@ RecordKeyboardController_Descriptor::RecordKeyboardController_Descriptor() RecordKeyboardController::~RecordKeyboardController(){ - // m_keyboard_manager->remove_listener(*this); } RecordKeyboardController::RecordKeyboardController() @@ -57,6 +55,7 @@ RecordKeyboardController::RecordKeyboardController() ) { PA_ADD_OPTION(MODE); + PA_ADD_OPTION(JSON_FILE_NAME); } @@ -67,36 +66,98 @@ void RecordKeyboardController::program(SingleSwitchProgramEnvironment& env, Canc if (MODE == Mode::RECORD){ context.controller().add_keyboard_listener(*this); + + try{ + context.wait_until_cancel(); + }catch (ProgramCancelledException&){ + + if (MODE == Mode::RECORD){ + JsonValue json = controller_history_to_json(env.console.logger(), controller_category); + json.dump(std::string(JSON_FILE_NAME) + ".json"); + m_controller_history.clear(); + + json_to_cpp_code(env.console.logger(),json); + + context.controller().remove_keyboard_listener(*this); + } + throw; + } }else if (MODE == Mode::REPLAY){ }else if (MODE == Mode::CONVERT_JSON_TO_CODE){ + JsonValue json = load_json_file(std::string(JSON_FILE_NAME) + ".json"); + json_to_cpp_code(env.console.logger(), json); + } +} + +std::string RecordKeyboardController::json_to_cpp_code(Logger& logger, const JsonValue& json){ try{ - context.wait_until_cancel(); - }catch (ProgramCancelledException&){ + const JsonObject& obj = json.to_object_throw(); - if (MODE == Mode::RECORD){ - JsonValue json = controller_history_to_json(env.console.logger(), controller_category); - json.dump(std::string(JSON_FILE_NAME) + ".json"); - m_controller_history.clear(); + std::string controller_category_string = obj.get_string_throw("controller_category"); + cout << controller_category_string << endl; + ControllerCategory controller_category = CONTROLLER_CATEGORY_STRINGS.get_enum(controller_category_string); - json_to_cpp_code(json); + const JsonArray& history_json = obj.get_array_throw("history"); - context.controller().remove_keyboard_listener(*this); + switch (controller_category){ + case ControllerCategory::PRO_CONTROLLER: + return json_to_cpp_code_pro_controller(history_json); } - throw; + + return ""; + }catch (ParseException&){ + + throw ParseException("JSON parsing error. Given JSON file doesn't match the expected format."); } } +std::string RecordKeyboardController::json_to_cpp_code_pro_controller(const JsonArray& history){ + std::string result; + for(size_t i = 0; i < history.size(); i++){ + const JsonObject& snapshot = history[i].to_object_throw(); + int64_t duration_in_ms = snapshot.get_integer_throw("duration_in_ms"); + bool is_neutral = snapshot.get_boolean_throw("is_neutral"); + cout << duration_in_ms << endl; + if (is_neutral){ + result += "pbf_wait(context, " + std::to_string(duration_in_ms) + "ms);\n"; + }else{ + std::string buttons_string = snapshot.get_string_throw("buttons"); + std::string dpad_string = snapshot.get_string_throw("dpad"); + int64_t left_x = snapshot.get_integer_throw("left_x"); + int64_t left_y = snapshot.get_integer_throw("left_y"); + int64_t right_x = snapshot.get_integer_throw("right_x"); + int64_t right_y = snapshot.get_integer_throw("right_y"); + + // ensure all x, y are uint8_t + uint8_t uint8_max = std::numeric_limits::max(); + uint8_t uint8_min = std::numeric_limits::min(); + if (left_x > uint8_max || left_x < uint8_min || + left_y > uint8_max || left_y < uint8_min || + right_x > uint8_max || right_x < uint8_min || + right_y > uint8_max || right_y < uint8_min){ + + throw ParseException(); + } + + result += "pbf_controller_state(context, " + + buttons_string + "," + + dpad_string + "," + + std::to_string(left_x) + "," + std::to_string(left_y) + "," + + std::to_string(right_x) + "," + std::to_string(right_y) + "," + + std::to_string(duration_in_ms) +"ms);\n"; + } + + } -std::string RecordKeyboardController::json_to_cpp_code(const JsonValue& json){ - // std::string controller_category = json[] + cout << result << endl; + return result; - return ""; } JsonValue RecordKeyboardController::controller_history_to_json(Logger& logger, ControllerCategory controller_category){ diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h index 4717850ae8..7340ea388a 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h @@ -43,7 +43,9 @@ class RecordKeyboardController : public SingleSwitchProgramInstance, public Keyb JsonValue controller_history_to_json(Logger& logger, ControllerCategory controller_category); // convert the json, with the controller history, to a string, which represents C++ code. - std::string json_to_cpp_code(const JsonValue& json); + std::string json_to_cpp_code(Logger& logger, const JsonValue& json); + + std::string json_to_cpp_code_pro_controller(const JsonArray& history_json); // Examples for JsonObject controller_state: From d40e0ea7def0266556fbd75f7e7df506327ad83f Mon Sep 17 00:00:00 2001 From: jw098 Date: Tue, 16 Sep 2025 18:23:47 -0700 Subject: [PATCH 19/34] add string_to_button() and string_to_dpad(). Finish implementation of json_to_cpp_code_pro_controller() with button and dpad converted to their respective strings. --- Common/Cpp/StringTools.cpp | 16 ++ Common/Cpp/StringTools.h | 2 + Common/Qt/Options/BoxFloatWidget.cpp | 18 +- .../NintendoSwitch_ControllerButtons.cpp | 209 ++++++++++++++---- .../NintendoSwitch_ControllerButtons.h | 8 + .../NintendoSwitch/DevPrograms/BoxDraw.cpp | 17 +- ...intendoSwitch_RecordKeyboardController.cpp | 26 ++- 7 files changed, 216 insertions(+), 80 deletions(-) diff --git a/Common/Cpp/StringTools.cpp b/Common/Cpp/StringTools.cpp index dea0b877e0..7393412b86 100644 --- a/Common/Cpp/StringTools.cpp +++ b/Common/Cpp/StringTools.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "StringTools.h" namespace PokemonAutomation{ @@ -48,6 +49,21 @@ size_t to_size_t(const std::string& str){ } } +std::vector split(const std::string& str, const std::string& delimiter) { + std::vector tokens; + size_t start = 0; + size_t end = str.find(delimiter); + + while (end != std::string::npos) { + tokens.push_back(str.substr(start, end - start)); + start = end + delimiter.length(); + end = str.find(delimiter, start); + } + + tokens.push_back(str.substr(start)); + return tokens; +} + } } diff --git a/Common/Cpp/StringTools.h b/Common/Cpp/StringTools.h index fbd0fccfce..a5c42f1520 100644 --- a/Common/Cpp/StringTools.h +++ b/Common/Cpp/StringTools.h @@ -21,6 +21,8 @@ std::string strip(const std::string& str); // Parse str to size_t. Return SIZE_MAX if parsing fails size_t to_size_t(const std::string& str); +std::vector split(const std::string& str, const std::string& delimiter); + } } #endif diff --git a/Common/Qt/Options/BoxFloatWidget.cpp b/Common/Qt/Options/BoxFloatWidget.cpp index 7e48aea3cb..9db2f7ba40 100644 --- a/Common/Qt/Options/BoxFloatWidget.cpp +++ b/Common/Qt/Options/BoxFloatWidget.cpp @@ -7,6 +7,7 @@ #include #include #include +#include "Common/Cpp/StringTools.h" #include "BoxFloatWidget.h" //#include @@ -24,21 +25,6 @@ ConfigWidget* BoxFloatOption::make_QtWidget(QWidget& parent){ -std::vector split(const std::string& str, const std::string& delimiter) { - std::vector tokens; - size_t start = 0; - size_t end = str.find(delimiter); - - while (end != std::string::npos) { - tokens.push_back(str.substr(start, end - start)); - start = end + delimiter.length(); - end = str.find(delimiter, start); - } - - tokens.push_back(str.substr(start)); - return tokens; -} - BoxFloatWidget::~BoxFloatWidget(){ @@ -167,7 +153,7 @@ BoxFloatWidget::BoxFloatWidget(QWidget& parent, BoxFloatOption& value) connect( m_array, &QLineEdit::editingFinished, this, [this](){ - std::vector all_coords = split(m_array->text().toStdString(), ", "); + std::vector all_coords = StringTools::split(m_array->text().toStdString(), ", "); if (all_coords.size() != 4){ return; } diff --git a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ControllerButtons.cpp b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ControllerButtons.cpp index d0f7d29b70..c38f4a01b0 100644 --- a/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ControllerButtons.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_ControllerButtons.cpp @@ -5,59 +5,194 @@ */ #include "NintendoSwitch_ControllerButtons.h" +#include "Common/Cpp/EnumStringMap.h" +#include "Common/Cpp/StringTools.h" +#include "NintendoSwitch_ControllerState.h" namespace PokemonAutomation{ namespace NintendoSwitch{ +const EnumStringMap