Skip to content

Commit

Permalink
Add the ability to label a profile and see it in the web UI and OLED …
Browse files Browse the repository at this point in the history
…display (OpenStickCommunity#1139)

* add the ability to give a profile a name

* Add support for changing profile labels

* Letters, numbers, and spaces allowed in profile label

* actually retain the alt. profile labels

aka increment the array index *after* you're done using it, silly bss

* actually provide the alt mappings profileLabels in the proper API spot

this fixes the issues with Pelsin's UI change, which was immaculately
done and only thwarted by my bugs =)

* display the profile label on the display when a label is set

e.g. the top line splash says "SNES FG" instead of "Profile #2"

---------

Co-authored-by: ian <[email protected]>
  • Loading branch information
bsstephan and Pelsin authored Sep 25, 2024
1 parent 245e15e commit 2712ecf
Show file tree
Hide file tree
Showing 15 changed files with 329 additions and 304 deletions.
1 change: 1 addition & 0 deletions headers/gamepad.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "BoardConfig.h"
#include "types.h"
#include <string.h>
#include <string>

#include "enums.pb.h"
#include "gamepad/GamepadState.h"
Expand Down
1 change: 1 addition & 0 deletions headers/storagemanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class Storage {
void nextProfile();
void previousProfile();
void setFunctionalPinMappings();
char* currentProfileLabel();

void ResetSettings(); // EEPROM Reset Feature

Expand Down
1 change: 1 addition & 0 deletions proto/config.proto
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ message GpioMappingInfo
message GpioMappings
{
repeated GpioMappingInfo pins = 1 [(nanopb).max_count = 30];
optional string profileLabel = 2 [(nanopb).max_length = 16];
}


Expand Down
84 changes: 47 additions & 37 deletions src/configs/webconfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,10 @@ std::string setProfileOptions()
profileOptions.gpioMappingsSets[altsIndex].pins[pin].customDpadMask = (uint32_t)alt[pinName]["customDpadMask"];
}
}
size_t profileLabelSize = sizeof(profileOptions.gpioMappingsSets[altsIndex].profileLabel);
strncpy(profileOptions.gpioMappingsSets[altsIndex].profileLabel, alt["profileLabel"], profileLabelSize - 1);
profileOptions.gpioMappingsSets[altsIndex].profileLabel[profileLabelSize - 1] = '\0';

profileOptions.gpioMappingsSets_count = ++altsIndex;
if (altsIndex > 2) break;
}
Expand Down Expand Up @@ -614,6 +618,7 @@ std::string getProfileOptions()
writePinDoc(i, "pin27", profileOptions.gpioMappingsSets[i].pins[27]);
writePinDoc(i, "pin28", profileOptions.gpioMappingsSets[i].pins[28]);
writePinDoc(i, "pin29", profileOptions.gpioMappingsSets[i].pins[29]);
writeDoc(doc, "alternativePinMappings", i, "profileLabel", profileOptions.gpioMappingsSets[i].profileLabel);
}

