diff --git a/companion/src/firmwares/boards.cpp b/companion/src/firmwares/boards.cpp index a736c406649..4cf3e287403 100644 --- a/companion/src/firmwares/boards.cpp +++ b/companion/src/firmwares/boards.cpp @@ -396,6 +396,12 @@ int Boards::getCapability(Board::Type board, Board::Capability capability) return ((IS_FAMILY_HORUS_OR_T16(board) && getCapability(board, HasAuxSerialMode)) || IS_RADIOMASTER_TX15(board) || IS_RADIOMASTER_TX16SMK3(board)); + case HasKeyLockCombo: + return !(IS_HELLORADIOSKY_V12(board) || IS_TARANIS_XLITE(board) || + IS_FLYSKY_PA01(board) || IS_FLYSKY_NV14(board) || + IS_FLYSKY_EL18(board) || IS_FAMILY_PL18(board) || + board == Board::BOARD_FLYSKY_NB4P); + case HasLedStripGPIO: return (IS_RADIOMASTER_MT12(board) || IS_FAMILY_PL18(board) || IS_HELLORADIOSKY_V16(board)); diff --git a/companion/src/firmwares/boards.h b/companion/src/firmwares/boards.h index 0788792a545..21490b9f914 100644 --- a/companion/src/firmwares/boards.h +++ b/companion/src/firmwares/boards.h @@ -237,6 +237,7 @@ namespace Board { HasInternalGPS, HasInternalModuleSupport, HasIntModuleHeartbeatGPIO, + HasKeyLockCombo, HasLedStripGPIO, HasRTC, HasSDCard, diff --git a/companion/src/firmwares/edgetx/yaml_generalsettings.cpp b/companion/src/firmwares/edgetx/yaml_generalsettings.cpp index a085d935b3f..bbf58c7c206 100644 --- a/companion/src/firmwares/edgetx/yaml_generalsettings.cpp +++ b/companion/src/firmwares/edgetx/yaml_generalsettings.cpp @@ -399,6 +399,7 @@ Node convert::encode(const GeneralSettings& rhs) } node["oneLogPerDay"] = (int)rhs.oneLogPerDay; + node["keyLockEnabled"] = (int)rhs.keyLockEnabled; return node; } @@ -737,6 +738,7 @@ bool convert::decode(const Node& node, GeneralSettings& rhs) } node["oneLogPerDay"] >> rhs.oneLogPerDay; + node["keyLockEnabled"] >> rhs.keyLockEnabled; // override critical settings after import // TODO: for consistency move up call stack to use existing eeprom and profile conversions diff --git a/companion/src/firmwares/generalsettings.h b/companion/src/firmwares/generalsettings.h index 7ef2e901e3d..c36fefe19b3 100644 --- a/companion/src/firmwares/generalsettings.h +++ b/companion/src/firmwares/generalsettings.h @@ -458,6 +458,7 @@ class GeneralSettings { unsigned int keyShortcuts[MAX_KEYSHORTCUTS]; unsigned int qmFavorites[MAX_QMFAVOURITES]; bool oneLogPerDay; + bool keyLockEnabled; void switchConfigClear(); diff --git a/companion/src/generaledit/generalsetup.cpp b/companion/src/generaledit/generalsetup.cpp index 9ba789d74f9..c67aff9e680 100644 --- a/companion/src/generaledit/generalsetup.cpp +++ b/companion/src/generaledit/generalsetup.cpp @@ -635,6 +635,16 @@ void GeneralSetupPanel::setValues() ui->modelQuickSelect_CB->setChecked(generalSettings.modelQuickSelect); ui->chkOneLogPerDay->setChecked(generalSettings.oneLogPerDay); + { + bool hasCombo = Boards::getCapability(board, Board::HasKeyLockCombo); + ui->chkKeyLockEnabled->setChecked(hasCombo && generalSettings.keyLockEnabled); + ui->chkKeyLockEnabled->setEnabled(hasCombo); + ui->label_keyLockEnabled->setEnabled(hasCombo); + if (!hasCombo) { + ui->chkKeyLockEnabled->setToolTip(tr("Not available on this radio (no key combo defined)")); + ui->label_keyLockEnabled->setToolTip(tr("Not available on this radio (no key combo defined)")); + } + } if (Boards::getCapability(board, Board::HasColorLcd)) { ui->modelSelectLayout_CB->setCurrentIndex(generalSettings.modelSelectLayout); @@ -1141,3 +1151,11 @@ void GeneralSetupPanel::on_chkOneLogPerDay_stateChanged(int) emit modified(); } } + +void GeneralSetupPanel::on_chkKeyLockEnabled_stateChanged(int) +{ + if (!lock) { + generalSettings.keyLockEnabled = ui->chkKeyLockEnabled->isChecked(); + emit modified(); + } +} diff --git a/companion/src/generaledit/generalsetup.h b/companion/src/generaledit/generalsetup.h index 55b51a815a9..d0d3249122c 100644 --- a/companion/src/generaledit/generalsetup.h +++ b/companion/src/generaledit/generalsetup.h @@ -105,6 +105,7 @@ class GeneralSetupPanel : public GeneralPanel void on_pwrOffIfInactiveSB_editingFinished(); void on_chkOneLogPerDay_stateChanged(int); + void on_chkKeyLockEnabled_stateChanged(int); private: Ui::GeneralSetup *ui; diff --git a/companion/src/generaledit/generalsetup.ui b/companion/src/generaledit/generalsetup.ui index 0b1c42d9ca5..c17ef1e1aac 100644 --- a/companion/src/generaledit/generalsetup.ui +++ b/companion/src/generaledit/generalsetup.ui @@ -1727,7 +1727,7 @@ p, li { white-space: pre-wrap; } - + Qt::Orientation::Vertical @@ -2544,6 +2544,20 @@ Mode 4: + + + + Key lock + + + + + + + + + + diff --git a/radio/src/datastructs_private.h b/radio/src/datastructs_private.h index e291ddad4ea..3fa6b75692c 100644 --- a/radio/src/datastructs_private.h +++ b/radio/src/datastructs_private.h @@ -1159,14 +1159,14 @@ PACK(struct RadioData { NOBACKUP(uint8_t modelQuickSelect:1); NOBACKUP(uint8_t oneLogPerDay:1); + NOBACKUP(uint8_t keyLockEnabled:1); #if defined(COLORLCD) - NOBACKUP(uint8_t spare:4 SKIP); + NOBACKUP(uint8_t spare:3 SKIP); #elif LCD_W == 128 uint8_t invertLCD:1; // Invert B&W LCD display - NOBACKUP(uint8_t spare:1 SKIP); #else - NOBACKUP(uint8_t spare:2 SKIP); + NOBACKUP(uint8_t spare:1 SKIP); #endif NOBACKUP(uint8_t pwrOffIfInactive); diff --git a/radio/src/gui/128x64/radio_setup.cpp b/radio/src/gui/128x64/radio_setup.cpp index bea0b3509e3..9c71270169d 100644 --- a/radio/src/gui/128x64/radio_setup.cpp +++ b/radio/src/gui/128x64/radio_setup.cpp @@ -83,6 +83,7 @@ enum { CASE_BACKLIGHT(ITEM_RADIO_SETUP_BRIGHTNESS) CASE_CONTRAST(ITEM_RADIO_SETUP_CONTRAST) CASE_BACKLIGHT(ITEM_RADIO_SETUP_FLASH_BEEP) + CASE_KEY_LOCK(ITEM_RADIO_SETUP_KEY_LOCK) ITEM_RADIO_ONE_LOG_PER_DAY, CASE_SPLASH_PARAM(ITEM_RADIO_SETUP_DISABLE_SPLASH) CASE_PWR_BUTTON_PRESS(ITEM_RADIO_SETUP_PWR_ON_SPEED) @@ -218,6 +219,7 @@ void menuRadioSetup(event_t event) CASE_BACKLIGHT(0) CASE_CONTRAST(0) CASE_BACKLIGHT(0) + CASE_KEY_LOCK(0) 0, CASE_SPLASH_PARAM(0) CASE_PWR_BUTTON_PRESS(0) @@ -594,6 +596,20 @@ void menuRadioSetup(event_t event) break; } +#if defined(KEYS_LOCK_KEY1) && defined(KEYS_LOCK_KEY2) + case ITEM_RADIO_SETUP_KEY_LOCK: { + static char lbl[45]; + const char* k1 = keysGetLabel((EnumKeys)KEYS_LOCK_KEY1); + const char* k2 = keysGetLabel((EnumKeys)KEYS_LOCK_KEY2); + snprintf(lbl, sizeof(lbl), STR_KEY_LOCK_FMT, + k1 ? k1 : "?", k2 ? k2 : "?"); + lcdDrawTextAlignedLeft(y, lbl); + g_eeGeneral.keyLockEnabled = + editCheckBox(g_eeGeneral.keyLockEnabled, LCD_W - 9, y, nullptr, attr, event); + break; + } +#endif + case ITEM_RADIO_SETUP_DISABLE_SPLASH: { lcdDrawTextAlignedLeft(y, STR_SPLASHSCREEN); diff --git a/radio/src/gui/212x64/radio_setup.cpp b/radio/src/gui/212x64/radio_setup.cpp index 9fa7e1baf3f..b7640ef19b7 100644 --- a/radio/src/gui/212x64/radio_setup.cpp +++ b/radio/src/gui/212x64/radio_setup.cpp @@ -80,6 +80,7 @@ enum MenuRadioSetupItems { ITEM_RADIO_SETUP_CONTRAST, CASE_PCBX9E_PCBX9DP(ITEM_RADIO_SETUP_BACKLIGHT_COLOR) ITEM_RADIO_SETUP_FLASH_BEEP, + CASE_KEY_LOCK(ITEM_RADIO_SETUP_KEY_LOCK) ITEM_RADIO_ONE_LOG_PER_DAY, CASE_SPLASH_PARAM(ITEM_RADIO_SETUP_DISABLE_SPLASH) CASE_PWR_BUTTON_PRESS(ITEM_RADIO_SETUP_PWR_ON_SPEED) @@ -218,6 +219,7 @@ void menuRadioSetup(event_t event) 0, // contrast CASE_PCBX9E_PCBX9DP(0) // backlight color 0, // flash beep + CASE_KEY_LOCK(0) // key lock 0, CASE_SPLASH_PARAM(0) // disable splash CASE_PWR_BUTTON_PRESS(0) // pwr on speed @@ -577,6 +579,20 @@ void menuRadioSetup(event_t event) break; } +#if defined(KEYS_LOCK_KEY1) && defined(KEYS_LOCK_KEY2) + case ITEM_RADIO_SETUP_KEY_LOCK: { + static char lbl[45]; + const char* k1 = keysGetLabel((EnumKeys)KEYS_LOCK_KEY1); + const char* k2 = keysGetLabel((EnumKeys)KEYS_LOCK_KEY2); + snprintf(lbl, sizeof(lbl), STR_KEY_LOCK_FMT, + k1 ? k1 : "?", k2 ? k2 : "?"); + lcdDrawTextAlignedLeft(y, lbl); + g_eeGeneral.keyLockEnabled = + editCheckBox(g_eeGeneral.keyLockEnabled, RADIO_SETUP_2ND_COLUMN, y, nullptr, attr, event); + break; + } +#endif + case ITEM_RADIO_SETUP_DISABLE_SPLASH: lcdDrawTextAlignedLeft(y, STR_SPLASHSCREEN); if (SPLASH_NEEDED()) { diff --git a/radio/src/gui/colorlcd/radio/radio_setup.cpp b/radio/src/gui/colorlcd/radio/radio_setup.cpp index 7ffb91f25ed..5b46f6d9c71 100644 --- a/radio/src/gui/colorlcd/radio/radio_setup.cpp +++ b/radio/src/gui/colorlcd/radio/radio_setup.cpp @@ -718,6 +718,25 @@ class ManageModelsSetupPage : public SubPage Window* favSelectMatch = nullptr; }; +#if defined(KEYS_LOCK_KEY1) && defined(KEYS_LOCK_KEY2) +// Combo-specific label ("Lock keys (SYS+MDL)"), so built dynamically +// rather than as a SetupLineDef - can't be a plain STR_TYP entry. +static coord_t addKeyLockLine(Window* window, coord_t y, coord_t col2, PaddingSize padding) +{ + static char keyLockLabel[45]; + const char* k1 = keysGetLabel((EnumKeys)KEYS_LOCK_KEY1); + const char* k2 = keysGetLabel((EnumKeys)KEYS_LOCK_KEY2); + snprintf(keyLockLabel, sizeof(keyLockLabel), STR_KEY_LOCK_FMT, + k1 ? k1 : "?", k2 ? k2 : "?"); + Window* w = new SetupLine(window, y, col2, padding, keyLockLabel, + [=](Window* parent, coord_t x, coord_t y) { + new ToggleSwitch(parent, {x, y, 0, 0}, + GET_SET_DEFAULT(g_eeGeneral.keyLockEnabled)); + }); + return y + w->height() + padding; +} +#endif + static SetupLineDef setupLines[] = { { // Have only one log per day @@ -1013,5 +1032,9 @@ void RadioSetupPage::build(Window* window) }, BTN_H); y += w->height() + padding; +#if defined(KEYS_LOCK_KEY1) && defined(KEYS_LOCK_KEY2) + y = addKeyLockLine(window, y, SubPage::EDT_X, padding); +#endif + SetupLine::showLines(window, y, SubPage::EDT_X, padding, setupLines, DIM(setupLines)); } diff --git a/radio/src/gui/common/stdlcd/feature_control.h b/radio/src/gui/common/stdlcd/feature_control.h index 9aeda6d4fe7..244f7c75fb6 100644 --- a/radio/src/gui/common/stdlcd/feature_control.h +++ b/radio/src/gui/common/stdlcd/feature_control.h @@ -47,6 +47,12 @@ #define CASE_BACKLIGHT(x) #endif +#if defined(KEYS_LOCK_KEY1) && defined(KEYS_LOCK_KEY2) +#define CASE_KEY_LOCK(x) x, +#else +#define CASE_KEY_LOCK(x) +#endif + #if defined(RTCLOCK) #define CASE_RTCLOCK(x) x, #else diff --git a/radio/src/hal/key_driver.h b/radio/src/hal/key_driver.h index 0919f2570e6..e53a8975b2d 100644 --- a/radio/src/hal/key_driver.h +++ b/radio/src/hal/key_driver.h @@ -65,8 +65,13 @@ uint32_t readTrims(); // Init GPIO ports void keysInit(); +// returns a bit field with each supported key uint32_t keysGetSupported(); +static inline bool keyIsSupported(EnumKeys key) { + return keysGetSupported() & (1 << key); +} + uint8_t keysGetMaxKeys(); uint8_t keysGetMaxTrims(); diff --git a/radio/src/keys.cpp b/radio/src/keys.cpp index af4a93f908d..36a2fe7dce7 100644 --- a/radio/src/keys.cpp +++ b/radio/src/keys.cpp @@ -28,7 +28,7 @@ #include "hal/rotary_encoder.h" #include "dataconstants.h" -#if !defined(BOOT) && (defined(USE_HATS_AS_KEYS) || defined(PCBXLITE)) +#if !defined(BOOT) #include "edgetx.h" #endif @@ -183,6 +183,26 @@ void Key::killEvents() static Key keys[MAX_KEYS]; static Key trim_keys[MAX_TRIMS * 2]; +#if !defined(BOOT) +// Per-target key combo (from hal.h KEYS_LOCK_KEY1/KEY2) long-pressed together +// toggles a software key lock. +static bool s_keys_locked = false; +static bool s_keys_lock_notify = false; +static uint8_t s_keys_lock_combo_cnt = 0; + +bool areKeysLocked() { return s_keys_locked; } + +bool consumeKeysLockToggleEvent() +{ + if (!s_keys_lock_notify) return false; + s_keys_lock_notify = false; + return true; +} +#else +bool areKeysLocked() { return false; } +bool consumeKeysLockToggleEvent() { return false; } +#endif + /** * @brief returns true if there is an event waiting. * @@ -491,11 +511,48 @@ bool keysPollingCycle() trims_input = READ_TRIMS(); #endif +#if !defined(BOOT) && defined(KEYS_LOCK_KEY1) && defined(KEYS_LOCK_KEY2) + // Combo keys (from hal.h) long-pressed together toggle the key lock; killing + // the per-key events while both are held prevents their individual actions + // from firing. + if (g_eeGeneral.keyLockEnabled && + keyIsSupported(KEYS_LOCK_KEY1) && keyIsSupported(KEYS_LOCK_KEY2)) { + bool both = (keys_input & (1u << KEYS_LOCK_KEY1)) && + (keys_input & (1u << KEYS_LOCK_KEY2)); + if (both) { + keys[KEYS_LOCK_KEY1].killEvents(); + keys[KEYS_LOCK_KEY2].killEvents(); + if (s_keys_lock_combo_cnt < 0xFF) s_keys_lock_combo_cnt++; + if (s_keys_lock_combo_cnt == KEY_LONG_DELAY) { + s_keys_locked = !s_keys_locked; + s_keys_lock_notify = true; + } + } else { + s_keys_lock_combo_cnt = 0; + } + } else { + // Feature disabled: never leave keys stuck locked. + s_keys_locked = false; + s_keys_lock_combo_cnt = 0; + } +#endif + for (int i = 0; i < MAX_KEYS; i++) { event_t evt = keys[i].input(keys_input & (1 << i)); if (evt) { evt = keyMapping(evt | i); +#if !defined(BOOT) + if (evt) { + if (!s_keys_locked) { + pushEvent(evt); + } else if ((evt & _MSK_KEY_FLAGS) == _MSK_KEY_FIRST) { + // Re-show the "Keys locked" toast on each new key press while locked. + s_keys_lock_notify = true; + } + } +#else if (evt) pushEvent(evt); +#endif } } diff --git a/radio/src/keys.h b/radio/src/keys.h index 44cef3af146..cb04f2447d3 100644 --- a/radio/src/keys.h +++ b/radio/src/keys.h @@ -186,6 +186,12 @@ uint8_t keysGetTrimState(uint8_t trim); bool keysPollingCycle(); bool rotaryEncoderPollingCycle(); +// Holding the per-target combo (KEYS_LOCK_KEY1 + KEYS_LOCK_KEY2 from hal.h) +// for KEY_LONG_DELAY toggles the key lock. While locked, key events are +// suppressed; trims/sticks/switches still work. +bool areKeysLocked(); +bool consumeKeysLockToggleEvent(); + #if defined(USE_HATS_AS_KEYS) void setHatsAsKeys(bool val); bool getHatsAsKeys(); diff --git a/radio/src/main.cpp b/radio/src/main.cpp index b0b2c24c5ee..7ae1b24812e 100644 --- a/radio/src/main.cpp +++ b/radio/src/main.cpp @@ -254,6 +254,54 @@ void checkHatsAsKeys() } #endif +#if !defined(COLORLCD) +// Tick count at which to clear our key-lock message. 0 = no message active. +static tmr10ms_t s_keysLockMsgUntil = 0; +static const char* s_keysLockMsg = nullptr; +#endif + +void checkKeysLock() +{ + if (consumeKeysLockToggleEvent()) { + audioKeyPress(); + const char* lockedMsg = STR_KEYS_LOCKED; +#if defined(KEYS_LOCK_KEY1) && defined(KEYS_LOCK_KEY2) + static char lockedBuf[45]; + const char* k1 = keysGetLabel((EnumKeys)KEYS_LOCK_KEY1); + const char* k2 = keysGetLabel((EnumKeys)KEYS_LOCK_KEY2); + snprintf(lockedBuf, sizeof(lockedBuf), STR_KEYS_LOCKED_FMT, + k1 ? k1 : "?", k2 ? k2 : "?"); + lockedMsg = lockedBuf; +#endif +#if defined(COLORLCD) + POPUP_BUBBLE(areKeysLocked() ? lockedMsg : STR_KEYS_UNLOCKED, 1500); +#else + // Can't use a modal POPUP_INFORMATION: keys may be locked, so the user + // couldn't dismiss it. Keep our own deadline and re-arm POPUP_WAIT every + // tick below — that survives other code clearing warningText (e.g. the + // GVAR display in view_main.cpp). + s_keysLockMsg = areKeysLocked() ? lockedMsg : STR_KEYS_UNLOCKED; + s_keysLockMsgUntil = get_tmr10ms() + 150; +#endif + } + +#if !defined(COLORLCD) + if (s_keysLockMsgUntil) { + if ((int32_t)(get_tmr10ms() - s_keysLockMsgUntil) >= 0) { + s_keysLockMsgUntil = 0; + // Only clear if our message is still the active one; another popup + // may have replaced it in the meantime. + if (warningText == s_keysLockMsg) CLEAR_POPUP(); + s_keysLockMsg = nullptr; + } else { + // Keep the popup fresh every tick — another path (GVAR, etc.) may + // have cleared warningText; just re-arm it. + POPUP_WAIT(s_keysLockMsg); + } + } +#endif +} + void checkStorageUpdate() { #if defined(RTC_BACKUP_RAM) && !defined(SIMU) @@ -508,6 +556,9 @@ void perMain() checkHatsAsKeys(); #endif + checkKeysLock(); + + #if defined(RTC_BACKUP_RAM) if (UNEXPECTED_SHUTDOWN()) { #if defined(COLORLCD) diff --git a/radio/src/storage/yaml/yaml_datastructs_128x64.cpp b/radio/src/storage/yaml/yaml_datastructs_128x64.cpp index b91a4f92b8f..007a02f3652 100644 --- a/radio/src/storage/yaml/yaml_datastructs_128x64.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_128x64.cpp @@ -382,8 +382,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), YAML_UNSIGNED( "invertLCD", 1 ), - YAML_PADDING( 1 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_c14.cpp b/radio/src/storage/yaml/yaml_datastructs_c14.cpp index 634be7f7379..4732c417ee3 100644 --- a/radio/src/storage/yaml/yaml_datastructs_c14.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_c14.cpp @@ -447,7 +447,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), - YAML_PADDING( 4 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), + YAML_PADDING( 3 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL), YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL), diff --git a/radio/src/storage/yaml/yaml_datastructs_f16.cpp b/radio/src/storage/yaml/yaml_datastructs_f16.cpp index 81c271903ed..737ba38f92f 100644 --- a/radio/src/storage/yaml/yaml_datastructs_f16.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_f16.cpp @@ -448,7 +448,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), - YAML_PADDING( 4 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), + YAML_PADDING( 3 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL), YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL), diff --git a/radio/src/storage/yaml/yaml_datastructs_gx12.cpp b/radio/src/storage/yaml/yaml_datastructs_gx12.cpp index 160b3258036..4a3a8c029b8 100644 --- a/radio/src/storage/yaml/yaml_datastructs_gx12.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_gx12.cpp @@ -406,8 +406,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), YAML_UNSIGNED( "invertLCD", 1 ), - YAML_PADDING( 1 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_nb4p.cpp b/radio/src/storage/yaml/yaml_datastructs_nb4p.cpp index 8f0fa5a8e3e..5955ec54b07 100644 --- a/radio/src/storage/yaml/yaml_datastructs_nb4p.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_nb4p.cpp @@ -438,7 +438,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), - YAML_PADDING( 4 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), + YAML_PADDING( 3 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL), YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL), diff --git a/radio/src/storage/yaml/yaml_datastructs_nv14.cpp b/radio/src/storage/yaml/yaml_datastructs_nv14.cpp index 07ba8e7721e..a96e30cf133 100644 --- a/radio/src/storage/yaml/yaml_datastructs_nv14.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_nv14.cpp @@ -445,7 +445,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), - YAML_PADDING( 4 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), + YAML_PADDING( 3 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL), YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL), diff --git a/radio/src/storage/yaml/yaml_datastructs_pa01.cpp b/radio/src/storage/yaml/yaml_datastructs_pa01.cpp index f1fb8b77671..846201b7fba 100644 --- a/radio/src/storage/yaml/yaml_datastructs_pa01.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_pa01.cpp @@ -471,7 +471,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), - YAML_PADDING( 4 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), + YAML_PADDING( 3 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL), YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL), diff --git a/radio/src/storage/yaml/yaml_datastructs_pl18.cpp b/radio/src/storage/yaml/yaml_datastructs_pl18.cpp index afcda6d4261..d00d18f1aa6 100644 --- a/radio/src/storage/yaml/yaml_datastructs_pl18.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_pl18.cpp @@ -445,7 +445,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), - YAML_PADDING( 4 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), + YAML_PADDING( 3 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL), YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL), diff --git a/radio/src/storage/yaml/yaml_datastructs_pl18u.cpp b/radio/src/storage/yaml/yaml_datastructs_pl18u.cpp index 619b433a945..6793a80d279 100644 --- a/radio/src/storage/yaml/yaml_datastructs_pl18u.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_pl18u.cpp @@ -438,7 +438,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), - YAML_PADDING( 4 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), + YAML_PADDING( 3 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL), YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL), diff --git a/radio/src/storage/yaml/yaml_datastructs_st16.cpp b/radio/src/storage/yaml/yaml_datastructs_st16.cpp index 50a8fbddb2f..058aa58aa03 100644 --- a/radio/src/storage/yaml/yaml_datastructs_st16.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_st16.cpp @@ -471,7 +471,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), - YAML_PADDING( 4 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), + YAML_PADDING( 3 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL), YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL), diff --git a/radio/src/storage/yaml/yaml_datastructs_t15.cpp b/radio/src/storage/yaml/yaml_datastructs_t15.cpp index f9ad5884f91..59e9418a3e7 100644 --- a/radio/src/storage/yaml/yaml_datastructs_t15.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_t15.cpp @@ -456,7 +456,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), - YAML_PADDING( 4 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), + YAML_PADDING( 3 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL), YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL), diff --git a/radio/src/storage/yaml/yaml_datastructs_t15pro.cpp b/radio/src/storage/yaml/yaml_datastructs_t15pro.cpp index 50a8fbddb2f..058aa58aa03 100644 --- a/radio/src/storage/yaml/yaml_datastructs_t15pro.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_t15pro.cpp @@ -471,7 +471,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), - YAML_PADDING( 4 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), + YAML_PADDING( 3 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL), YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL), diff --git a/radio/src/storage/yaml/yaml_datastructs_t20.cpp b/radio/src/storage/yaml/yaml_datastructs_t20.cpp index 42e3775cb7f..47acf972e53 100644 --- a/radio/src/storage/yaml/yaml_datastructs_t20.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_t20.cpp @@ -391,8 +391,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), YAML_UNSIGNED( "invertLCD", 1 ), - YAML_PADDING( 1 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_t22.cpp b/radio/src/storage/yaml/yaml_datastructs_t22.cpp index 4b51ff36f19..253887ecec5 100644 --- a/radio/src/storage/yaml/yaml_datastructs_t22.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_t22.cpp @@ -471,7 +471,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), - YAML_PADDING( 4 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), + YAML_PADDING( 3 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL), YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL), diff --git a/radio/src/storage/yaml/yaml_datastructs_tpro.cpp b/radio/src/storage/yaml/yaml_datastructs_tpro.cpp index 6900f12ef57..07f24dd8995 100644 --- a/radio/src/storage/yaml/yaml_datastructs_tpro.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_tpro.cpp @@ -391,8 +391,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), YAML_UNSIGNED( "invertLCD", 1 ), - YAML_PADDING( 1 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_tx15.cpp b/radio/src/storage/yaml/yaml_datastructs_tx15.cpp index 50a8fbddb2f..058aa58aa03 100644 --- a/radio/src/storage/yaml/yaml_datastructs_tx15.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_tx15.cpp @@ -471,7 +471,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), - YAML_PADDING( 4 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), + YAML_PADDING( 3 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL), YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL), diff --git a/radio/src/storage/yaml/yaml_datastructs_tx16smk3.cpp b/radio/src/storage/yaml/yaml_datastructs_tx16smk3.cpp index 5a91f4c6ac6..c083b188376 100644 --- a/radio/src/storage/yaml/yaml_datastructs_tx16smk3.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_tx16smk3.cpp @@ -472,7 +472,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), - YAML_PADDING( 4 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), + YAML_PADDING( 3 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL), YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL), diff --git a/radio/src/storage/yaml/yaml_datastructs_v12.cpp b/radio/src/storage/yaml/yaml_datastructs_v12.cpp index 97328f3dade..bfc5a885c94 100644 --- a/radio/src/storage/yaml/yaml_datastructs_v12.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_v12.cpp @@ -466,7 +466,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), - YAML_PADDING( 4 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), + YAML_PADDING( 3 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL), YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL), diff --git a/radio/src/storage/yaml/yaml_datastructs_x10.cpp b/radio/src/storage/yaml/yaml_datastructs_x10.cpp index 8cc22f3eb1d..93aff2958ed 100644 --- a/radio/src/storage/yaml/yaml_datastructs_x10.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_x10.cpp @@ -447,7 +447,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), - YAML_PADDING( 4 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), + YAML_PADDING( 3 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL), YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL), diff --git a/radio/src/storage/yaml/yaml_datastructs_x9d.cpp b/radio/src/storage/yaml/yaml_datastructs_x9d.cpp index b3ecaa27930..86d0afca491 100644 --- a/radio/src/storage/yaml/yaml_datastructs_x9d.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_x9d.cpp @@ -382,7 +382,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), - YAML_PADDING( 2 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_x9dp2019.cpp b/radio/src/storage/yaml/yaml_datastructs_x9dp2019.cpp index b3ecaa27930..86d0afca491 100644 --- a/radio/src/storage/yaml/yaml_datastructs_x9dp2019.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_x9dp2019.cpp @@ -382,7 +382,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), - YAML_PADDING( 2 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_x9e.cpp b/radio/src/storage/yaml/yaml_datastructs_x9e.cpp index 55808994c0b..5def72c269e 100644 --- a/radio/src/storage/yaml/yaml_datastructs_x9e.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_x9e.cpp @@ -382,7 +382,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), - YAML_PADDING( 2 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), + YAML_PADDING( 1 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_xlite.cpp b/radio/src/storage/yaml/yaml_datastructs_xlite.cpp index fcca68e690e..a079cbb8632 100644 --- a/radio/src/storage/yaml/yaml_datastructs_xlite.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_xlite.cpp @@ -382,8 +382,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), YAML_UNSIGNED( "invertLCD", 1 ), - YAML_PADDING( 1 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_END }; diff --git a/radio/src/storage/yaml/yaml_datastructs_xlites.cpp b/radio/src/storage/yaml/yaml_datastructs_xlites.cpp index 6c2e3fe3507..30ce8aed82b 100644 --- a/radio/src/storage/yaml/yaml_datastructs_xlites.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_xlites.cpp @@ -387,8 +387,8 @@ static const struct YamlNode struct_RadioData[] = { YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), YAML_UNSIGNED( "modelQuickSelect", 1 ), YAML_UNSIGNED( "oneLogPerDay", 1 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), YAML_UNSIGNED( "invertLCD", 1 ), - YAML_PADDING( 1 ), YAML_UNSIGNED( "pwrOffIfInactive", 8 ), YAML_END }; diff --git a/radio/src/targets/c14/hal.h b/radio/src/targets/c14/hal.h index f85cfa27753..b788b6eb188 100644 --- a/radio/src/targets/c14/hal.h +++ b/radio/src/targets/c14/hal.h @@ -478,3 +478,8 @@ UART5: TELEMETRY_USART #define USE_EXTI4_IRQ #define EXTI4_IRQ_Priority 6 #endif + +// Keys held together to toggle the keyboard lock. Override either define +// in this file to map the combo to a different pair on this target. +#define KEYS_LOCK_KEY1 KEY_SYS +#define KEYS_LOCK_KEY2 KEY_MODEL diff --git a/radio/src/targets/horus/hal.h b/radio/src/targets/horus/hal.h index b5d5c6258c3..4143114907a 100644 --- a/radio/src/targets/horus/hal.h +++ b/radio/src/targets/horus/hal.h @@ -1267,3 +1267,19 @@ #define LCD_PHYS_H LCD_H #define LCD_PHYS_W LCD_W #define LCD_DEPTH 16 + +// Keys held together to toggle the keyboard lock. Override either define +// in this file to map the combo to a different pair on this target. +#if defined(PCBX12S) +#define KEYS_LOCK_KEY1 KEY_PAGEUP +#define KEYS_LOCK_KEY2 KEY_ENTER +#elif defined(RADIO_X10) || defined(RADIO_X10E) +#define KEYS_LOCK_KEY1 KEY_PAGEDN +#define KEYS_LOCK_KEY2 KEY_SYS +#elif defined(RADIO_T15) +#define KEYS_LOCK_KEY1 KEY_SYS +#define KEYS_LOCK_KEY2 KEY_TELE +#else +#define KEYS_LOCK_KEY1 KEY_SYS +#define KEYS_LOCK_KEY2 KEY_MODEL +#endif diff --git a/radio/src/targets/st16/hal.h b/radio/src/targets/st16/hal.h index 1448483d69f..1d6fa0f17a0 100644 --- a/radio/src/targets/st16/hal.h +++ b/radio/src/targets/st16/hal.h @@ -554,3 +554,8 @@ #define LCD_PHYS_H LCD_W #define LCD_DEPTH 16 + +// Keys held together to toggle the keyboard lock. Override either define +// in this file to map the combo to a different pair on this target. +#define KEYS_LOCK_KEY1 KEY_EXIT +#define KEYS_LOCK_KEY2 KEY_ENTER diff --git a/radio/src/targets/stm32h7s78-dk/hal.h b/radio/src/targets/stm32h7s78-dk/hal.h index 1b8540a0751..fc349590334 100644 --- a/radio/src/targets/stm32h7s78-dk/hal.h +++ b/radio/src/targets/stm32h7s78-dk/hal.h @@ -369,4 +369,9 @@ #define LCD_DEPTH 16 // #define LCD_CONTRAST_DEFAULT 20 +// Keys held together to toggle the keyboard lock. Override either define +// in this file to map the combo to a different pair on this target. +#define KEYS_LOCK_KEY1 KEY_SYS +#define KEYS_LOCK_KEY2 KEY_MODEL + #endif // _HAL_H_ diff --git a/radio/src/targets/t15pro/hal.h b/radio/src/targets/t15pro/hal.h index a8b5804a0c9..6c64dff6ce1 100644 --- a/radio/src/targets/t15pro/hal.h +++ b/radio/src/targets/t15pro/hal.h @@ -498,4 +498,9 @@ USART6: EXTMODULE_USART #define LSE_DRIVE_STRENGTH RCC_LSEDRIVE_HIGH +// Keys held together to toggle the keyboard lock. Override either define +// in this file to map the combo to a different pair on this target. +#define KEYS_LOCK_KEY1 KEY_PAGEDN +#define KEYS_LOCK_KEY2 KEY_ENTER + #endif // _HAL_H_ diff --git a/radio/src/targets/t22/hal.h b/radio/src/targets/t22/hal.h index 376412d7ccf..d53ae0c7fc7 100644 --- a/radio/src/targets/t22/hal.h +++ b/radio/src/targets/t22/hal.h @@ -526,4 +526,9 @@ TIM17: ROTARY_ENCODER_TIMER #define LSE_DRIVE_STRENGTH RCC_LSEDRIVE_HIGH -#endif // _HAL_H_ \ No newline at end of file +// Keys held together to toggle the keyboard lock. Override either define +// in this file to map the combo to a different pair on this target. +#define KEYS_LOCK_KEY1 KEY_PAGEDN +#define KEYS_LOCK_KEY2 KEY_ENTER + +#endif // _HAL_H_ diff --git a/radio/src/targets/taranis/hal.h b/radio/src/targets/taranis/hal.h index 181ec2c3556..e53440a17f2 100644 --- a/radio/src/targets/taranis/hal.h +++ b/radio/src/targets/taranis/hal.h @@ -2962,3 +2962,28 @@ #define MIXER_SCHEDULER_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) #define MIXER_SCHEDULER_TIMER_IRQn TIM8_BRK_TIM12_IRQn #define MIXER_SCHEDULER_TIMER_IRQHandler TIM8_BRK_TIM12_IRQHandler + +// Keys held together to toggle the keyboard lock. Override either define +// in this file to map the combo to a different pair on this target. +#if defined(PCBXLITE) || defined(PCBXLITES) || defined(RADIO_V12) +// no combo defined +#elif defined(RADIO_ZORRO) || defined(RADIO_BOXER) || defined(RADIO_GX12) || \ + defined(RADIO_TX12) || defined(RADIO_TX12MK2) || defined(RADIO_MT12) || \ + defined(RADIO_POCKET) || defined(RADIO_T8) || defined(RADIO_COMMANDO8) || \ + defined(RADIO_V14) || defined(RADIO_V14LCD) +#define KEYS_LOCK_KEY1 KEY_SYS +#define KEYS_LOCK_KEY2 KEY_MODEL +#elif defined(RADIO_T12MAX) +#define KEYS_LOCK_KEY1 KEY_PAGEDN +#define KEYS_LOCK_KEY2 KEY_ENTER +#elif defined(RADIO_FAMILY_JUMPER_T12) +// T12, TLITE, LR3PRO — only have EXIT/ENTER/UP/DOWN/LEFT/RIGHT +#define KEYS_LOCK_KEY1 KEY_ENTER +#define KEYS_LOCK_KEY2 KEY_RIGHT +#elif defined(PCBX7) +#define KEYS_LOCK_KEY1 KEY_MENU +#define KEYS_LOCK_KEY2 KEY_ENTER +#else +#define KEYS_LOCK_KEY1 KEY_MENU +#define KEYS_LOCK_KEY2 KEY_EXIT +#endif diff --git a/radio/src/targets/tx15/hal.h b/radio/src/targets/tx15/hal.h index 48fad2e6024..67f1f7cfbdc 100644 --- a/radio/src/targets/tx15/hal.h +++ b/radio/src/targets/tx15/hal.h @@ -617,4 +617,9 @@ SAI1_Block_A: PDM_CLOCK (1 MHz bit-clock output on SAI1_CK1 / PE5, !FLYSKY_GIMBA #define LSE_DRIVE_STRENGTH RCC_LSEDRIVE_HIGH +// Keys held together to toggle the keyboard lock. Override either define +// in this file to map the combo to a different pair on this target. +#define KEYS_LOCK_KEY1 KEY_SYS +#define KEYS_LOCK_KEY2 KEY_MODEL + #endif // _HAL_H_ diff --git a/radio/src/targets/tx16smk3/hal.h b/radio/src/targets/tx16smk3/hal.h index 7383be64b82..39c6444b367 100644 --- a/radio/src/targets/tx16smk3/hal.h +++ b/radio/src/targets/tx16smk3/hal.h @@ -654,4 +654,9 @@ USART6: INTMODULE_USART #define LSE_DRIVE_STRENGTH RCC_LSEDRIVE_HIGH +// Keys held together to toggle the keyboard lock. Override either define +// in this file to map the combo to a different pair on this target. +#define KEYS_LOCK_KEY1 KEY_SYS +#define KEYS_LOCK_KEY2 KEY_MODEL + #endif // _HAL_H_ diff --git a/radio/src/tests/keys_lock.cpp b/radio/src/tests/keys_lock.cpp new file mode 100644 index 00000000000..d11ba25d4a2 --- /dev/null +++ b/radio/src/tests/keys_lock.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (C) EdgeTX + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "gtests.h" + +#if defined(KEYS_LOCK_KEY1) && defined(KEYS_LOCK_KEY2) + +// keys.cpp local; must match. +static constexpr int LOCK_POLL_DELAY = 32; +// A few extra polling cycles past the threshold to be safe against off-by-ones. +static constexpr int LOCK_POLL_HOLD = LOCK_POLL_DELAY + 4; + +static void releaseAllKeys() +{ + for (int i = 0; i < MAX_KEYS; i++) simuSetKey(i, false); + // Drain any pending events from prior tests. + while (getEvent()) {} + // Two polling cycles to let the Key debouncers see "released". + keysPollingCycle(); + keysPollingCycle(); + while (getEvent()) {} + (void)consumeKeysLockToggleEvent(); +} + +static void holdComboFor(int cycles) +{ + simuSetKey(KEYS_LOCK_KEY1, true); + simuSetKey(KEYS_LOCK_KEY2, true); + for (int i = 0; i < cycles; i++) keysPollingCycle(); +} + +class KeyLockTest : public EdgeTxTest +{ + protected: + void SetUp() override + { + EdgeTxTest::SetUp(); + g_eeGeneral.keyLockEnabled = 1; + releaseAllKeys(); + } +}; + +TEST_F(KeyLockTest, ComboTogglesLock) +{ + EXPECT_FALSE(areKeysLocked()); + + holdComboFor(LOCK_POLL_HOLD); + EXPECT_TRUE(areKeysLocked()); + EXPECT_TRUE(consumeKeysLockToggleEvent()); + EXPECT_FALSE(consumeKeysLockToggleEvent()); // consumed once + + releaseAllKeys(); + + holdComboFor(LOCK_POLL_HOLD); + EXPECT_FALSE(areKeysLocked()); + EXPECT_TRUE(consumeKeysLockToggleEvent()); +} + +TEST_F(KeyLockTest, BriefComboDoesNotToggle) +{ + // Hold for fewer cycles than the long-press threshold. + holdComboFor(LOCK_POLL_DELAY - 2); + EXPECT_FALSE(areKeysLocked()); + EXPECT_FALSE(consumeKeysLockToggleEvent()); +} + +TEST_F(KeyLockTest, DisabledFlagPreventsLocking) +{ + g_eeGeneral.keyLockEnabled = 0; + holdComboFor(LOCK_POLL_HOLD); + EXPECT_FALSE(areKeysLocked()); + EXPECT_FALSE(consumeKeysLockToggleEvent()); +} + +TEST_F(KeyLockTest, DisablingFlagWhileLockedReleasesLock) +{ + holdComboFor(LOCK_POLL_HOLD); + ASSERT_TRUE(areKeysLocked()); + (void)consumeKeysLockToggleEvent(); + releaseAllKeys(); + + // Turning the feature off must never leave the radio stuck locked. + g_eeGeneral.keyLockEnabled = 0; + keysPollingCycle(); + EXPECT_FALSE(areKeysLocked()); +} + +// Find a key not part of the lock combo to use for input-suppression tests. +static int pickProbeKey() +{ + for (int i = 0; i < MAX_KEYS; i++) { + if (i == KEYS_LOCK_KEY1 || i == KEYS_LOCK_KEY2) continue; + if (keyIsSupported((EnumKeys)i)) return i; + } + return -1; +} + +TEST_F(KeyLockTest, LockedKeyPressIsSuppressed) +{ + int probe = pickProbeKey(); + if (probe < 0) GTEST_SKIP() << "no spare key to probe with"; + + // Sanity check: while unlocked, a key press emits an event. + simuSetKey(probe, true); + keysPollingCycle(); + simuSetKey(probe, false); + keysPollingCycle(); + bool sawEvent = false; + while (event_t e = getEvent()) { (void)e; sawEvent = true; } + EXPECT_TRUE(sawEvent); + + // Lock the keys. + holdComboFor(LOCK_POLL_HOLD); + ASSERT_TRUE(areKeysLocked()); + (void)consumeKeysLockToggleEvent(); + releaseAllKeys(); + + // Now key presses must not push any events. + simuSetKey(probe, true); + keysPollingCycle(); + simuSetKey(probe, false); + keysPollingCycle(); + EXPECT_EQ(getEvent(), (event_t)0); + + // A key press while locked re-arms the toggle-event notification so the + // UI can re-show the "Keys locked" toast. + EXPECT_TRUE(consumeKeysLockToggleEvent()); +} + +#endif // KEYS_LOCK_KEY1 && KEYS_LOCK_KEY2 diff --git a/radio/src/translations/i18n/cn.h b/radio/src/translations/i18n/cn.h index b444e6e340f..cd09250998e 100644 --- a/radio/src/translations/i18n/cn.h +++ b/radio/src/translations/i18n/cn.h @@ -570,6 +570,10 @@ #define TR_KEYS_BACKLIGHT "按键背光" #define TR_BLCOLOR "颜色" #define TR_ONE_LOG_PER_DAY "One log per day" +#define TR_KEY_LOCK_FMT "Key lock (%s+%s hold)" +#define TR_KEYS_LOCKED "Keys locked" +#define TR_KEYS_LOCKED_FMT "Keys locked (%s+%s)" +#define TR_KEYS_UNLOCKED "Keys unlocked" #define TR_SPLASHSCREEN "开机图片" #define TR_PLAY_HELLO "开机语音" #define TR_PWR_ON_DELAY "开机延迟" diff --git a/radio/src/translations/i18n/cz.h b/radio/src/translations/i18n/cz.h index d0ad92f2801..6fc8ee1a8ff 100644 --- a/radio/src/translations/i18n/cz.h +++ b/radio/src/translations/i18n/cz.h @@ -573,6 +573,10 @@ #define TR_KEYS_BACKLIGHT "Podsvětlení kláves" #define TR_BLCOLOR "Barva" #define TR_ONE_LOG_PER_DAY "One log per day" +#define TR_KEY_LOCK_FMT "Key lock (%s+%s hold)" +#define TR_KEYS_LOCKED "Keys locked" +#define TR_KEYS_LOCKED_FMT "Keys locked (%s+%s)" +#define TR_KEYS_UNLOCKED "Keys unlocked" #define TR_SPLASHSCREEN TR("úvodní logo", "Zobrazit úvodní logo") #define TR_PLAY_HELLO "Zvuk při spuštění" #define TR_PWR_ON_DELAY "Zpoždění zapnutí" diff --git a/radio/src/translations/i18n/da.h b/radio/src/translations/i18n/da.h index ddb608cdb63..24528f91f93 100644 --- a/radio/src/translations/i18n/da.h +++ b/radio/src/translations/i18n/da.h @@ -575,6 +575,10 @@ #define TR_KEYS_BACKLIGHT "Taster klarhed" #define TR_BLCOLOR "Farve" #define TR_ONE_LOG_PER_DAY "One log per day" +#define TR_KEY_LOCK_FMT "Key lock (%s+%s hold)" +#define TR_KEYS_LOCKED "Keys locked" +#define TR_KEYS_LOCKED_FMT "Keys locked (%s+%s)" +#define TR_KEYS_UNLOCKED "Keys unlocked" #define TR_SPLASHSCREEN "Start skærm" #define TR_PLAY_HELLO "Startop lyd" #define TR_PWR_ON_DELAY "Forsinkelse ved tænd" diff --git a/radio/src/translations/i18n/de.h b/radio/src/translations/i18n/de.h index dded51e14af..c023c1bec1f 100644 --- a/radio/src/translations/i18n/de.h +++ b/radio/src/translations/i18n/de.h @@ -571,6 +571,10 @@ #define TR_KEYS_BACKLIGHT "Tastenbeleucht." #define TR_BLCOLOR "Farbe" #define TR_ONE_LOG_PER_DAY "One log per day" +#define TR_KEY_LOCK_FMT "Key lock (%s+%s hold)" +#define TR_KEYS_LOCKED "Keys locked" +#define TR_KEYS_LOCKED_FMT "Keys locked (%s+%s)" +#define TR_KEYS_UNLOCKED "Keys unlocked" #define TR_SPLASHSCREEN TR("Startbild Ein", "Startbild Anzeigedauer") #define TR_PLAY_HELLO "Startton abspielen" #define TR_PWR_ON_DELAY TR("PWR EIN Verzög.", "Einschaltverzögerung") diff --git a/radio/src/translations/i18n/en.h b/radio/src/translations/i18n/en.h index 09aa435ce82..afeb36a80ad 100644 --- a/radio/src/translations/i18n/en.h +++ b/radio/src/translations/i18n/en.h @@ -571,6 +571,10 @@ #define TR_KEYS_BACKLIGHT "Keys backlight" #define TR_BLCOLOR "Color" #define TR_ONE_LOG_PER_DAY "One log per day" +#define TR_KEY_LOCK_FMT "Key lock (%s+%s hold)" +#define TR_KEYS_LOCKED "Keys locked" +#define TR_KEYS_LOCKED_FMT "Keys locked (%s+%s)" +#define TR_KEYS_UNLOCKED "Keys unlocked" #define TR_SPLASHSCREEN "Splash screen" #define TR_PLAY_HELLO "Startup Sound" #define TR_PWR_ON_DELAY "Pwr On delay" diff --git a/radio/src/translations/i18n/es.h b/radio/src/translations/i18n/es.h index 448b57ad55e..a6442768c42 100644 --- a/radio/src/translations/i18n/es.h +++ b/radio/src/translations/i18n/es.h @@ -569,6 +569,10 @@ #define TR_KEYS_BACKLIGHT "Keys backlight" #define TR_BLCOLOR "Color" #define TR_ONE_LOG_PER_DAY "One log per day" +#define TR_KEY_LOCK_FMT "Key lock (%s+%s hold)" +#define TR_KEYS_LOCKED "Keys locked" +#define TR_KEYS_LOCKED_FMT "Keys locked (%s+%s)" +#define TR_KEYS_UNLOCKED "Keys unlocked" #define TR_SPLASHSCREEN "Pantalla inicio" #define TR_PLAY_HELLO "Startup Sound" #define TR_PWR_ON_DELAY TR("Atraso On", "Atraso encendido") diff --git a/radio/src/translations/i18n/fi.h b/radio/src/translations/i18n/fi.h index 13fca2ab9fd..e0d38978cdc 100644 --- a/radio/src/translations/i18n/fi.h +++ b/radio/src/translations/i18n/fi.h @@ -570,6 +570,10 @@ #define TR_KEYS_BACKLIGHT "Keys backlight" #define TR_BLCOLOR "Color" #define TR_ONE_LOG_PER_DAY "One log per day" +#define TR_KEY_LOCK_FMT "Key lock (%s+%s hold)" +#define TR_KEYS_LOCKED "Keys locked" +#define TR_KEYS_LOCKED_FMT "Keys locked (%s+%s)" +#define TR_KEYS_UNLOCKED "Keys unlocked" #define TR_SPLASHSCREEN "Splash screen" #define TR_PLAY_HELLO "Startup Sound" #define TR_PWR_ON_DELAY "Pwr On delay" diff --git a/radio/src/translations/i18n/fr.h b/radio/src/translations/i18n/fr.h index 5cbf215161b..a7ce7be96c5 100644 --- a/radio/src/translations/i18n/fr.h +++ b/radio/src/translations/i18n/fr.h @@ -574,6 +574,10 @@ #define TR_KEYS_BACKLIGHT "Rétroéclairage touches" #define TR_BLCOLOR "Couleur" #define TR_ONE_LOG_PER_DAY "Un log par jour" +#define TR_KEY_LOCK_FMT "Key lock (%s+%s hold)" +#define TR_KEYS_LOCKED "Keys locked" +#define TR_KEYS_LOCKED_FMT "Keys locked (%s+%s)" +#define TR_KEYS_UNLOCKED "Keys unlocked" #define TR_SPLASHSCREEN "Écran d'accueil" #define TR_PLAY_HELLO "Son de démarrage" #define TR_PWR_ON_DELAY "Délai btn ON" diff --git a/radio/src/translations/i18n/he.h b/radio/src/translations/i18n/he.h index 6fdf5072622..0054bc6f5ab 100644 --- a/radio/src/translations/i18n/he.h +++ b/radio/src/translations/i18n/he.h @@ -574,6 +574,10 @@ #define TR_KEYS_BACKLIGHT "תאורת לחצנים" #define TR_BLCOLOR "צבע" #define TR_ONE_LOG_PER_DAY "One log per day" +#define TR_KEY_LOCK_FMT "Key lock (%s+%s hold)" +#define TR_KEYS_LOCKED "Keys locked" +#define TR_KEYS_LOCKED_FMT "Keys locked (%s+%s)" +#define TR_KEYS_UNLOCKED "Keys unlocked" #define TR_SPLASHSCREEN "מסך פתיחה" #define TR_PLAY_HELLO "צליל אתחול" #define TR_PWR_ON_DELAY "השהיית הפעלה פעיל" diff --git a/radio/src/translations/i18n/it.h b/radio/src/translations/i18n/it.h index 4d07ce8491e..29beaf6fbff 100644 --- a/radio/src/translations/i18n/it.h +++ b/radio/src/translations/i18n/it.h @@ -571,6 +571,10 @@ #define TR_KEYS_BACKLIGHT "Luce tasti" #define TR_BLCOLOR "Colore" #define TR_ONE_LOG_PER_DAY "Un log al giorno" +#define TR_KEY_LOCK_FMT "Key lock (%s+%s hold)" +#define TR_KEYS_LOCKED "Keys locked" +#define TR_KEYS_LOCKED_FMT "Keys locked (%s+%s)" +#define TR_KEYS_UNLOCKED "Keys unlocked" #define TR_SPLASHSCREEN TR("Sch. avvio", "Schermata d'avvio") #define TR_PLAY_HELLO "Suono all'accensione" #define TR_PWR_ON_DELAY "Rit. accens." diff --git a/radio/src/translations/i18n/jp.h b/radio/src/translations/i18n/jp.h index e967f597b1c..19c762041fc 100644 --- a/radio/src/translations/i18n/jp.h +++ b/radio/src/translations/i18n/jp.h @@ -570,6 +570,10 @@ #define TR_KEYS_BACKLIGHT "キー バックライト" #define TR_BLCOLOR "カラー" #define TR_ONE_LOG_PER_DAY "One log per day" +#define TR_KEY_LOCK_FMT "Key lock (%s+%s hold)" +#define TR_KEYS_LOCKED "Keys locked" +#define TR_KEYS_LOCKED_FMT "Keys locked (%s+%s)" +#define TR_KEYS_UNLOCKED "Keys unlocked" #define TR_SPLASHSCREEN "起動イメージ" #define TR_PLAY_HELLO "起動時サウンド" #define TR_PWR_ON_DELAY "電源ON遅延" diff --git a/radio/src/translations/i18n/ko.h b/radio/src/translations/i18n/ko.h index c200015707e..daeded79943 100644 --- a/radio/src/translations/i18n/ko.h +++ b/radio/src/translations/i18n/ko.h @@ -580,6 +580,10 @@ #define TR_KEYS_BACKLIGHT "키 백라이트" #define TR_BLCOLOR "색상" #define TR_ONE_LOG_PER_DAY "One log per day" +#define TR_KEY_LOCK_FMT "Key lock (%s+%s hold)" +#define TR_KEYS_LOCKED "Keys locked" +#define TR_KEYS_LOCKED_FMT "Keys locked (%s+%s)" +#define TR_KEYS_UNLOCKED "Keys unlocked" #define TR_SPLASHSCREEN "시작화면" #define TR_PLAY_HELLO "시작 사운드" diff --git a/radio/src/translations/i18n/nl.h b/radio/src/translations/i18n/nl.h index 8b25d0f4ba2..6716d80e40c 100644 --- a/radio/src/translations/i18n/nl.h +++ b/radio/src/translations/i18n/nl.h @@ -572,6 +572,10 @@ #define TR_KEYS_BACKLIGHT "Keys backlight" #define TR_BLCOLOR "Kleur" #define TR_ONE_LOG_PER_DAY "One log per day" +#define TR_KEY_LOCK_FMT "Key lock (%s+%s hold)" +#define TR_KEYS_LOCKED "Keys locked" +#define TR_KEYS_LOCKED_FMT "Keys locked (%s+%s)" +#define TR_KEYS_UNLOCKED "Keys unlocked" #define TR_SPLASHSCREEN "Startscherm Aan" #define TR_PLAY_HELLO "Startup Sound" #define TR_PWR_ON_DELAY "Pwr On delay" diff --git a/radio/src/translations/i18n/pl.h b/radio/src/translations/i18n/pl.h index abeffe3e675..f3288da5d7c 100644 --- a/radio/src/translations/i18n/pl.h +++ b/radio/src/translations/i18n/pl.h @@ -570,6 +570,10 @@ #define TR_KEYS_BACKLIGHT "Podśw. przycisków" #define TR_BLCOLOR "Kolor" #define TR_ONE_LOG_PER_DAY "One log per day" +#define TR_KEY_LOCK_FMT "Key lock (%s+%s hold)" +#define TR_KEYS_LOCKED "Keys locked" +#define TR_KEYS_LOCKED_FMT "Keys locked (%s+%s)" +#define TR_KEYS_UNLOCKED "Keys unlocked" #define TR_SPLASHSCREEN "Logo ekranu" #define TR_PLAY_HELLO "Dźwięk uruchomienia" #define TR_PWR_ON_DELAY "Pwr On delay" diff --git a/radio/src/translations/i18n/pt.h b/radio/src/translations/i18n/pt.h index 4fac68f62ce..d5f597c6770 100644 --- a/radio/src/translations/i18n/pt.h +++ b/radio/src/translations/i18n/pt.h @@ -571,6 +571,10 @@ #define TR_KEYS_BACKLIGHT "Keys backlight" #define TR_BLCOLOR "Cor" #define TR_ONE_LOG_PER_DAY "One log per day" +#define TR_KEY_LOCK_FMT "Key lock (%s+%s hold)" +#define TR_KEYS_LOCKED "Keys locked" +#define TR_KEYS_LOCKED_FMT "Keys locked (%s+%s)" +#define TR_KEYS_UNLOCKED "Keys unlocked" #define TR_SPLASHSCREEN "Tela abertura" #define TR_PLAY_HELLO "Som ao ligar" #define TR_PWR_ON_DELAY "Delay para LIGA" diff --git a/radio/src/translations/i18n/ru.h b/radio/src/translations/i18n/ru.h index fa16867fdc1..2c4003c1133 100644 --- a/radio/src/translations/i18n/ru.h +++ b/radio/src/translations/i18n/ru.h @@ -573,6 +573,10 @@ #define TR_KEYS_BACKLIGHT "Подсветка клавиш" #define TR_BLCOLOR "Цвет" #define TR_ONE_LOG_PER_DAY "One log per day" +#define TR_KEY_LOCK_FMT "Key lock (%s+%s hold)" +#define TR_KEYS_LOCKED "Keys locked" +#define TR_KEYS_LOCKED_FMT "Keys locked (%s+%s)" +#define TR_KEYS_UNLOCKED "Keys unlocked" #define TR_SPLASHSCREEN "Заставка" #define TR_PLAY_HELLO "Звук запуска" #define TR_PWR_ON_DELAY "Время включ" diff --git a/radio/src/translations/i18n/se.h b/radio/src/translations/i18n/se.h index 68ee79fc6b5..beb27fd3cdc 100644 --- a/radio/src/translations/i18n/se.h +++ b/radio/src/translations/i18n/se.h @@ -573,6 +573,10 @@ #define TR_BLOFFBRIGHTNESS "Ljusstyrka av" #define TR_KEYS_BACKLIGHT "Tangentbelysning" #define TR_ONE_LOG_PER_DAY "En logg per dag" +#define TR_KEY_LOCK_FMT "Key lock (%s+%s hold)" +#define TR_KEYS_LOCKED "Keys locked" +#define TR_KEYS_LOCKED_FMT "Keys locked (%s+%s)" +#define TR_KEYS_UNLOCKED "Keys unlocked" #define TR_SPLASHSCREEN "Startbild" #define TR_PLAY_HELLO "Startljud" #define TR_PWR_ON_DELAY "Fördröj start" diff --git a/radio/src/translations/i18n/tw.h b/radio/src/translations/i18n/tw.h index 36012452a2a..29140891611 100644 --- a/radio/src/translations/i18n/tw.h +++ b/radio/src/translations/i18n/tw.h @@ -568,6 +568,10 @@ #define TR_KEYS_BACKLIGHT "按鍵背光" #define TR_BLCOLOR "顏色" #define TR_ONE_LOG_PER_DAY "One log per day" +#define TR_KEY_LOCK_FMT "Key lock (%s+%s hold)" +#define TR_KEYS_LOCKED "Keys locked" +#define TR_KEYS_LOCKED_FMT "Keys locked (%s+%s)" +#define TR_KEYS_UNLOCKED "Keys unlocked" #define TR_SPLASHSCREEN "開機圖片" #define TR_PLAY_HELLO "開機語音" #define TR_PWR_ON_DELAY "開機延遲" diff --git a/radio/src/translations/i18n/ua.h b/radio/src/translations/i18n/ua.h index 28049d395f7..f517cbe2438 100644 --- a/radio/src/translations/i18n/ua.h +++ b/radio/src/translations/i18n/ua.h @@ -572,6 +572,10 @@ #define TR_KEYS_BACKLIGHT "Яскравість кнопки" #define TR_BLCOLOR "Колір" #define TR_ONE_LOG_PER_DAY "One log per day" +#define TR_KEY_LOCK_FMT "Key lock (%s+%s hold)" +#define TR_KEYS_LOCKED "Keys locked" +#define TR_KEYS_LOCKED_FMT "Keys locked (%s+%s)" +#define TR_KEYS_UNLOCKED "Keys unlocked" #define TR_SPLASHSCREEN "Заставка" #define TR_PLAY_HELLO "Звук запуску" #define TR_PWR_ON_DELAY "Затримка увімкн." diff --git a/radio/src/translations/sim_string_list.h b/radio/src/translations/sim_string_list.h index 872abe0b443..a35b7861d8f 100644 --- a/radio/src/translations/sim_string_list.h +++ b/radio/src/translations/sim_string_list.h @@ -1165,3 +1165,7 @@ #define STR_VVARIOCENTER currentLangStrings->STR_VVARIOCENTER #define STR_XJT_ACCST_RF_PROTOCOLS currentLangStrings->STR_XJT_ACCST_RF_PROTOCOLS #define STR_ONE_LOG_PER_DAY currentLangStrings->STR_ONE_LOG_PER_DAY +#define STR_KEY_LOCK_FMT currentLangStrings->STR_KEY_LOCK_FMT +#define STR_KEYS_LOCKED currentLangStrings->STR_KEYS_LOCKED +#define STR_KEYS_LOCKED_FMT currentLangStrings->STR_KEYS_LOCKED_FMT +#define STR_KEYS_UNLOCKED currentLangStrings->STR_KEYS_UNLOCKED diff --git a/radio/src/translations/string_list.h b/radio/src/translations/string_list.h index c219893d851..3a624410ba2 100644 --- a/radio/src/translations/string_list.h +++ b/radio/src/translations/string_list.h @@ -953,6 +953,10 @@ STR(SPECTRUM_ANALYSER_EXT) STR(SPECTRUM_ANALYSER_INT) STR(SPLASHSCREEN) STR(ONE_LOG_PER_DAY) +STR(KEY_LOCK_FMT) +STR(KEYS_LOCKED) +STR(KEYS_LOCKED_FMT) +STR(KEYS_UNLOCKED) STR(SPORT_UPDATE_POWER_MODE) STR(SRC_BATT) STR(SRC_GPS)