diff --git a/CMakeLists.txt b/CMakeLists.txt index 6c0770c0e1..cab232c5fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -286,6 +286,7 @@ src/addons/reverse.cpp src/addons/drv8833_rumble.cpp src/addons/turbo.cpp src/addons/slider_socd.cpp +src/addons/slider_profile.cpp src/addons/wiiext.cpp src/addons/input_macro.cpp src/addons/snes_input.cpp diff --git a/headers/addons/slider_profile.h b/headers/addons/slider_profile.h new file mode 100644 index 0000000000..76700882cd --- /dev/null +++ b/headers/addons/slider_profile.h @@ -0,0 +1,41 @@ +#ifndef _SliderProfile_H +#define _SliderProfile_H + +#include "gpaddon.h" +#include "types.h" + +#ifndef SLIDER_PROFILE_ENABLED +#define SLIDER_PROFILE_ENABLED 0 +#endif + +#ifndef SLIDER_PROFILE_NUM_POSITIONS +#define SLIDER_PROFILE_NUM_POSITIONS 2 +#endif + +#ifndef SLIDER_PROFILE_DEFAULT_PROFILE +#define SLIDER_PROFILE_DEFAULT_PROFILE 1 +#endif + +#define MAX_PROFILE_SLIDER_POSITIONS 8 + +// Slider Module Name +#define SliderProfileName "SliderProfile" + +class SliderProfileInput : public GPAddon { +public: + virtual bool available(); + virtual void setup(); + virtual void reinit(); + virtual void preprocess() {} + virtual void process(); + virtual void postprocess(bool sent) {} + virtual std::string name() { return SliderProfileName; } +private: + uint32_t read(); + + Mask_t positionMasks[MAX_PROFILE_SLIDER_POSITIONS] = {0}; + Mask_t anyPositionMask = 0; + uint32_t numPositions = 0; +}; + +#endif // _SliderProfile_H diff --git a/headers/display/ui/screens/PinViewerScreen.h b/headers/display/ui/screens/PinViewerScreen.h index 6e62b41faa..febe082300 100644 --- a/headers/display/ui/screens/PinViewerScreen.h +++ b/headers/display/ui/screens/PinViewerScreen.h @@ -48,6 +48,14 @@ class PinViewerScreen : public GPScreen { {GpioAction::SUSTAIN_SOCD_MODE_SECOND_WIN, "SOCD-2W"}, {GpioAction::SUSTAIN_SOCD_MODE_FIRST_WIN, "SOCD-1W"}, {GpioAction::SUSTAIN_SOCD_MODE_BYPASS, "SOCD-BP"}, + {GpioAction::SUSTAIN_PROFILE_SLIDER_POSITION_1, "PROF1"}, + {GpioAction::SUSTAIN_PROFILE_SLIDER_POSITION_2, "PROF2"}, + {GpioAction::SUSTAIN_PROFILE_SLIDER_POSITION_3, "PROF3"}, + {GpioAction::SUSTAIN_PROFILE_SLIDER_POSITION_4, "PROF4"}, + {GpioAction::SUSTAIN_PROFILE_SLIDER_POSITION_5, "PROF5"}, + {GpioAction::SUSTAIN_PROFILE_SLIDER_POSITION_6, "PROF6"}, + {GpioAction::SUSTAIN_PROFILE_SLIDER_POSITION_7, "PROF7"}, + {GpioAction::SUSTAIN_PROFILE_SLIDER_POSITION_8, "PROF8"}, {GpioAction::BUTTON_PRESS_TURBO, "TRB"}, {GpioAction::BUTTON_PRESS_MACRO, "M"}, {GpioAction::BUTTON_PRESS_MACRO_1, "M1"}, diff --git a/proto/config.proto b/proto/config.proto index a2e7dcaf35..0d8c0b6a9e 100644 --- a/proto/config.proto +++ b/proto/config.proto @@ -473,6 +473,14 @@ message SOCDSliderOptions optional SOCDMode deprecatedModeTwo = 6 [deprecated = true]; } +message ProfileSliderOptions +{ + optional bool enabled = 1; + optional uint32 numPositions = 2; + optional uint32 defaultProfile = 3; + repeated uint32 profileAssignments = 4 [(nanopb).max_count = 8]; +} + message ReverseOptions { optional bool enabled = 1; @@ -916,6 +924,7 @@ message AddonOptions optional GamepadUSBHostOptions gamepadUSBHostOptions = 28; optional TG16Options tg16Options = 29; optional HETriggerOptions heTriggerOptions = 30; + optional ProfileSliderOptions profileSliderOptions = 31; } message MigrationHistory diff --git a/proto/enums.proto b/proto/enums.proto index 42edc7fcc8..bc1b359830 100644 --- a/proto/enums.proto +++ b/proto/enums.proto @@ -361,6 +361,14 @@ enum GpioAction MODE_WHEEL_PEDAL_GAS = 128; MODE_WHEEL_PEDAL_BRAKE = 129; MODE_WHEEL_PEDAL_CLUTCH = 130; + SUSTAIN_PROFILE_SLIDER_POSITION_1 = 131; + SUSTAIN_PROFILE_SLIDER_POSITION_2 = 132; + SUSTAIN_PROFILE_SLIDER_POSITION_3 = 133; + SUSTAIN_PROFILE_SLIDER_POSITION_4 = 134; + SUSTAIN_PROFILE_SLIDER_POSITION_5 = 135; + SUSTAIN_PROFILE_SLIDER_POSITION_6 = 136; + SUSTAIN_PROFILE_SLIDER_POSITION_7 = 137; + SUSTAIN_PROFILE_SLIDER_POSITION_8 = 138; } enum GpioDirection diff --git a/src/addons/slider_profile.cpp b/src/addons/slider_profile.cpp new file mode 100644 index 0000000000..931a4d779a --- /dev/null +++ b/src/addons/slider_profile.cpp @@ -0,0 +1,99 @@ +#include "addons/slider_profile.h" + +#include "enums.pb.h" +#include "storagemanager.h" +#include "types.h" + +bool SliderProfileInput::available() { + const ProfileSliderOptions& options = Storage::getInstance().getAddonOptions().profileSliderOptions; + return options.enabled; +} + +void SliderProfileInput::setup() +{ + const ProfileSliderOptions& options = Storage::getInstance().getAddonOptions().profileSliderOptions; + numPositions = options.numPositions; + if (numPositions > MAX_PROFILE_SLIDER_POSITIONS) { + numPositions = MAX_PROFILE_SLIDER_POSITIONS; + } + + // Clear all masks + anyPositionMask = 0; + for (int i = 0; i < MAX_PROFILE_SLIDER_POSITIONS; i++) { + positionMasks[i] = 0; + } + + // Build masks for each position based on GPIO mappings + GpioMappingInfo* pinMappings = Storage::getInstance().getProfilePinMappings(); + for (Pin_t pin = 0; pin < (Pin_t)NUM_BANK0_GPIOS; pin++) + { + switch (pinMappings[pin].action) { + case SUSTAIN_PROFILE_SLIDER_POSITION_1: positionMasks[0] |= 1 << pin; break; + case SUSTAIN_PROFILE_SLIDER_POSITION_2: positionMasks[1] |= 1 << pin; break; + case SUSTAIN_PROFILE_SLIDER_POSITION_3: positionMasks[2] |= 1 << pin; break; + case SUSTAIN_PROFILE_SLIDER_POSITION_4: positionMasks[3] |= 1 << pin; break; + case SUSTAIN_PROFILE_SLIDER_POSITION_5: positionMasks[4] |= 1 << pin; break; + case SUSTAIN_PROFILE_SLIDER_POSITION_6: positionMasks[5] |= 1 << pin; break; + case SUSTAIN_PROFILE_SLIDER_POSITION_7: positionMasks[6] |= 1 << pin; break; + case SUSTAIN_PROFILE_SLIDER_POSITION_8: positionMasks[7] |= 1 << pin; break; + default: break; + } + } + + for (uint32_t i = 0; i < numPositions; i++) { + anyPositionMask |= positionMasks[i]; + } +} + +uint32_t SliderProfileInput::read() { + const ProfileSliderOptions& options = Storage::getInstance().getAddonOptions().profileSliderOptions; + uint32_t currentProfile = Storage::getInstance().GetGamepad()->getOptions().profileNumber; + + // Masks are rebuilt from the active profile's pin mappings on every + // profile change; if the new profile doesn't map any slider positions, + // hold the current profile instead of snapping to the default profile, + // which would oscillate between the two profiles + if (anyPositionMask == 0) { + return currentProfile; + } + + Mask_t values = Storage::getInstance().GetGamepad()->debouncedGpio; + + // Check each position mask in order + for (uint32_t i = 0; i < numPositions; i++) { + if (values & positionMasks[i]) { + // Return the profile number for this position (1-indexed); an + // assignment of 0 means unset, so fall back to position index + 1 + if (i < options.profileAssignments_count && options.profileAssignments[i] > 0) { + return options.profileAssignments[i]; + } + return i + 1; + } + } + + // No GPIO position matched, return default profile + if (options.defaultProfile > 0) { + return options.defaultProfile; + } + // Fallback: stay at current profile + return currentProfile; +} + +/** + * Reinitialize masks. + */ +void SliderProfileInput::reinit() +{ + this->setup(); +} + +void SliderProfileInput::process() +{ + // Get Slider State + uint32_t profileNumber = read(); + + Gamepad * gamepad = Storage::getInstance().GetGamepad(); + if (gamepad->getOptions().profileNumber != profileNumber) { + Storage::getInstance().setProfile(profileNumber); + } +} diff --git a/src/config_utils.cpp b/src/config_utils.cpp index 478a6b21a8..fa72b97ea6 100644 --- a/src/config_utils.cpp +++ b/src/config_utils.cpp @@ -25,6 +25,7 @@ #include "addons/reactiveleds.h" #include "addons/reverse.h" #include "addons/slider_socd.h" +#include "addons/slider_profile.h" #include "addons/spi_analog_ads1256.h" #include "addons/turbo.h" #include "addons/wiiext.h" @@ -662,6 +663,11 @@ void ConfigUtils::initUnsetPropertiesWithDefaults(Config& config) INIT_UNSET_PROPERTY(config.addonOptions.socdSliderOptions, deprecatedModeOne, SLIDER_SOCD_SLOT_ONE); INIT_UNSET_PROPERTY(config.addonOptions.socdSliderOptions, deprecatedModeTwo, SLIDER_SOCD_SLOT_TWO); + // addonOptions.profileSliderOptions + INIT_UNSET_PROPERTY(config.addonOptions.profileSliderOptions, enabled, !!SLIDER_PROFILE_ENABLED); + INIT_UNSET_PROPERTY(config.addonOptions.profileSliderOptions, numPositions, SLIDER_PROFILE_NUM_POSITIONS); + INIT_UNSET_PROPERTY(config.addonOptions.profileSliderOptions, defaultProfile, SLIDER_PROFILE_DEFAULT_PROFILE); + // addonOptions.analogADS1219Options INIT_UNSET_PROPERTY(config.addonOptions.analogADS1219Options, enabled, !!I2C_ANALOG1219_ENABLED); INIT_UNSET_PROPERTY(config.addonOptions.analogADS1219Options, deprecatedI2cBlock, (I2C_ANALOG1219_BLOCK == i2c0) ? 0 : 1) diff --git a/src/gp2040.cpp b/src/gp2040.cpp index 689d1116c2..b60578f1f6 100644 --- a/src/gp2040.cpp +++ b/src/gp2040.cpp @@ -31,6 +31,7 @@ #include "addons/gamepad_usb_host.h" #include "addons/he_trigger.h" #include "addons/tg16_input.h" +#include "addons/slider_profile.h" // Pico includes #include "pico/bootrom.h" @@ -116,6 +117,7 @@ void GP2040::setup() { addons.LoadAddon(new WiiExtensionInput()); addons.LoadAddon(new SNESpadInput()); addons.LoadAddon(new SliderSOCDInput()); + addons.LoadAddon(new SliderProfileInput()); addons.LoadAddon(new TiltInput()); addons.LoadAddon(new RotaryEncoderInput()); addons.LoadAddon(new PCF8575Addon()); diff --git a/src/webconfig.cpp b/src/webconfig.cpp index d59cb1ac47..7ecc6408b0 100644 --- a/src/webconfig.cpp +++ b/src/webconfig.cpp @@ -1741,6 +1741,19 @@ std::string setAddonOptions() docToValue(socdSliderOptions.enabled, doc, "SliderSOCDInputEnabled"); docToValue(socdSliderOptions.modeDefault, doc, "sliderSOCDModeDefault"); + ProfileSliderOptions& profileSliderOptions = Storage::getInstance().getAddonOptions().profileSliderOptions; + docToValue(profileSliderOptions.enabled, doc, "SliderProfileInputEnabled"); + docToValue(profileSliderOptions.numPositions, doc, "sliderProfileNumPositions"); + docToValue(profileSliderOptions.defaultProfile, doc, "sliderProfileDefaultProfile"); + // Handle profile assignments array + if (doc.containsKey("sliderProfileAssignments")) { + JsonArray profileArray = doc["sliderProfileAssignments"]; + profileSliderOptions.profileAssignments_count = std::min(static_cast(8), profileArray.size()); + for (size_t i = 0; i < profileSliderOptions.profileAssignments_count; i++) { + profileSliderOptions.profileAssignments[i] = profileArray[i]; + } + } + OnBoardLedOptions& onBoardLedOptions = Storage::getInstance().getAddonOptions().onBoardLedOptions; docToValue(onBoardLedOptions.mode, doc, "onBoardLedMode"); docToValue(onBoardLedOptions.enabled, doc, "BoardLedAddonEnabled"); @@ -2189,6 +2202,15 @@ std::string getAddonOptions() writeDoc(doc, "sliderSOCDModeDefault", socdSliderOptions.modeDefault); writeDoc(doc, "SliderSOCDInputEnabled", socdSliderOptions.enabled); + const ProfileSliderOptions& profileSliderOptions = Storage::getInstance().getAddonOptions().profileSliderOptions; + writeDoc(doc, "SliderProfileInputEnabled", profileSliderOptions.enabled); + writeDoc(doc, "sliderProfileNumPositions", profileSliderOptions.numPositions); + writeDoc(doc, "sliderProfileDefaultProfile", profileSliderOptions.defaultProfile); + JsonArray profileAssignmentsArray = doc.createNestedArray("sliderProfileAssignments"); + for (size_t i = 0; i < profileSliderOptions.profileAssignments_count; i++) { + profileAssignmentsArray.add(profileSliderOptions.profileAssignments[i]); + } + const OnBoardLedOptions& onBoardLedOptions = Storage::getInstance().getAddonOptions().onBoardLedOptions; writeDoc(doc, "onBoardLedMode", onBoardLedOptions.mode); writeDoc(doc, "BoardLedAddonEnabled", onBoardLedOptions.enabled); diff --git a/www/src/Addons/ProfileSlider.tsx b/www/src/Addons/ProfileSlider.tsx new file mode 100644 index 0000000000..6d127eb9ab --- /dev/null +++ b/www/src/Addons/ProfileSlider.tsx @@ -0,0 +1,193 @@ +import { ChangeEvent } from 'react'; +import { useTranslation, Trans } from 'react-i18next'; +import { FormCheck, Row } from 'react-bootstrap'; +import * as yup from 'yup'; + +import Section from '../Components/Section'; +import FormControl from '../Components/FormControl'; +import FormSelect from '../Components/FormSelect'; +import { AddonPropTypes } from '../Pages/AddonsConfigPage'; + +// matches MAX_PROFILE_SLIDER_POSITIONS and the proto max_count +const MAX_SLIDER_POSITIONS = 8; +const MIN_SLIDER_POSITIONS = 2; +// core profile + 5 alternate gpioMappingsSets +const MAX_PROFILES = 6; + +export const profileSliderScheme = { + SliderProfileInputEnabled: yup + .number() + .required() + .label('Slider Profile Input Enabled'), + sliderProfileNumPositions: yup + .number() + .label('Slider Profile Num Positions') + .min(MIN_SLIDER_POSITIONS) + .max(MAX_SLIDER_POSITIONS) + .typeError('Slider Profile Num Positions must be a number'), + sliderProfileDefaultProfile: yup + .number() + .label('Slider Profile Default Profile') + .min(1) + .max(MAX_PROFILES), + sliderProfileAssignments: yup + .array() + .of(yup.number().min(1).max(MAX_PROFILES)) + .label('Slider Profile Assignments'), +}; + +export const profileSliderState = { + SliderProfileInputEnabled: 0, + sliderProfileNumPositions: 2, + sliderProfileDefaultProfile: 1, + sliderProfileAssignments: [1, 2, 3, 4, 5, 6, 7, 8], +}; + +const ProfileSlider = ({ + values, + errors, + handleChange, + handleCheckbox, + setFieldValue, +}: AddonPropTypes) => { + const { t } = useTranslation(); + const numPositions = Math.min( + Math.max( + Number(values.sliderProfileNumPositions) || MIN_SLIDER_POSITIONS, + MIN_SLIDER_POSITIONS, + ), + MAX_SLIDER_POSITIONS, + ); + const assignmentErrors = Array.isArray(errors.sliderProfileAssignments) + ? errors.sliderProfileAssignments + : []; + + // position i falls back to profile i + 1 when it has no assignment yet + const assignmentForPosition = (i: number) => + values.sliderProfileAssignments?.[i] || Math.min(i + 1, MAX_PROFILES); + + const profileOptions = Array.from({ length: MAX_PROFILES }, (_, i) => ({ + label: t('PinMapping:profile-label-default', { profileNumber: i + 1 }), + value: i + 1, + })); + + return ( +
+ {t('AddonsConfig:profile-slider-header-text')} + + } + > + + + { + handleCheckbox('SliderProfileInputEnabled'); + handleChange(e); + }} + /> +
+ ); +}; + +export default ProfileSlider; diff --git a/www/src/Locales/de-DE/AddonsConfig.jsx b/www/src/Locales/de-DE/AddonsConfig.jsx index dd415571eb..20f450a5a5 100644 --- a/www/src/Locales/de-DE/AddonsConfig.jsx +++ b/www/src/Locales/de-DE/AddonsConfig.jsx @@ -104,6 +104,11 @@ export default { "Hinweis: PS4, PS3 und Nintendo Switch modi unterstützen nicht die SOCD-Säuberung auf 'Aus' und verwenden standardmäßig den neutralen SOCD-Säuberungsmodus", 'socd-cleaning-mode-selection-slider-mode-default-label': 'SOCD Schieberegler Modus Standard', + 'profile-slider-header-text': 'Profilauswahl-Schieberegler', + 'profile-slider-sub-header-text': 'Hinweis: GPIO-Pins für die Positionen des Profilschiebereglers werden auf der Seite Pin-Zuordnung konfiguriert.', + 'profile-slider-num-positions-label': 'Anzahl der Schiebereglerpositionen', + 'profile-slider-default-profile-label': 'Standardprofil', + 'profile-slider-position-label': 'Profil für Position {{position}}', 'ps4-mode-sub-header': 'HAFTUNGSAUSSCHLUSS!', 'ps4-mode-sub-header-text': 'GP2040-CE WIRD NIEMALS DIESE DATEIEN ZUR VERFÜGUNG STELLEN!!!', diff --git a/www/src/Locales/en/AddonsConfig.jsx b/www/src/Locales/en/AddonsConfig.jsx index feedbdc8da..5dd56eb8f0 100644 --- a/www/src/Locales/en/AddonsConfig.jsx +++ b/www/src/Locales/en/AddonsConfig.jsx @@ -172,6 +172,11 @@ export default { 'socd-slider-mode-2': 'Last Win', 'socd-slider-mode-3': 'First Win', 'socd-slider-mode-4': 'SOCD Cleaning Off', + 'profile-slider-header-text': 'Profile Selection Slider', + 'profile-slider-sub-header-text': 'Note: GPIO pins for the profile slider positions are configured in the Pin Mapping page.', + 'profile-slider-num-positions-label': 'Number of Slider Positions', + 'profile-slider-default-profile-label': 'Default Profile', + 'profile-slider-position-label': 'Profile for Position {{position}}', 'tilt-socd-mode-0': 'Up Priority', 'tilt-socd-mode-1': 'Neutral', 'tilt-socd-mode-2': 'Last Win', diff --git a/www/src/Locales/en/Proto/GpioAction.jsx b/www/src/Locales/en/Proto/GpioAction.jsx index 83a24b72ce..30818691fd 100644 --- a/www/src/Locales/en/Proto/GpioAction.jsx +++ b/www/src/Locales/en/Proto/GpioAction.jsx @@ -132,4 +132,12 @@ export default { 'MODE_WHEEL_PEDAL_GAS': 'Gas Pedal', 'MODE_WHEEL_PEDAL_BRAKE': 'Brake Pedal', 'MODE_WHEEL_PEDAL_CLUTCH': 'Clutch Pedal', + 'SUSTAIN_PROFILE_SLIDER_POSITION_1': 'Profile Slider Position 1', + 'SUSTAIN_PROFILE_SLIDER_POSITION_2': 'Profile Slider Position 2', + 'SUSTAIN_PROFILE_SLIDER_POSITION_3': 'Profile Slider Position 3', + 'SUSTAIN_PROFILE_SLIDER_POSITION_4': 'Profile Slider Position 4', + 'SUSTAIN_PROFILE_SLIDER_POSITION_5': 'Profile Slider Position 5', + 'SUSTAIN_PROFILE_SLIDER_POSITION_6': 'Profile Slider Position 6', + 'SUSTAIN_PROFILE_SLIDER_POSITION_7': 'Profile Slider Position 7', + 'SUSTAIN_PROFILE_SLIDER_POSITION_8': 'Profile Slider Position 8', }; \ No newline at end of file diff --git a/www/src/Locales/es-MX/AddonsConfig.jsx b/www/src/Locales/es-MX/AddonsConfig.jsx index 8e2ff962b5..d840754611 100644 --- a/www/src/Locales/es-MX/AddonsConfig.jsx +++ b/www/src/Locales/es-MX/AddonsConfig.jsx @@ -163,6 +163,11 @@ export default { 'socd-slider-mode-2': 'Último Gana', 'socd-slider-mode-3': 'Primero Gana', 'socd-slider-mode-4': 'Limpieza SOCD Desactivada', + 'profile-slider-header-text': 'Deslizador de Selección de Perfil', + 'profile-slider-sub-header-text': 'Nota: Los pines GPIO para las posiciones del deslizador de perfil se configuran en la página de Asignación de Pines.', + 'profile-slider-num-positions-label': 'Número de Posiciones del Deslizador', + 'profile-slider-default-profile-label': 'Perfil Predeterminado', + 'profile-slider-position-label': 'Perfil para Posición {{position}}', 'tilt-socd-mode-0': 'Prioridad Arriba', 'tilt-socd-mode-1': 'Neutral', 'tilt-socd-mode-2': 'Último Gana', diff --git a/www/src/Locales/fr-FR/AddonsConfig.jsx b/www/src/Locales/fr-FR/AddonsConfig.jsx index e66553f8d5..4165b801d2 100644 --- a/www/src/Locales/fr-FR/AddonsConfig.jsx +++ b/www/src/Locales/fr-FR/AddonsConfig.jsx @@ -171,7 +171,12 @@ export default { 'socd-slider-mode-1': 'Neutre', 'socd-slider-mode-2': 'Dernier gagne', 'socd-slider-mode-3': 'Premier gagne', - 'socd-slider-mode-4': 'Désactivation du nettoyage SOCD', + 'socd-slider-mode-4': 'Désactivation du nettoyage SOCD', + 'profile-slider-header-text': 'Sélecteur de Profil', + 'profile-slider-sub-header-text': 'Remarque : les broches GPIO pour les positions du sélecteur de profil sont configurées sur la page de mappage des broches GPIO.', + 'profile-slider-num-positions-label': 'Nombre de Positions du Sélecteur', + 'profile-slider-default-profile-label': 'Profil par Défaut', + 'profile-slider-position-label': 'Profil pour la Position {{position}}', 'tilt-socd-mode-0': 'Priorité Haut', 'tilt-socd-mode-1': 'Neutre', 'tilt-socd-mode-2': 'Dernier gagne', diff --git a/www/src/Locales/fr-FR/Proto/GpioAction.jsx b/www/src/Locales/fr-FR/Proto/GpioAction.jsx index 07629ee44e..34eeef33c4 100644 --- a/www/src/Locales/fr-FR/Proto/GpioAction.jsx +++ b/www/src/Locales/fr-FR/Proto/GpioAction.jsx @@ -129,7 +129,15 @@ export default { 'MODE_WHEEL_DIAL_UP': 'Molette volant +', 'MODE_WHEEL_DIAL_DOWN': 'Molette volant -', 'MODE_WHEEL_DIAL_ENTER': 'Molette volant Entrée', - 'MODE_WHEEL_PEDAL_GAS': 'Pédale d’accélérateur', + 'MODE_WHEEL_PEDAL_GAS': 'Pédale d\'accélérateur', 'MODE_WHEEL_PEDAL_BRAKE': 'Pédale de frein', - 'MODE_WHEEL_PEDAL_CLUTCH': 'Pédale d’embrayage', + 'MODE_WHEEL_PEDAL_CLUTCH': 'Pédale d\'embrayage', + 'SUSTAIN_PROFILE_SLIDER_POSITION_1': 'Position 1 du Sélecteur de Profil', + 'SUSTAIN_PROFILE_SLIDER_POSITION_2': 'Position 2 du Sélecteur de Profil', + 'SUSTAIN_PROFILE_SLIDER_POSITION_3': 'Position 3 du Sélecteur de Profil', + 'SUSTAIN_PROFILE_SLIDER_POSITION_4': 'Position 4 du Sélecteur de Profil', + 'SUSTAIN_PROFILE_SLIDER_POSITION_5': 'Position 5 du Sélecteur de Profil', + 'SUSTAIN_PROFILE_SLIDER_POSITION_6': 'Position 6 du Sélecteur de Profil', + 'SUSTAIN_PROFILE_SLIDER_POSITION_7': 'Position 7 du Sélecteur de Profil', + 'SUSTAIN_PROFILE_SLIDER_POSITION_8': 'Position 8 du Sélecteur de Profil', }; \ No newline at end of file diff --git a/www/src/Locales/ja-JP/AddonsConfig.jsx b/www/src/Locales/ja-JP/AddonsConfig.jsx index 91f459a2af..fbb255ef31 100644 --- a/www/src/Locales/ja-JP/AddonsConfig.jsx +++ b/www/src/Locales/ja-JP/AddonsConfig.jsx @@ -172,6 +172,11 @@ export default { 'socd-slider-mode-2': '後入力優先', 'socd-slider-mode-3': '先入力優先', 'socd-slider-mode-4': 'SOCDクリーナ無効', + 'profile-slider-header-text': 'プロフィール選択スライダー', + 'profile-slider-sub-header-text': '注:プロフィール選択スライダーのポジションGPIOピンはピンマッピングページで設定されます。', + 'profile-slider-num-positions-label': 'スライダーポジション数', + 'profile-slider-default-profile-label': 'デフォルトプロフィール', + 'profile-slider-position-label': 'ポジション {{position}} のプロフィール', 'tilt-socd-mode-0': '上優先', 'tilt-socd-mode-1': 'ニュートラル', 'tilt-socd-mode-2': '後入力優先', diff --git a/www/src/Locales/ja-JP/Proto/GpioAction.jsx b/www/src/Locales/ja-JP/Proto/GpioAction.jsx index fe5ba897d3..9ff4ba119d 100644 --- a/www/src/Locales/ja-JP/Proto/GpioAction.jsx +++ b/www/src/Locales/ja-JP/Proto/GpioAction.jsx @@ -116,4 +116,12 @@ export default { 'MODE_WHEEL_PEDAL_GAS': 'アクセルペダル', 'MODE_WHEEL_PEDAL_BRAKE': 'ブレーキペダル', 'MODE_WHEEL_PEDAL_CLUTCH': 'クラッチペダル', + 'SUSTAIN_PROFILE_SLIDER_POSITION_1': 'プロフィールスライダーポジション 1', + 'SUSTAIN_PROFILE_SLIDER_POSITION_2': 'プロフィールスライダーポジション 2', + 'SUSTAIN_PROFILE_SLIDER_POSITION_3': 'プロフィールスライダーポジション 3', + 'SUSTAIN_PROFILE_SLIDER_POSITION_4': 'プロフィールスライダーポジション 4', + 'SUSTAIN_PROFILE_SLIDER_POSITION_5': 'プロフィールスライダーポジション 5', + 'SUSTAIN_PROFILE_SLIDER_POSITION_6': 'プロフィールスライダーポジション 6', + 'SUSTAIN_PROFILE_SLIDER_POSITION_7': 'プロフィールスライダーポジション 7', + 'SUSTAIN_PROFILE_SLIDER_POSITION_8': 'プロフィールスライダーポジション 8', }; diff --git a/www/src/Locales/ko-KR/AddonsConfig.jsx b/www/src/Locales/ko-KR/AddonsConfig.jsx index b7734f3703..00cb834c18 100644 --- a/www/src/Locales/ko-KR/AddonsConfig.jsx +++ b/www/src/Locales/ko-KR/AddonsConfig.jsx @@ -172,6 +172,11 @@ export default { 'socd-slider-mode-2': '후 입력 우선', 'socd-slider-mode-3': '선 입력 우선', 'socd-slider-mode-4': 'SOCD 끄기', + 'profile-slider-header-text': '프로필 선택 슬라이더', + 'profile-slider-sub-header-text': '참고: 프로필 슬라이더 위치에 대한 GPIO 핀은 핀 매핑 페이지에서 구성됩니다.', + 'profile-slider-num-positions-label': '슬라이더 위치 수', + 'profile-slider-default-profile-label': '기본 프로필', + 'profile-slider-position-label': '위치 {{position}}의 프로필', 'tilt-socd-mode-0': '상단 우선', 'tilt-socd-mode-1': '중립', 'tilt-socd-mode-2': '후 입력 우선', diff --git a/www/src/Locales/ko-KR/Proto/GpioAction.jsx b/www/src/Locales/ko-KR/Proto/GpioAction.jsx index 1295596256..b43c7e17ef 100644 --- a/www/src/Locales/ko-KR/Proto/GpioAction.jsx +++ b/www/src/Locales/ko-KR/Proto/GpioAction.jsx @@ -129,7 +129,15 @@ export default { 'MODE_WHEEL_DIAL_UP': '휠 다이얼 위', 'MODE_WHEEL_DIAL_DOWN': '휠 다이얼 아래', 'MODE_WHEEL_DIAL_ENTER': '휠 다이얼 엔터', - 'MODE_WHEEL_PEDAL_GAS': '엑셀 페달', + 'MODE_WHEEL_PEDAL_GAS': '연료 페달', 'MODE_WHEEL_PEDAL_BRAKE': '브레이크 페달', 'MODE_WHEEL_PEDAL_CLUTCH': '클러치 페달', + 'SUSTAIN_PROFILE_SLIDER_POSITION_1': '프로필 슬라이더 위치 1', + 'SUSTAIN_PROFILE_SLIDER_POSITION_2': '프로필 슬라이더 위치 2', + 'SUSTAIN_PROFILE_SLIDER_POSITION_3': '프로필 슬라이더 위치 3', + 'SUSTAIN_PROFILE_SLIDER_POSITION_4': '프로필 슬라이더 위치 4', + 'SUSTAIN_PROFILE_SLIDER_POSITION_5': '프로필 슬라이더 위치 5', + 'SUSTAIN_PROFILE_SLIDER_POSITION_6': '프로필 슬라이더 위치 6', + 'SUSTAIN_PROFILE_SLIDER_POSITION_7': '프로필 슬라이더 위치 7', + 'SUSTAIN_PROFILE_SLIDER_POSITION_8': '프로필 슬라이더 위치 8', }; \ No newline at end of file diff --git a/www/src/Locales/pt-BR/AddonsConfig.jsx b/www/src/Locales/pt-BR/AddonsConfig.jsx index 32992bbf73..afc5ee5768 100644 --- a/www/src/Locales/pt-BR/AddonsConfig.jsx +++ b/www/src/Locales/pt-BR/AddonsConfig.jsx @@ -106,6 +106,11 @@ export default { 'Observação: os modos PS4, PS3 e Nintendo Switch não suportam a configuração SOCD Cleaning como Desligada e usarão o modo SOCD Cleaning Neutro por padrão.', 'socd-cleaning-mode-selection-slider-mode-default-label': 'Modo de Controle Deslizante SOCD Padrão', + 'profile-slider-header-text': 'Controle Deslizante de Seleção de Perfil', + 'profile-slider-sub-header-text': 'Observação: os pinos GPIO para as posições do controle deslizante de perfil são configurados na página de Mapeamento de Pinos.', + 'profile-slider-num-positions-label': 'Número de Posições do Controle Deslizante', + 'profile-slider-default-profile-label': 'Perfil Padrão', + 'profile-slider-position-label': 'Perfil para Posição {{position}}', 'ps4-mode-sub-header-text': '<0>!!!! AVISO: O GP2040-CE NUNCA FORNECERÁ ESSES ARQUIVOS !!!! <1>Carregue os 3 arquivos necessários e clique no botão "Verificar e Salvar" para usar o Modo PS4.', 'ps4-mode-private-key-label': 'Chave Privada (PEM)', diff --git a/www/src/Locales/tr-TR/AddonsConfig.jsx b/www/src/Locales/tr-TR/AddonsConfig.jsx index f50ea929b1..d8cecb6b9c 100644 --- a/www/src/Locales/tr-TR/AddonsConfig.jsx +++ b/www/src/Locales/tr-TR/AddonsConfig.jsx @@ -172,6 +172,11 @@ export default { 'socd-slider-mode-2': 'Son basılan', 'socd-slider-mode-3': 'İlk basılan', 'socd-slider-mode-4': 'SOCD Temizleme Kapalı', + 'profile-slider-header-text': 'Profil Seçim Kaydırıcısı', + 'profile-slider-sub-header-text': 'Not: Profil kaydırıcı konumları için GPIO pinleri Pin Eşlemesi sayfasında yapılandırılır.', + 'profile-slider-num-positions-label': 'Kaydırıcı Konum Sayısı', + 'profile-slider-default-profile-label': 'Varsayılan Profil', + 'profile-slider-position-label': 'Konum {{position}} için Profil', 'tilt-socd-mode-0': 'Yukarı Öncelik', 'tilt-socd-mode-1': 'Doğal', 'tilt-socd-mode-2': 'Son basılan', diff --git a/www/src/Locales/zh-CN/AddonsConfig.jsx b/www/src/Locales/zh-CN/AddonsConfig.jsx index bdd6be2f75..d41ae65ec9 100644 --- a/www/src/Locales/zh-CN/AddonsConfig.jsx +++ b/www/src/Locales/zh-CN/AddonsConfig.jsx @@ -161,6 +161,11 @@ export default { 'socd-slider-mode-2': '后输入优先', 'socd-slider-mode-3': '先输入优先', 'socd-slider-mode-4': 'SOCD 清理关闭', + 'profile-slider-header-text': '个人资料选择滑块', + 'profile-slider-sub-header-text': '注意:个人资料滑块位置的 GPIO 引脚在引脚映射页面上配置。', + 'profile-slider-num-positions-label': '滑块位置数', + 'profile-slider-default-profile-label': '默认个人资料', + 'profile-slider-position-label': '位置 {{position}} 的个人资料', 'tilt-socd-mode-0': '上优先', 'tilt-socd-mode-1': '中立', 'tilt-socd-mode-2': '后输入优先', diff --git a/www/src/Locales/zh-CN/Proto/GpioAction.jsx b/www/src/Locales/zh-CN/Proto/GpioAction.jsx index 2a9c715a7a..f44c195d39 100644 --- a/www/src/Locales/zh-CN/Proto/GpioAction.jsx +++ b/www/src/Locales/zh-CN/Proto/GpioAction.jsx @@ -116,4 +116,12 @@ export default { 'MODE_WHEEL_PEDAL_GAS': '油门踏板', 'MODE_WHEEL_PEDAL_BRAKE': '刹车踏板', 'MODE_WHEEL_PEDAL_CLUTCH': '离合器踏板', + 'SUSTAIN_PROFILE_SLIDER_POSITION_1': '个人资料滑块位置 1', + 'SUSTAIN_PROFILE_SLIDER_POSITION_2': '个人资料滑块位置 2', + 'SUSTAIN_PROFILE_SLIDER_POSITION_3': '个人资料滑块位置 3', + 'SUSTAIN_PROFILE_SLIDER_POSITION_4': '个人资料滑块位置 4', + 'SUSTAIN_PROFILE_SLIDER_POSITION_5': '个人资料滑块位置 5', + 'SUSTAIN_PROFILE_SLIDER_POSITION_6': '个人资料滑块位置 6', + 'SUSTAIN_PROFILE_SLIDER_POSITION_7': '个人资料滑块位置 7', + 'SUSTAIN_PROFILE_SLIDER_POSITION_8': '个人资料滑块位置 8', }; \ No newline at end of file diff --git a/www/src/Pages/AddonsConfigPage.tsx b/www/src/Pages/AddonsConfigPage.tsx index 0c147e6892..d1b87a96e2 100644 --- a/www/src/Pages/AddonsConfigPage.tsx +++ b/www/src/Pages/AddonsConfigPage.tsx @@ -33,6 +33,10 @@ import OnBoardLed, { } from '../Addons/OnBoardLed'; import Reverse, { reverseScheme, reverseState } from '../Addons/Reverse'; import SOCD, { socdScheme, socdState } from '../Addons/SOCD'; +import ProfileSlider, { + profileSliderScheme, + profileSliderState, +} from '../Addons/ProfileSlider'; import Tilt, { tiltScheme, tiltState } from '../Addons/Tilt'; import Turbo, { turboScheme, turboState } from '../Addons/Turbo'; import Wii, { wiiScheme, wiiState } from '../Addons/Wii'; @@ -82,6 +86,7 @@ const schema = yup.object().shape({ ...tiltScheme, ...buzzerScheme, ...socdScheme, + ...profileSliderScheme, ...wiiScheme, ...focusModeScheme, ...keyboardScheme, @@ -105,6 +110,7 @@ export const DEFAULT_VALUES = { ...tiltState, ...buzzerState, ...socdState, + ...profileSliderState, ...wiiState, ...snesState, ...tg16State, @@ -130,6 +136,7 @@ const ADDONS = [ Tilt, Buzzer, SOCD, + ProfileSlider, Wii, SNES, TG16,