mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-05-11 16:48:11 +03:00
feat(keyboard): shortcuts, debug web
Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
@@ -15,7 +15,9 @@ import 'package:get/get.dart';
|
|||||||
|
|
||||||
import '../../models/model.dart';
|
import '../../models/model.dart';
|
||||||
import '../../models/platform_model.dart';
|
import '../../models/platform_model.dart';
|
||||||
|
import '../../models/shortcut_model.dart';
|
||||||
import '../../models/state_model.dart';
|
import '../../models/state_model.dart';
|
||||||
|
import '../common/widgets/keyboard_shortcuts/shortcut_utils.dart';
|
||||||
import 'input_modifier_utils.dart';
|
import 'input_modifier_utils.dart';
|
||||||
import 'relative_mouse_model.dart';
|
import 'relative_mouse_model.dart';
|
||||||
import '../common.dart';
|
import '../common.dart';
|
||||||
@@ -826,6 +828,9 @@ class InputModel {
|
|||||||
return KeyEventResult.ignored;
|
return KeyEventResult.ignored;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (_tryDispatchWebFlutterShortcut(e)) {
|
||||||
|
return KeyEventResult.handled;
|
||||||
|
}
|
||||||
if (isWindows || isLinux) {
|
if (isWindows || isLinux) {
|
||||||
// Ignore meta keys. Because flutter window will loose focus if meta key is pressed.
|
// Ignore meta keys. Because flutter window will loose focus if meta key is pressed.
|
||||||
if (e.physicalKey == PhysicalKeyboardKey.metaLeft ||
|
if (e.physicalKey == PhysicalKeyboardKey.metaLeft ||
|
||||||
@@ -920,6 +925,53 @@ class InputModel {
|
|||||||
return KeyEventResult.handled;
|
return KeyEventResult.handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _tryDispatchWebFlutterShortcut(KeyEvent e) {
|
||||||
|
if (!isWeb || !isInputSourceFlutter) return false;
|
||||||
|
if (e is! KeyDownEvent && e is! KeyRepeatEvent) return false;
|
||||||
|
if (!ShortcutModel.isEnabled() || ShortcutModel.isPassThrough()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final keyName = logicalKeyName(e.logicalKey);
|
||||||
|
if (keyName == null) return false;
|
||||||
|
final mods = canonicalShortcutModsForSave(_webFlutterShortcutMods());
|
||||||
|
final action = _matchWebFlutterShortcut(keyName, mods);
|
||||||
|
if (action == null) return false;
|
||||||
|
if (e is KeyDownEvent) {
|
||||||
|
parent.target?.shortcutModel.onTriggered(action);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> _webFlutterShortcutMods() {
|
||||||
|
final keyboard = HardwareKeyboard.instance;
|
||||||
|
final mods = <String>{};
|
||||||
|
if (isMacOS || isIOS || isWebOnMacOs) {
|
||||||
|
if (keyboard.isMetaPressed) mods.add('primary');
|
||||||
|
if (keyboard.isControlPressed) mods.add('ctrl');
|
||||||
|
} else if (keyboard.isControlPressed) {
|
||||||
|
mods.add('primary');
|
||||||
|
}
|
||||||
|
if (keyboard.isAltPressed) mods.add('alt');
|
||||||
|
if (keyboard.isShiftPressed) mods.add('shift');
|
||||||
|
return mods;
|
||||||
|
}
|
||||||
|
|
||||||
|
String? _matchWebFlutterShortcut(String keyName, List<String> mods) {
|
||||||
|
for (final binding in ShortcutModel.readBindings()) {
|
||||||
|
final action = binding['action'];
|
||||||
|
final key = binding['key'];
|
||||||
|
final bindingMods =
|
||||||
|
canonicalShortcutModsForSave(shortcutModSetFrom(binding['mods']));
|
||||||
|
if (action is String &&
|
||||||
|
key == keyName &&
|
||||||
|
bindingMods.isNotEmpty &&
|
||||||
|
listEquals(bindingMods, mods)) {
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// Send Key Event
|
/// Send Key Event
|
||||||
void newKeyboardMode(
|
void newKeyboardMode(
|
||||||
String character, int usbHid, bool down, bool iosCapsLock) {
|
String character, int usbHid, bool down, bool iosCapsLock) {
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ typedef ShortcutCallback = FutureOr<void> Function();
|
|||||||
/// via [onTriggered], which runs whatever callback the toolbar / menu
|
/// via [onTriggered], which runs whatever callback the toolbar / menu
|
||||||
/// builders previously registered for that action id.
|
/// builders previously registered for that action id.
|
||||||
class ShortcutModel {
|
class ShortcutModel {
|
||||||
|
static WeakReference<ShortcutModel>? _activeWebModel;
|
||||||
|
|
||||||
final WeakReference<FFI> parent;
|
final WeakReference<FFI> parent;
|
||||||
final Map<String, ShortcutCallback> _callbacks = {};
|
final Map<String, ShortcutCallback> _callbacks = {};
|
||||||
|
|
||||||
@@ -35,6 +37,7 @@ class ShortcutModel {
|
|||||||
/// matched shortcut fires.
|
/// matched shortcut fires.
|
||||||
void register(String actionId, ShortcutCallback callback) {
|
void register(String actionId, ShortcutCallback callback) {
|
||||||
_callbacks[actionId] = callback;
|
_callbacks[actionId] = callback;
|
||||||
|
_activeWebModel = WeakReference(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unregister(String actionId) {
|
void unregister(String actionId) {
|
||||||
@@ -43,6 +46,18 @@ class ShortcutModel {
|
|||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
_callbacks.clear();
|
_callbacks.clear();
|
||||||
|
if (identical(_activeWebModel?.target, this)) {
|
||||||
|
_activeWebModel = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onWebTriggered(String actionId) {
|
||||||
|
final model = _activeWebModel?.target;
|
||||||
|
if (model != null) {
|
||||||
|
model.onTriggered(actionId);
|
||||||
|
} else {
|
||||||
|
debugPrint('shortcut_triggered: no active web shortcut model');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called by the session event listener when a `shortcut_triggered` event
|
/// Called by the session event listener when a `shortcut_triggered` event
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ class PlatformFFI {
|
|||||||
gFFI.dialogManager.dismissAll();
|
gFFI.dialogManager.dismissAll();
|
||||||
closeConnection();
|
closeConnection();
|
||||||
};
|
};
|
||||||
|
await _ffiBind.mainInit(appDir: '');
|
||||||
context.callMethod('init');
|
context.callMethod('init');
|
||||||
version = getByName('version');
|
version = getByName('version');
|
||||||
window.onContextMenu.listen((event) {
|
window.onContextMenu.listen((event) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import 'package:uuid/uuid.dart';
|
|||||||
import 'dart:html' as html;
|
import 'dart:html' as html;
|
||||||
|
|
||||||
import 'package:flutter_hbb/consts.dart';
|
import 'package:flutter_hbb/consts.dart';
|
||||||
import 'package:flutter_hbb/common.dart' as common;
|
import 'package:flutter_hbb/models/shortcut_model.dart';
|
||||||
|
|
||||||
final _privateConstructorUsedError = UnsupportedError(
|
final _privateConstructorUsedError = UnsupportedError(
|
||||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||||
@@ -1195,10 +1195,11 @@ class RustdeskImpl {
|
|||||||
// JS -> Dart shortcut bridge. The matcher in flutter/web/js/src/
|
// JS -> Dart shortcut bridge. The matcher in flutter/web/js/src/
|
||||||
// shortcut_matcher.ts calls `window.onShortcutTriggered(actionId)` when a
|
// shortcut_matcher.ts calls `window.onShortcutTriggered(actionId)` when a
|
||||||
// binding fires; route it to the active session's ShortcutModel.
|
// binding fires; route it to the active session's ShortcutModel.
|
||||||
// Web is single-window so `gFFI` is always the active session.
|
// Web uses a JS-side connection, so the event does not arrive through the
|
||||||
|
// native session event stream.
|
||||||
js.context['onShortcutTriggered'] = (dynamic action) {
|
js.context['onShortcutTriggered'] = (dynamic action) {
|
||||||
if (action is String) {
|
if (action is String) {
|
||||||
common.gFFI.shortcutModel.onTriggered(action);
|
ShortcutModel.onWebTriggered(action);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return Future.value();
|
return Future.value();
|
||||||
|
|||||||
Reference in New Issue
Block a user