From b75e47388053f67380e87a341681348f5e14e186 Mon Sep 17 00:00:00 2001 From: jw098 Date: Sun, 19 Oct 2025 13:55:22 -0700 Subject: [PATCH] RecordKeyboardController: add ability to loop action --- ...intendoSwitch_RecordKeyboardController.cpp | 162 ++++++++++-------- .../NintendoSwitch_RecordKeyboardController.h | 9 +- 2 files changed, 97 insertions(+), 74 deletions(-) diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp index 86fcedbabf..5ab0194837 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.cpp @@ -56,6 +56,16 @@ RecordKeyboardController::RecordKeyboardController() "UserSettings/recording", "" ) + , LOOP( + "Number of times to loop:", + LockMode::UNLOCK_WHILE_RUNNING, + 100, 0 + ) + , WAIT( + "Number of seconds between loops:", + LockMode::UNLOCK_WHILE_RUNNING, + 5, 0 + ) , GENERATE_CPP_CODE_AFTER_RECORDING( "[For Developers]
" "Automatically generate C++ code:
" @@ -67,6 +77,8 @@ RecordKeyboardController::RecordKeyboardController() { PA_ADD_OPTION(MODE); PA_ADD_OPTION(FILE_NAME); + PA_ADD_OPTION(LOOP); + PA_ADD_OPTION(WAIT); PA_ADD_OPTION(GENERATE_CPP_CODE_AFTER_RECORDING); } @@ -105,7 +117,7 @@ void RecordKeyboardController::program(SingleSwitchProgramEnvironment& env, Canc }else if (MODE == Mode::REPLAY){ JsonValue json = load_json_file(std::string(FILE_NAME) + ".json"); - json_to_pbf_actions(env, scope, json, controller_class); + json_to_pbf_actions(env, scope, json, controller_class, LOOP, WAIT); }else if (MODE == Mode::CONVERT_JSON_TO_CODE){ @@ -207,7 +219,7 @@ std::string json_to_cpp_code_pro_controller(const JsonArray& history){ } ); - cout << result << endl; + cout << "\n" + result << endl; return result; } @@ -252,13 +264,13 @@ std::string json_to_cpp_code_joycon(const JsonArray& history){ } ); - cout << result << endl; + cout << "\n" + result << endl; return result; } -void json_to_pbf_actions(SingleSwitchProgramEnvironment& env, CancellableScope& scope, const JsonValue& json, ControllerClass controller_class){ +void json_to_pbf_actions(SingleSwitchProgramEnvironment& env, CancellableScope& scope, const JsonValue& json, ControllerClass controller_class, uint32_t num_loops, uint32_t seconds_wait_between_loops){ try{ const JsonObject& obj = json.to_object_throw(); @@ -274,14 +286,14 @@ void json_to_pbf_actions(SingleSwitchProgramEnvironment& env, CancellableScope& case ControllerClass::NintendoSwitch_ProController: { ProControllerContext context(scope, env.console.controller()); - json_to_pbf_actions_pro_controller(context, history_json); + json_to_pbf_actions_pro_controller(context, history_json, num_loops, seconds_wait_between_loops); break; } case ControllerClass::NintendoSwitch_LeftJoycon: case ControllerClass::NintendoSwitch_RightJoycon: { JoyconContext context(scope, env.console.controller()); - json_to_pbf_actions_joycon(context, history_json); + json_to_pbf_actions_joycon(context, history_json, num_loops, seconds_wait_between_loops); break; } default: @@ -296,77 +308,85 @@ void json_to_pbf_actions(SingleSwitchProgramEnvironment& env, CancellableScope& } -void json_to_pbf_actions_pro_controller(ProControllerContext& context, const JsonArray& history){ +void json_to_pbf_actions_pro_controller(ProControllerContext& context, const JsonArray& history, uint32_t num_loops, uint32_t seconds_wait_between_loops){ - json_to_pro_controller_state(history, - [&](int64_t duration_in_ms){ - pbf_wait(context, Milliseconds(duration_in_ms)); - }, - [&](NonNeutralControllerField non_neutral_field, - Button button, - DpadPosition dpad, - uint8_t left_x, - uint8_t left_y, - uint8_t right_x, - uint8_t right_y, - int64_t duration_in_ms - ){ - switch (non_neutral_field){ - case NonNeutralControllerField::BUTTON: - pbf_press_button(context, button, Milliseconds(duration_in_ms), Milliseconds(0)); - break; - case NonNeutralControllerField::DPAD: - pbf_press_dpad(context, dpad, Milliseconds(duration_in_ms), Milliseconds(0)); - break; - case NonNeutralControllerField::LEFT_JOYSTICK: - pbf_move_left_joystick(context, left_x, left_y, Milliseconds(duration_in_ms), Milliseconds(0)); - break; - case NonNeutralControllerField::RIGHT_JOYSTICK: - pbf_move_right_joystick(context, right_x, right_y, Milliseconds(duration_in_ms), Milliseconds(0)); - break; - case NonNeutralControllerField::MULTIPLE: - pbf_controller_state(context, button, dpad, left_x, left_y, right_x, right_y, Milliseconds(duration_in_ms)); - break; - case NonNeutralControllerField::NONE: + for (uint32_t i = 0; i < num_loops; i++){ + json_to_pro_controller_state(history, + [&](int64_t duration_in_ms){ pbf_wait(context, Milliseconds(duration_in_ms)); - break; - default: - throw ParseException("Unexpected NonNeutralControllerField enum."); - } - } - ); + }, + [&](NonNeutralControllerField non_neutral_field, + Button button, + DpadPosition dpad, + uint8_t left_x, + uint8_t left_y, + uint8_t right_x, + uint8_t right_y, + int64_t duration_in_ms + ){ + switch (non_neutral_field){ + case NonNeutralControllerField::BUTTON: + pbf_press_button(context, button, Milliseconds(duration_in_ms), Milliseconds(0)); + break; + case NonNeutralControllerField::DPAD: + pbf_press_dpad(context, dpad, Milliseconds(duration_in_ms), Milliseconds(0)); + break; + case NonNeutralControllerField::LEFT_JOYSTICK: + pbf_move_left_joystick(context, left_x, left_y, Milliseconds(duration_in_ms), Milliseconds(0)); + break; + case NonNeutralControllerField::RIGHT_JOYSTICK: + pbf_move_right_joystick(context, right_x, right_y, Milliseconds(duration_in_ms), Milliseconds(0)); + break; + case NonNeutralControllerField::MULTIPLE: + pbf_controller_state(context, button, dpad, left_x, left_y, right_x, right_y, Milliseconds(duration_in_ms)); + break; + case NonNeutralControllerField::NONE: + pbf_wait(context, Milliseconds(duration_in_ms)); + break; + default: + throw ParseException("Unexpected NonNeutralControllerField enum."); + } + } + ); + + pbf_wait(context, Seconds(seconds_wait_between_loops)); + } } -void json_to_pbf_actions_joycon(JoyconContext& context, const JsonArray& history){ +void json_to_pbf_actions_joycon(JoyconContext& context, const JsonArray& history, uint32_t num_loops, uint32_t seconds_wait_between_loops){ - json_to_joycon_state(history, - [&](int64_t duration_in_ms){ - pbf_wait(context, Milliseconds(duration_in_ms)); - }, - [&](NonNeutralControllerField non_neutral_field, - Button button, - uint8_t x, - uint8_t y, - int64_t duration_in_ms - ){ - switch (non_neutral_field){ - case NonNeutralControllerField::BUTTON: - pbf_press_button(context, button, Milliseconds(duration_in_ms), Milliseconds(0)); - break; - case NonNeutralControllerField::JOYSTICK: - pbf_move_joystick(context, x, y, Milliseconds(duration_in_ms), Milliseconds(0)); - break; - case NonNeutralControllerField::MULTIPLE: - pbf_controller_state(context, button, x, y, Milliseconds(duration_in_ms)); - break; - case NonNeutralControllerField::NONE: + for (uint32_t i = 0; i < num_loops; i++){ + json_to_joycon_state(history, + [&](int64_t duration_in_ms){ pbf_wait(context, Milliseconds(duration_in_ms)); - break; - default: - throw ParseException("Unexpected NonNeutralControllerField enum."); - } - } - ); + }, + [&](NonNeutralControllerField non_neutral_field, + Button button, + uint8_t x, + uint8_t y, + int64_t duration_in_ms + ){ + switch (non_neutral_field){ + case NonNeutralControllerField::BUTTON: + pbf_press_button(context, button, Milliseconds(duration_in_ms), Milliseconds(0)); + break; + case NonNeutralControllerField::JOYSTICK: + pbf_move_joystick(context, x, y, Milliseconds(duration_in_ms), Milliseconds(0)); + break; + case NonNeutralControllerField::MULTIPLE: + pbf_controller_state(context, button, x, y, Milliseconds(duration_in_ms)); + break; + case NonNeutralControllerField::NONE: + pbf_wait(context, Milliseconds(duration_in_ms)); + break; + default: + throw ParseException("Unexpected NonNeutralControllerField enum."); + } + } + ); + + pbf_wait(context, Seconds(seconds_wait_between_loops)); + } } diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h index e07e3652b0..b28c3b1687 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_RecordKeyboardController.h @@ -10,6 +10,7 @@ #include #include "Common/Cpp/Json/JsonObject.h" #include "Common/Cpp/Options/BooleanCheckBoxOption.h" +#include "Common/Cpp/Options/SimpleIntegerOption.h" #include "Common/Cpp/Options/StringOption.h" #include "NintendoSwitch/Controllers/NintendoSwitch_Joycon.h" #include "Controllers/KeyboardInput/KeyboardInput.h" @@ -67,9 +68,9 @@ std::string json_to_cpp_code_pro_controller(const JsonArray& history_json); std::string json_to_cpp_code_joycon(const JsonArray& history); // given the json, with the controller history, run the controller actions using the pbf functions. -void json_to_pbf_actions(SingleSwitchProgramEnvironment& env, CancellableScope& scope, const JsonValue& json, ControllerClass controller_class); -void json_to_pbf_actions_pro_controller(ProControllerContext& context, const JsonArray& history); -void json_to_pbf_actions_joycon(JoyconContext& context, const JsonArray& history); +void json_to_pbf_actions(SingleSwitchProgramEnvironment& env, CancellableScope& scope, const JsonValue& json, ControllerClass controller_class, uint32_t num_loops, uint32_t seconds_wait_between_loops); +void json_to_pbf_actions_pro_controller(ProControllerContext& context, const JsonArray& history, uint32_t num_loops, uint32_t seconds_wait_between_loops); +void json_to_pbf_actions_joycon(JoyconContext& context, const JsonArray& history, uint32_t num_loops, uint32_t seconds_wait_between_loops); class RecordKeyboardController_Descriptor : public SingleSwitchProgramDescriptor{ public: @@ -132,6 +133,8 @@ class RecordKeyboardController : public SingleSwitchProgramInstance, public Keyb }; EnumDropdownOption MODE; StringOption FILE_NAME; + SimpleIntegerOption LOOP; + SimpleIntegerOption WAIT; BooleanCheckBoxOption GENERATE_CPP_CODE_AFTER_RECORDING; std::vector m_controller_history;