Skip to content

Commit b4ad7d7

Browse files
committed
Finish macro table. Apply to TurboMacro.
1 parent d39e6ff commit b4ad7d7

File tree

10 files changed

+286
-96
lines changed

10 files changed

+286
-96
lines changed

Common/Cpp/Exceptions.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,15 @@ FileException::FileException(Logger* logger, const char* location, std::string m
4444
}
4545
}
4646
std::string FileException::message() const{
47-
return m_message + "\nFile: " + m_file + "\nLocation: " + m_location;
47+
std::string ret = m_message;
48+
if (!m_file.empty()){
49+
ret += "\nFile: " + m_file;
50+
}
51+
if (m_location != nullptr){
52+
ret += "\nLocation: ";
53+
ret += m_location;
54+
}
55+
return ret;
4856
}
4957

5058

Common/Cpp/Options/EditableTableOption.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,15 @@ class EditableTableOption : public ConfigOption{
128128

129129
// Lambda returns a boolean. False to continue running. True to stop.
130130
template <typename RowType, typename Lambda>
131+
void run_on_all_rows(Lambda function) const{
132+
ReadSpinLock lg(m_current_lock);
133+
for (auto& item : m_current){
134+
if (function(static_cast<const RowType&>(*item))){
135+
return;
136+
}
137+
}
138+
}
139+
template <typename RowType, typename Lambda>
131140
void run_on_all_rows(Lambda function){
132141
ReadSpinLock lg(m_current_lock);
133142
for (auto& item : m_current){

Common/Cpp/Options/EnumDropdownDatabase.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,12 +125,14 @@ class EnumDropdownDatabase : public IntegerEnumDropdownDatabase{
125125
const EnumEntry* find(EnumType value) const{
126126
return IntegerEnumDropdownDatabase::find((size_t)value);
127127
}
128+
#if 0
128129
EnumType find_slug(const std::string& slug) const{
129130
return (EnumType)IntegerEnumDropdownDatabase::find_slug(slug);
130131
}
131132
EnumType find_display(const std::string& display) const{
132133
return (EnumType)IntegerEnumDropdownDatabase::find_display(display);
133134
}
135+
#endif
134136

135137
protected:
136138
EnumDropdownDatabase(void*) : IntegerEnumDropdownDatabase(nullptr) {}

Common/Qt/CheckboxDropdown.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ class CheckboxDropdown : public QComboBox{
7373
setItemText(0, label);
7474
}
7575

76+
virtual void wheelEvent(QWheelEvent* event) override{
77+
QWidget::wheelEvent(event);
78+
}
7679
virtual bool eventFilter(QObject* obj, QEvent* event) override{
7780
// cout << "eventFilter()" << endl;
7881
if (event->type() != QEvent::MouseButtonRelease){

Common/Qt/Options/EditableTableWidget.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,16 @@ EditableTableWidget::EditableTableWidget(QWidget& parent, EditableTableOption& v
109109
if (path.empty()){
110110
return;
111111
}
112-
value.load_json(load_json_file(path));
112+
try{
113+
value.load_json(load_json_file(path));
114+
}catch (Exception& e){
115+
QMessageBox::warning(
116+
nullptr,
117+
"Failed to load JSON.",
118+
QString::fromStdString(e.message())
119+
);
120+
}
121+
113122
}
114123
);
115124
}

SerialPrograms/Source/Controllers/ControllerStateTable.cpp

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,20 @@
66

77
#include <map>
88
#include "Common/Cpp/Exceptions.h"
9+
#include "Common/Cpp/Json/JsonArray.h"
10+
#include "Common/Cpp/Json/JsonObject.h"
911
#include "ControllerTypeStrings.h"
1012
#include "ControllerStateTable.h"
1113

1214
#include "NintendoSwitch/Controllers/Procon/NintendoSwitch_ProControllerTable.h"
1315
#include "NintendoSwitch/Controllers/Joycon/NintendoSwitch_JoyconTable.h"
1416

17+
#include "NintendoSwitch/Options/TurboMacroTable.h"
18+
19+
//#include <iostream>
20+
//using std::cout;
21+
//using std::endl;
22+
1523
namespace PokemonAutomation{
1624

1725

@@ -58,6 +66,219 @@ void ControllerCommandTable::register_controller_type(
5866
}
5967

6068

69+
70+
71+
void ControllerCommandTable::load_json_NS_TurboMacro(const JsonValue& json){
72+
using namespace NintendoSwitch;
73+
74+
if (m_type != ControllerClass::NintendoSwitch_ProController){
75+
throw FileException(
76+
nullptr, nullptr,
77+
"Incompatible controller type.",
78+
""
79+
);
80+
}
81+
82+
JsonObject translated;
83+
translated["ControllerClass"] = CONTROLLER_CLASS_STRINGS().get_string(m_type);
84+
85+
// JSON to JSON translate to the new format.
86+
JsonArray history;
87+
88+
for (const JsonValue& item : json.to_array_throw()){
89+
const JsonObject& obj = item.to_object_throw();
90+
91+
const std::string& action_name = obj.get_string_throw("Action");
92+
const auto* entry = TurboMacroAction_Database().find_slug(action_name);
93+
if (entry == nullptr){
94+
throw ParseException("Invalid Action: " + action_name);
95+
}
96+
97+
const JsonValue* value;
98+
99+
TurboMacroAction action = (TurboMacroAction)entry->enum_value;
100+
101+
if (action == TurboMacroAction::NO_ACTION){
102+
continue;
103+
}
104+
105+
// Wait has different timing fields.
106+
if (action == TurboMacroAction::WAIT){
107+
value = obj.get_value("Wait");
108+
if (value != nullptr && value->is_integer()){
109+
JsonObject out;
110+
out["ms"] = std::to_string(value->to_integer_default() * 8) + " ms";
111+
history.push_back(std::move(out));
112+
}
113+
value = obj.get_value("WaitMs");
114+
if (value != nullptr){
115+
JsonObject out;
116+
out["ms"] = value->to_string_throw();
117+
history.push_back(std::move(out));
118+
}
119+
continue;
120+
}
121+
122+
JsonObject command;
123+
124+
value = obj.get_value("Hold");
125+
if (value != nullptr && value->is_integer()){
126+
command["ms"] = std::to_string(value->to_integer_default() * 8) + " ms";
127+
}
128+
value = obj.get_value("HoldMs");
129+
if (value != nullptr){
130+
command["ms"] = value->to_string_throw();
131+
}
132+
if (value == nullptr){
133+
throw ParseException("Missing Duration: " + obj.dump());
134+
}
135+
136+
137+
switch (action){
138+
case TurboMacroAction::B:
139+
command["buttons"] = "B";
140+
break;
141+
case TurboMacroAction::A:
142+
command["buttons"] = "A";
143+
break;
144+
case TurboMacroAction::Y:
145+
command["buttons"] = "Y";
146+
break;
147+
case TurboMacroAction::X:
148+
command["buttons"] = "X";
149+
break;
150+
case TurboMacroAction::R:
151+
command["buttons"] = "R";
152+
break;
153+
case TurboMacroAction::L:
154+
command["buttons"] = "L";
155+
break;
156+
case TurboMacroAction::ZR:
157+
command["buttons"] = "ZR";
158+
break;
159+
case TurboMacroAction::ZL:
160+
command["buttons"] = "ZL";
161+
break;
162+
case TurboMacroAction::PLUS:
163+
command["buttons"] = "+";
164+
break;
165+
case TurboMacroAction::MINUS:
166+
command["buttons"] = "-";
167+
break;
168+
case TurboMacroAction::LEFT_JOY_CLICK:
169+
command["buttons"] = "LJ";
170+
break;
171+
case TurboMacroAction::RIGHT_JOY_CLICK:
172+
command["buttons"] = "RJ";
173+
break;
174+
case TurboMacroAction::DPADLEFT:
175+
command["dpad"] = "left";
176+
break;
177+
case TurboMacroAction::DPADRIGHT:
178+
command["dpad"] = "right";
179+
break;
180+
case TurboMacroAction::DPADUP:
181+
command["dpad"] = "up";
182+
break;
183+
case TurboMacroAction::DPADDOWN:
184+
command["dpad"] = "down";
185+
break;
186+
case TurboMacroAction::LEFT_JOYSTICK:
187+
value = obj.get_value("MoveDirectionX");
188+
if (value != nullptr){
189+
command["lx"] = value->to_integer_throw();
190+
}
191+
value = obj.get_value("MoveDirectionY");
192+
if (value != nullptr){
193+
command["ly"] = value->to_integer_throw();
194+
}
195+
break;
196+
case TurboMacroAction::RIGHT_JOYSTICK:
197+
value = obj.get_value("MoveDirectionX");
198+
if (value != nullptr){
199+
command["rx"] = value->to_integer_throw();
200+
}
201+
value = obj.get_value("MoveDirectionY");
202+
if (value != nullptr){
203+
command["ry"] = value->to_integer_throw();
204+
}
205+
break;
206+
default:;
207+
}
208+
209+
history.push_back(std::move(command));
210+
211+
212+
JsonObject cooldown;
213+
value = obj.get_value("Release");
214+
if (value != nullptr && value->is_integer()){
215+
cooldown["ms"] = std::to_string(value->to_integer_default() * 8) + " ms";
216+
}
217+
value = obj.get_value("ReleaseMs");
218+
if (value != nullptr){
219+
cooldown["ms"] = value->to_string_throw();
220+
}
221+
if (value != nullptr){
222+
history.push_back(std::move(cooldown));
223+
}
224+
}
225+
226+
translated["Schedule"] = std::move(history);
227+
228+
// cout << translated.dump() << endl;
229+
230+
JsonValue value(std::move(translated));
231+
load_json(value);
232+
}
233+
234+
void ControllerCommandTable::load_json(const JsonValue& json){
235+
clear();
236+
237+
if (json.is_array()){
238+
load_json_NS_TurboMacro(json);
239+
return;
240+
}
241+
242+
const JsonObject& obj = json.to_object_throw();
243+
244+
const JsonValue* value = obj.get_value("controller_class");
245+
if (value == nullptr){
246+
value = obj.get_value("ControllerClass");
247+
}
248+
if (value == nullptr){
249+
throw JsonParseException("", "ControllerClass");
250+
}
251+
const std::string& controller = value->to_string_throw();
252+
if (CONTROLLER_CLASS_STRINGS().get_enum(controller) != m_type){
253+
throw FileException(
254+
nullptr, nullptr,
255+
"Incompatible controller type.",
256+
""
257+
);
258+
}
259+
260+
value = obj.get_value("history");
261+
if (value == nullptr){
262+
value = obj.get_value("Schedule");
263+
}
264+
if (value == nullptr){
265+
throw JsonParseException("", "Schedule");
266+
}
267+
268+
EditableTableOption::load_json(*value);
269+
}
270+
JsonValue ControllerCommandTable::to_json() const{
271+
JsonObject obj;
272+
obj["ControllerClass"] = CONTROLLER_CLASS_STRINGS().get_string(m_type);
273+
JsonArray history;
274+
run_on_all_rows<ControllerStateRow>([&](const ControllerStateRow& row){
275+
history.push_back(row.to_json());
276+
return false;
277+
});
278+
obj["Schedule"] = std::move(history);
279+
return obj;
280+
}
281+
61282
std::vector<std::string> ControllerCommandTable::make_header() const{
62283
auto& map = get_controller_map();
63284
auto iter = map.find(m_type);

SerialPrograms/Source/Controllers/ControllerStateTable.h

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
namespace PokemonAutomation{
1717

1818

19+
class ControllerCommandTables;
20+
1921

2022

2123
class ControllerStateRow : public EditableTableRow{
@@ -57,10 +59,7 @@ class ControllerCommandTable : public EditableTableOption{
5759
return m_type;
5860
}
5961

60-
void run(
61-
CancellableScope& scope,
62-
AbstractController& controller
63-
){
62+
void run(CancellableScope& scope, AbstractController& controller){
6463
std::vector<std::unique_ptr<ControllerStateRow>> table = EditableTableOption::copy_snapshot<ControllerStateRow>();
6564
for (std::unique_ptr<ControllerStateRow>& command : table){
6665
Milliseconds duration;
@@ -69,12 +68,20 @@ class ControllerCommandTable : public EditableTableOption{
6968
}
7069
}
7170

71+
virtual void load_json(const JsonValue& json) override;
72+
virtual JsonValue to_json() const override;
73+
7274
virtual std::vector<std::string> make_header() const override;
7375
virtual std::unique_ptr<EditableTableRow> make_row() override;
7476

7577

78+
private:
79+
void load_json_NS_TurboMacro(const JsonValue& json);
80+
81+
7682
private:
7783
friend class ControllerCommandTables;
84+
7885
ControllerClass m_type;
7986
};
8087

@@ -87,6 +94,11 @@ class ControllerCommandTables : public BatchOption, public ConfigOption::Listene
8794
~ControllerCommandTables();
8895
ControllerCommandTables(const std::vector<ControllerClass>& controller_list);
8996

97+
void run(CancellableScope& scope, AbstractController& controller){
98+
m_table.run(scope, controller);
99+
}
100+
101+
90102
public:
91103
virtual void on_config_value_changed(void* object) override;
92104

@@ -96,6 +108,8 @@ class ControllerCommandTables : public BatchOption, public ConfigOption::Listene
96108
);
97109

98110
private:
111+
friend class ControllerCommandTable;
112+
99113
// There is a race condition here if multiple threads try to change this
100114
// at the same time since it clears the table. But we only ever do this
101115
// from the main Qt thread.

SerialPrograms/Source/NintendoSwitch/Controllers/Procon/NintendoSwitch_ProControllerTable.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class ProControllerStateRow : public ControllerStateRow{
3131
void get_state(ProControllerState& state) const;
3232
virtual std::unique_ptr<ControllerState> get_state(Milliseconds& duration) const override;
3333

34+
3435
private:
3536
MillisecondsCell DURATION;
3637
CheckboxDropdownCell<Button> BUTTONS;

0 commit comments

Comments
 (0)