return serialize_json(doc);
Expand Down Expand Up @@ -1039,21 +1044,24 @@ std::string setPinMappings()
{
DynamicJsonDocument doc = get_post_data();

GpioMappingInfo* gpioMappings = Storage::getInstance().getGpioMappings().pins;
GpioMappings& gpioMappings = Storage::getInstance().getGpioMappings();

char pinName[6];
for (Pin_t pin = 0; pin < (Pin_t)NUM_BANK0_GPIOS; pin++) {
snprintf(pinName, 6, "pin%0*d", 2, pin);
// setting a pin shouldn't change a new existing addon/reserved pin
if (gpioMappings[pin].action != GpioAction::RESERVED &&
gpioMappings[pin].action != GpioAction::ASSIGNED_TO_ADDON &&
if (gpioMappings.pins[pin].action != GpioAction::RESERVED &&
gpioMappings.pins[pin].action != GpioAction::ASSIGNED_TO_ADDON &&
(GpioAction)doc[pinName]["action"] != GpioAction::RESERVED &&
(GpioAction)doc[pinName]["action"] != GpioAction::ASSIGNED_TO_ADDON) {
gpioMappings[pin].action = (GpioAction)doc[pinName]["action"];
gpioMappings[pin].customButtonMask = (uint32_t)doc[pinName]["customButtonMask"];
gpioMappings[pin].customDpadMask = (uint32_t)doc[pinName]["customDpadMask"];
gpioMappings.pins[pin].action = (GpioAction)doc[pinName]["action"];
gpioMappings.pins[pin].customButtonMask = (uint32_t)doc[pinName]["customButtonMask"];
gpioMappings.pins[pin].customDpadMask = (uint32_t)doc[pinName]["customDpadMask"];
}
}
size_t profileLabelSize = sizeof(gpioMappings.profileLabel);
strncpy(gpioMappings.profileLabel, doc["profileLabel"], profileLabelSize - 1);
gpioMappings.profileLabel[profileLabelSize - 1] = '\0';

Storage::getInstance().save();

Expand All @@ -1064,7 +1072,7 @@ std::string getPinMappings()
{
DynamicJsonDocument doc(LWIP_HTTPD_POST_MAX_PAYLOAD_LEN);

GpioMappingInfo* gpioMappings = Storage::getInstance().getGpioMappings().pins;
GpioMappings& gpioMappings = Storage::getInstance().getGpioMappings();

const auto writePinDoc = [&](const char* key, const GpioMappingInfo& value) -> void
{
Expand All @@ -1073,36 +1081,38 @@ std::string getPinMappings()
writeDoc(doc, key, "customDpadMask", value.customDpadMask);
};

writePinDoc("pin00", gpioMappings[0]);
writePinDoc("pin01", gpioMappings[1]);
writePinDoc("pin02", gpioMappings[2]);
writePinDoc("pin03", gpioMappings[3]);
writePinDoc("pin04", gpioMappings[4]);
writePinDoc("pin05", gpioMappings[5]);
writePinDoc("pin06", gpioMappings[6]);
writePinDoc("pin07", gpioMappings[7]);
writePinDoc("pin08", gpioMappings[8]);
writePinDoc("pin09", gpioMappings[9]);
writePinDoc("pin10", gpioMappings[10]);
writePinDoc("pin11", gpioMappings[11]);
writePinDoc("pin12", gpioMappings[12]);
writePinDoc("pin13", gpioMappings[13]);
writePinDoc("pin14", gpioMappings[14]);
writePinDoc("pin15", gpioMappings[15]);
writePinDoc("pin16", gpioMappings[16]);
writePinDoc("pin17", gpioMappings[17]);
writePinDoc("pin18", gpioMappings[18]);
writePinDoc("pin19", gpioMappings[19]);
writePinDoc("pin20", gpioMappings[20]);
writePinDoc("pin21", gpioMappings[21]);
writePinDoc("pin22", gpioMappings[22]);
writePinDoc("pin23", gpioMappings[23]);
writePinDoc("pin24", gpioMappings[24]);
writePinDoc("pin25", gpioMappings[25]);
writePinDoc("pin26", gpioMappings[26]);
writePinDoc("pin27", gpioMappings[27]);
writePinDoc("pin28", gpioMappings[28]);
writePinDoc("pin29", gpioMappings[29]);
writePinDoc("pin00", gpioMappings.pins[0]);
writePinDoc("pin01", gpioMappings.pins[1]);
writePinDoc("pin02", gpioMappings.pins[2]);
writePinDoc("pin03", gpioMappings.pins[3]);
writePinDoc("pin04", gpioMappings.pins[4]);
writePinDoc("pin05", gpioMappings.pins[5]);
writePinDoc("pin06", gpioMappings.pins[6]);
writePinDoc("pin07", gpioMappings.pins[7]);
writePinDoc("pin08", gpioMappings.pins[8]);
writePinDoc("pin09", gpioMappings.pins[9]);
writePinDoc("pin10", gpioMappings.pins[10]);
writePinDoc("pin11", gpioMappings.pins[11]);
writePinDoc("pin12", gpioMappings.pins[12]);
writePinDoc("pin13", gpioMappings.pins[13]);
writePinDoc("pin14", gpioMappings.pins[14]);
writePinDoc("pin15", gpioMappings.pins[15]);
writePinDoc("pin16", gpioMappings.pins[16]);
writePinDoc("pin17", gpioMappings.pins[17]);
writePinDoc("pin18", gpioMappings.pins[18]);
writePinDoc("pin19", gpioMappings.pins[19]);
writePinDoc("pin20", gpioMappings.pins[20]);
writePinDoc("pin21", gpioMappings.pins[21]);
writePinDoc("pin22", gpioMappings.pins[22]);
writePinDoc("pin23", gpioMappings.pins[23]);
writePinDoc("pin24", gpioMappings.pins[24]);
writePinDoc("pin25", gpioMappings.pins[25]);
writePinDoc("pin26", gpioMappings.pins[26]);
writePinDoc("pin27", gpioMappings.pins[27]);
writePinDoc("pin28", gpioMappings.pins[28]);
writePinDoc("pin29", gpioMappings.pins[29]);

writeDoc(doc, "profileLabel", gpioMappings.profileLabel);

return serialize_json(doc);
}
Expand Down
14 changes: 10 additions & 4 deletions src/display/ui/screens/ButtonLayoutScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,19 @@ int8_t ButtonLayoutScreen::update() {
void ButtonLayoutScreen::generateHeader() {
// Limit to 21 chars with 6x8 font for now
statusBar.clear();
Storage& storage = Storage::getInstance();

// Display Profile # banner
if ( profileModeDisplay ) {
if (((getMillis() - profileDelayStart) / 1000) < profileDelay) {
statusBar = " Profile #";
statusBar += std::to_string(getGamepad()->getOptions().profileNumber);
return;
statusBar.assign(storage.currentProfileLabel(), strlen(storage.currentProfileLabel()));
if (statusBar.empty()) {
statusBar = " Profile #";
statusBar += std::to_string(getGamepad()->getOptions().profileNumber);
} else {
statusBar.insert(statusBar.begin(), (21-statusBar.length())/2, ' ');
}
return;
} else {
profileModeDisplay = false;
}
Expand Down Expand Up @@ -172,7 +178,7 @@ void ButtonLayoutScreen::generateHeader() {
case INPUT_MODE_CONFIG: statusBar += "CONFIG"; break;
}

const TurboOptions& turboOptions = Storage::getInstance().getAddonOptions().turboOptions;
const TurboOptions& turboOptions = storage.getAddonOptions().turboOptions;
if ( turboOptions.enabled ) {
statusBar += " T";
if ( turboOptions.shotCount < 10 ) // padding
Expand Down
10 changes: 10 additions & 0 deletions src/storagemanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,16 @@ void Storage::previousProfile()
this->config.gamepadOptions.profileNumber -= 1;
}

/**
* @brief Return the current profile label.
*/
char* Storage::currentProfileLabel() {
if (this->config.gamepadOptions.profileNumber == 1)
return this->config.gpioMappings.profileLabel;
else
return this->config.profileOptions.gpioMappingsSets[config.gamepadOptions.profileNumber-2].profileLabel;
}

void Storage::setFunctionalPinMappings()
{
GpioMappingInfo* alts = nullptr;
Expand Down
20 changes: 11 additions & 9 deletions www/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion www/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"react-router-dom": "^6.10.0",
"react-select": "^5.7.5",
"yup": "^1.1.1",
"zustand": "^4.4.1"
"zustand": "^4.5.5"
},
"scripts": {
"analyze": "npx vite-bundle-visualizer",
Expand Down
29 changes: 20 additions & 9 deletions www/server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,20 @@ const __dirname = path.dirname(__filename);
const { pico: picoController } = JSON.parse(
readFileSync(path.resolve(__dirname, '../src/Data/Controllers.json'), 'utf8'),
);
const PinMappings = Object.entries(picoController).reduce(
(acc, [key, value]) => ({
...acc,
[key]: { action: value, customButtonMask: 0, customDpadMask: 0 },
}),
{},
);

// Structure pin mappings to include masks and profile label
const createPinMappings = ({ profileLabel = 'Profile' }) => {
let pinMappings = { profileLabel };

for (const [key, value] of Object.entries(picoController)) {
pinMappings[key] = {
action: value,
customButtonMask: 0,
customDpadMask: 0,
};
}
return pinMappings;
};

const port = process.env.PORT || 8080;

Expand Down Expand Up @@ -260,7 +267,7 @@ app.get('/api/getCustomTheme', (req, res) => {
});

app.get('/api/getPinMappings', (req, res) => {
return res.send(PinMappings);
return res.send(createPinMappings({ profileLabel: 'Profile 1' }));
});

app.get('/api/getKeyMappings', (req, res) =>
Expand Down Expand Up @@ -380,7 +387,11 @@ app.get('/api/getWiiControls', (req, res) =>

app.get('/api/getProfileOptions', (req, res) => {
return res.send({
alternativePinMappings: [PinMappings, PinMappings, PinMappings],
alternativePinMappings: [
createPinMappings({ profileLabel: 'Profile 2' }),
createPinMappings({ profileLabel: 'Profile 3' }),
createPinMappings({ profileLabel: 'Profile 4' }),
],
});
});

Expand Down
12 changes: 6 additions & 6 deletions www/src/Locales/en/PinMapping.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ export default {
'pin-viewer': 'Pin viewer',
'pin-pressed': 'Pressed pin: {{pressedPin}}',
'pin-header-label': 'Pin',
'profile-text-1': 'Base(Profile 1)',
'profile-text-2': 'Profile 2',
'profile-text-3': 'Profile 3',
'profile-text-4': 'Profile 4',
'profile-pin-mapping-title-base': 'Base(Profile 1) - Pin Mapping',
'profile-pin-mapping-title': 'Profile {{profileNumber}} - Pin Mapping',

'profile-label-title': 'Profile name',
'profile-label-description':
'Max 16 characters. Letters, numbers, and spaces allowed.',
'profile-pin-mapping-title': '{{profileLabel}} - Pin Mapping',
'profile-label-default': 'Profile {{profileNumber}}',
'profile-pins-warning':
'Try to avoid changing the buttons and/or directions used for the switch profile hotkeys. Otherwise, it will be difficult to understand what profile is being selected!',
'profile-copy-base': 'Copy base profile',
Expand Down
8 changes: 2 additions & 6 deletions www/src/Locales/ja-JP/PinMapping.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,8 @@ export default {
'未接続や未実装の端子を割当設定するとコントローラが動作しない状態に陥る可能性があります。無効な設定を初期化したい場合は<2>設定初期化</2>のページで初期化を実行してください。',
'pin-viewer': '端子確認',
'pin-pressed': 'このボタンの配線先は {{pressedPin}} 番端子です!',
'profile-text-1': '基本(プロファイル 1)',
'profile-text-2': 'プロファイル 2',
'profile-text-3': 'プロファイル 3',
'profile-text-4': 'プロファイル 4',
'profile-pin-mapping-title-base': 'デフォルト(プロファイル 1) - 端子割当',
'profile-pin-mapping-title': 'プロファイル {{profileNumber}} - 端子割当',
'profile-pin-mapping-title': '{{profileLabel}} - 端子割当',
'profile-label-default': 'プロファイル {{profileNumber}}',
'pin-header-label': '端子',
'profile-pins-warning':
'プロファイルの変更ホットキーに設定しているボタンや方向キーの設定変更は、現在のプロファイル選択状況がわからなくなる原因となるため非推奨です。',
Expand Down
8 changes: 2 additions & 6 deletions www/src/Locales/zh-CN/PinMapping.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,8 @@ export default {
'pin-viewer': '引脚查看器',
'pin-pressed': '按下的引脚:{{pressedPin}}',
'pin-header-label': '引脚',
'profile-text-1': '基础(档案 1)',
'profile-text-2': '档案 2',
'profile-text-3': '档案 3',
'profile-text-4': '档案 4',
'profile-pin-mapping-title-base': '基础(档案 1) - 引脚映射',
'profile-pin-mapping-title': '档案 {{profileNumber}} - 引脚映射',
'profile-pin-mapping-title': '{{profileLabel}} - 引脚映射',
'profile-label-default': '档案 {{profileNumber}}',
'profile-pins-warning':
'尽量避免修改已设置为切换档案快捷键的按键或方向键,否则之后将很难理解你选择的档案配置!',
'profile-copy-base': '复制基础档案',
Expand Down
Loading

0 comments on commit 2712ecf

Please sign in to comment.