fix(keyboard): shortcuts, keep an empty binding list on re-enable

setEnabled seeded the defaults whenever the binding list was empty, so a
user who cleared every binding got all defaults back after disable and
enable. Seed only when the config has never held a bindings list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ra4my61t8q1FN5n59wB16D
This commit is contained in:
rustdesk
2026-09-23 18:00:53 +08:00
co-authored by Claude Opus 5.5
parent c133948a91
commit 228bc7e586
3 changed files with 23 additions and 5 deletions
@@ -35,6 +35,12 @@ Set<String> shortcutModSetFrom(dynamic rawMods) {
return rawMods.whereType<String>().toSet();
}
/// Whether enabling shortcuts should seed the default bindings. Only a config
/// that has never held a bindings list is seeded; an empty list means the
/// user cleared every binding and must stay empty.
bool shouldSeedDefaultShortcutBindings(Map<String, dynamic> config) =>
!config.containsKey('bindings');
bool isSwitchTabShortcutAction(String? actionId) {
return actionId == kShortcutActionSwitchTabNext ||
actionId == kShortcutActionSwitchTabPrev;
+4 -5
View File
@@ -135,7 +135,7 @@ class ShortcutModel {
/// Flip the master `enabled` flag and persist. On the first enable we seed
/// the default bindings so common combos work out of the box; otherwise we
/// preserve whatever the user already has. Refreshes the matcher cache so
/// preserve whatever the user already has, an empty list included. Refreshes the matcher cache so
/// the change takes effect immediately (Rust on native, JS via the bridge
/// on Web).
static Future<void> setEnabled(bool v) async {
@@ -149,14 +149,13 @@ class ShortcutModel {
}
}
json['enabled'] = v;
final list = shortcutBindingMapsFrom(json['bindings']);
if (v && list.isEmpty) {
if (v && shouldSeedDefaultShortcutBindings(json)) {
json['bindings'] = filterDefaultBindingsForPlatform(
jsonDecode(bind.mainGetDefaultKeyboardShortcuts()) as List,
currentPlatformCapabilities(),
);
} else {
json['bindings'] = list;
} else if (json.containsKey('bindings')) {
json['bindings'] = shortcutBindingMapsFrom(json['bindings']);
}
await bind.mainSetLocalOption(
key: kShortcutLocalConfigKey, value: jsonEncode(json));
+13
View File
@@ -397,6 +397,19 @@ void main() {
expect(physicalKeyName(PhysicalKeyboardKey.numpad1), isNull);
});
test('enable seeds defaults only for a config without bindings', () {
expect(shouldSeedDefaultShortcutBindings(<String, dynamic>{}), isTrue);
expect(
shouldSeedDefaultShortcutBindings(
<String, dynamic>{'enabled': false, 'pass_through': true}),
isTrue);
// The user cleared every binding: re-enabling must not bring defaults back.
expect(
shouldSeedDefaultShortcutBindings(
<String, dynamic>{'enabled': false, 'bindings': <dynamic>[]}),
isFalse);
});
test('non-US layouts record and match the physical key', () {
// AZERTY: the key labelled "A" sits where US QWERTY has Q. The native
// matcher only sees the physical position (USB HID usage), so the