mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-05-07 14:48:11 +03:00
fix web break introduced in 38f130071 fix(linux): enable mouse side buttons in remote sessions (#14848)
This commit is contained in:
@@ -16,16 +16,43 @@ import 'package:get/get.dart';
|
||||
|
||||
bool isEditOsPassword = false;
|
||||
|
||||
/// Action IDs that `toolbarControls` is the sole registrar for. Each call to
|
||||
/// `toolbarControls` (e.g. opening the toolbar menu after a permission was
|
||||
/// revoked or a state changed) wipes these so a previously-registered closure
|
||||
/// can't outlive the menu entry that owns it. The for-loop at the bottom of
|
||||
/// `toolbarControls` then re-registers whichever entries are still present in
|
||||
/// the rebuilt menu list.
|
||||
///
|
||||
/// Actions registered elsewhere — `registerSessionShortcutActions` on desktop
|
||||
/// owns toggle_recording, fullscreen, switch_display, switch_tab, close_tab,
|
||||
/// toggle_toolbar — MUST NOT appear here, otherwise this list would clobber
|
||||
/// their registration on every menu rebuild.
|
||||
///
|
||||
/// `kShortcutActionToggleRecording` is platform-conditional (mobile-only —
|
||||
/// see the `!(isDesktop || isWeb)` guard in `toolbarControls`). It is handled
|
||||
/// separately in the unregister pass rather than appearing in this const list.
|
||||
const _kToolbarOwnedActionIds = <String>[
|
||||
kShortcutActionSendCtrlAltDel,
|
||||
kShortcutActionRestartRemote,
|
||||
kShortcutActionInsertLock,
|
||||
kShortcutActionToggleBlockInput,
|
||||
kShortcutActionSwitchSides,
|
||||
kShortcutActionRefresh,
|
||||
kShortcutActionScreenshot,
|
||||
];
|
||||
|
||||
class TTextMenu {
|
||||
final Widget child;
|
||||
final VoidCallback? onPressed;
|
||||
Widget? trailingIcon;
|
||||
bool divider;
|
||||
final String? actionId;
|
||||
TTextMenu(
|
||||
{required this.child,
|
||||
required this.onPressed,
|
||||
this.trailingIcon,
|
||||
this.divider = false});
|
||||
this.divider = false,
|
||||
this.actionId});
|
||||
|
||||
Widget getChild() {
|
||||
if (trailingIcon != null) {
|
||||
@@ -94,6 +121,20 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
|
||||
final sessionId = ffi.sessionId;
|
||||
final isDefaultConn = ffi.connType == ConnType.defaultConn;
|
||||
|
||||
// Wipe everything `toolbarControls` could have registered last call so
|
||||
// stale closures (e.g. for a menu entry whose permission has since been
|
||||
// revoked) don't outlive the menu rebuild. See _kToolbarOwnedActionIds.
|
||||
for (final actionId in _kToolbarOwnedActionIds) {
|
||||
ffi.shortcutModel.unregister(actionId);
|
||||
}
|
||||
// toggle_recording is platform-conditional — toolbarControls only builds
|
||||
// the menu entry on `!(isDesktop || isWeb)`. On desktop the registration
|
||||
// is owned by `registerSessionShortcutActions` and must NOT be touched
|
||||
// here. See the recording menu entry below.
|
||||
if (!(isDesktop || isWeb)) {
|
||||
ffi.shortcutModel.unregister(kShortcutActionToggleRecording);
|
||||
}
|
||||
|
||||
List<TTextMenu> v = [];
|
||||
// elevation
|
||||
if (isDefaultConn &&
|
||||
@@ -229,7 +270,8 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
|
||||
v.add(
|
||||
TTextMenu(
|
||||
child: Text('${translate("Insert Ctrl + Alt + Del")}'),
|
||||
onPressed: () => bind.sessionCtrlAltDel(sessionId: sessionId)),
|
||||
onPressed: () => bind.sessionCtrlAltDel(sessionId: sessionId),
|
||||
actionId: kShortcutActionSendCtrlAltDel),
|
||||
);
|
||||
}
|
||||
// restart
|
||||
@@ -242,7 +284,8 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
|
||||
TTextMenu(
|
||||
child: Text(translate('Restart remote device')),
|
||||
onPressed: () =>
|
||||
showRestartRemoteDevice(pi, id, sessionId, ffi.dialogManager)),
|
||||
showRestartRemoteDevice(pi, id, sessionId, ffi.dialogManager),
|
||||
actionId: kShortcutActionRestartRemote),
|
||||
);
|
||||
}
|
||||
// insertLock
|
||||
@@ -250,7 +293,8 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
|
||||
v.add(
|
||||
TTextMenu(
|
||||
child: Text(translate('Insert Lock')),
|
||||
onPressed: () => bind.sessionLockScreen(sessionId: sessionId)),
|
||||
onPressed: () => bind.sessionLockScreen(sessionId: sessionId),
|
||||
actionId: kShortcutActionInsertLock),
|
||||
);
|
||||
}
|
||||
// blockUserInput
|
||||
@@ -268,7 +312,8 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
|
||||
sessionId: sessionId,
|
||||
value: '${blockInput.value ? 'un' : ''}block-input');
|
||||
blockInput.value = !blockInput.value;
|
||||
}));
|
||||
},
|
||||
actionId: kShortcutActionToggleBlockInput));
|
||||
}
|
||||
// switchSides
|
||||
if (isDefaultConn &&
|
||||
@@ -280,13 +325,15 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
|
||||
v.add(TTextMenu(
|
||||
child: Text(translate('Switch Sides')),
|
||||
onPressed: () =>
|
||||
showConfirmSwitchSidesDialog(sessionId, id, ffi.dialogManager)));
|
||||
showConfirmSwitchSidesDialog(sessionId, id, ffi.dialogManager),
|
||||
actionId: kShortcutActionSwitchSides));
|
||||
}
|
||||
// refresh
|
||||
if (pi.version.isNotEmpty) {
|
||||
v.add(TTextMenu(
|
||||
child: Text(translate('Refresh')),
|
||||
onPressed: () => sessionRefreshVideo(sessionId, pi),
|
||||
actionId: kShortcutActionRefresh,
|
||||
));
|
||||
}
|
||||
// record
|
||||
@@ -308,7 +355,8 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
|
||||
)
|
||||
],
|
||||
),
|
||||
onPressed: () => ffi.recordingModel.toggle()));
|
||||
onPressed: () => ffi.recordingModel.toggle(),
|
||||
actionId: kShortcutActionToggleRecording));
|
||||
}
|
||||
|
||||
// to-do:
|
||||
@@ -325,6 +373,14 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
|
||||
onPressed: ffi.ffiModel.timerScreenshot != null
|
||||
? null
|
||||
: () {
|
||||
// Live cooldown check: the menu rebuilds onPressed=null
|
||||
// whenever toolbarControls runs and finds timerScreenshot
|
||||
// != null, but the keyboard-shortcut callback holds onto
|
||||
// the originally-enabled closure across cooldown periods
|
||||
// (toolbarControls only re-runs on menu open). Without
|
||||
// this guard the second shortcut press during the 30s
|
||||
// cooldown still fires sessionTakeScreenshot.
|
||||
if (ffi.ffiModel.timerScreenshot != null) return;
|
||||
if (pi.currentDisplay == kAllDisplayValue) {
|
||||
msgBox(
|
||||
sessionId,
|
||||
@@ -342,6 +398,7 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
|
||||
});
|
||||
}
|
||||
},
|
||||
actionId: kShortcutActionScreenshot,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -352,6 +409,28 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
|
||||
onPressed: () => onCopyFingerprint(FingerprintState.find(id).value),
|
||||
));
|
||||
}
|
||||
// Register tagged callbacks with the shortcut model so global keyboard
|
||||
// shortcuts can dispatch the same actions as the toolbar menu items.
|
||||
//
|
||||
// For action IDs already cleared at the top of this function (i.e. those
|
||||
// in [_kToolbarOwnedActionIds] plus the conditional toggle_recording),
|
||||
// the `else` branch below is a redundant idempotent no-op — `unregister`
|
||||
// just calls `Map.remove` on something already absent.
|
||||
//
|
||||
// The branch is kept as **defense in depth** for the case where a future
|
||||
// contributor tags a menu item with an actionId that they forget to add
|
||||
// to [_kToolbarOwnedActionIds]: without this `else`, the original
|
||||
// "stale-closure-outlives-disabled-state" bug (e.g. Screenshot cooldown
|
||||
// bypass) would silently come back for that new action only.
|
||||
for (final menu in v) {
|
||||
final actionId = menu.actionId;
|
||||
if (actionId == null) continue;
|
||||
if (menu.onPressed != null) {
|
||||
ffi.shortcutModel.register(actionId, menu.onPressed!);
|
||||
} else {
|
||||
ffi.shortcutModel.unregister(actionId);
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user