mirror of
https://github.com/rustdesk/rustdesk.git
synced 2025-01-19 00:13:01 +08:00
refactor input_model
This commit is contained in:
parent
729f4c0733
commit
3dc9ecce29
@ -19,6 +19,7 @@ import 'package:window_manager/window_manager.dart';
|
||||
import 'common/widgets/overlay.dart';
|
||||
import 'mobile/pages/file_manager_page.dart';
|
||||
import 'mobile/pages/remote_page.dart';
|
||||
import 'models/input_model.dart';
|
||||
import 'models/model.dart';
|
||||
import 'models/platform_model.dart';
|
||||
|
||||
@ -486,12 +487,12 @@ class OverlayDialogManager {
|
||||
position: Offset(left, top),
|
||||
width: overlayW,
|
||||
height: overlayH,
|
||||
onBackPressed: () => session.tap(MouseButtons.right),
|
||||
onHomePressed: () => session.tap(MouseButtons.wheel),
|
||||
onBackPressed: () => session.inputModel.tap(MouseButtons.right),
|
||||
onHomePressed: () => session.inputModel.tap(MouseButtons.wheel),
|
||||
onRecentPressed: () async {
|
||||
session.sendMouse('down', MouseButtons.wheel);
|
||||
session.inputModel.sendMouse('down', MouseButtons.wheel);
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
session.sendMouse('up', MouseButtons.wheel);
|
||||
session.inputModel.sendMouse('up', MouseButtons.wheel);
|
||||
},
|
||||
onHidePressed: () => hideMobileActionsOverlay(),
|
||||
);
|
||||
|
@ -58,7 +58,7 @@ class _FileManagerPageState extends State<FileManagerPage>
|
||||
void initState() {
|
||||
super.initState();
|
||||
_ffi = FFI();
|
||||
_ffi.connect(widget.id, isFileTransfer: true);
|
||||
_ffi.start(widget.id, isFileTransfer: true);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_ffi.dialogManager
|
||||
.showLoading(translate('Connecting...'), onCancel: closeConnection);
|
||||
|
@ -47,7 +47,7 @@ class _PortForwardPageState extends State<PortForwardPage>
|
||||
void initState() {
|
||||
super.initState();
|
||||
_ffi = FFI();
|
||||
_ffi.connect(widget.id, isPortForward: true);
|
||||
_ffi.start(widget.id, isPortForward: true);
|
||||
Get.put(_ffi, tag: 'pf_${widget.id}');
|
||||
if (!Platform.isLinux) {
|
||||
Wakelock.enable();
|
||||
|
@ -5,7 +5,6 @@ import 'dart:ui' as ui;
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hbb/models/input_model.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:wakelock/wakelock.dart';
|
||||
@ -49,12 +48,9 @@ class _RemotePageState extends State<RemotePage>
|
||||
Function(bool)? _onEnterOrLeaveImage4Menubar;
|
||||
|
||||
late FFI _ffi;
|
||||
late Keyboard _keyboard_input;
|
||||
late Mouse _mouse_input;
|
||||
|
||||
void _updateTabBarHeight() {
|
||||
_ffi.canvasModel.tabBarHeight = widget.tabBarHeight;
|
||||
_mouse_input.tabBarHeight = widget.tabBarHeight;
|
||||
}
|
||||
|
||||
void _initStates(String id) {
|
||||
@ -84,12 +80,10 @@ class _RemotePageState extends State<RemotePage>
|
||||
_initStates(widget.id);
|
||||
|
||||
_ffi = FFI();
|
||||
_keyboard_input = Keyboard(_ffi, widget.id);
|
||||
_mouse_input = Mouse(_ffi, widget.id, widget.tabBarHeight);
|
||||
|
||||
_updateTabBarHeight();
|
||||
Get.put(_ffi, tag: widget.id);
|
||||
_ffi.connect(widget.id, tabBarHeight: super.widget.tabBarHeight);
|
||||
_ffi.start(widget.id, tabBarHeight: super.widget.tabBarHeight);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
|
||||
_ffi.dialogManager
|
||||
@ -175,7 +169,7 @@ class _RemotePageState extends State<RemotePage>
|
||||
onFocusChange: (bool v) {
|
||||
_imageFocused = v;
|
||||
},
|
||||
onKey: _keyboard_input.handleRawKeyEvent,
|
||||
onKey: _ffi.inputModel.handleRawKeyEvent,
|
||||
child: child));
|
||||
}
|
||||
|
||||
@ -191,7 +185,7 @@ class _RemotePageState extends State<RemotePage>
|
||||
//
|
||||
}
|
||||
}
|
||||
_ffi.enterOrLeave(true);
|
||||
_ffi.inputModel.enterOrLeave(true);
|
||||
}
|
||||
|
||||
void leaveView(PointerExitEvent evt) {
|
||||
@ -203,16 +197,16 @@ class _RemotePageState extends State<RemotePage>
|
||||
//
|
||||
}
|
||||
}
|
||||
_ffi.enterOrLeave(false);
|
||||
_ffi.inputModel.enterOrLeave(false);
|
||||
}
|
||||
|
||||
Widget _buildImageListener(Widget child) {
|
||||
return Listener(
|
||||
onPointerHover: _mouse_input.onPointHoverImage,
|
||||
onPointerDown: _mouse_input.onPointDownImage,
|
||||
onPointerUp: _mouse_input.onPointUpImage,
|
||||
onPointerMove: _mouse_input.onPointMoveImage,
|
||||
onPointerSignal: _mouse_input.onPointerSignalImage,
|
||||
onPointerHover: _ffi.inputModel.onPointHoverImage,
|
||||
onPointerDown: _ffi.inputModel.onPointDownImage,
|
||||
onPointerUp: _ffi.inputModel.onPointUpImage,
|
||||
onPointerMove: _ffi.inputModel.onPointMoveImage,
|
||||
onPointerSignal: _ffi.inputModel.onPointerSignalImage,
|
||||
child:
|
||||
MouseRegion(onEnter: enterView, onExit: leaveView, child: child));
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ class _FileManagerPageState extends State<FileManagerPage> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
gFFI.connect(widget.id, isFileTransfer: true);
|
||||
gFFI.start(widget.id, isFileTransfer: true);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
gFFI.dialogManager
|
||||
.showLoading(translate('Connecting...'), onCancel: closeConnection);
|
||||
|
@ -12,6 +12,7 @@ import 'package:wakelock/wakelock.dart';
|
||||
|
||||
import '../../common.dart';
|
||||
import '../../consts.dart';
|
||||
import '../../models/input_model.dart';
|
||||
import '../../models/model.dart';
|
||||
import '../../models/platform_model.dart';
|
||||
import '../widgets/dialog.dart';
|
||||
@ -45,10 +46,12 @@ class _RemotePageState extends State<RemotePage> {
|
||||
var _showEdit = false; // use soft keyboard
|
||||
var _isPhysicalMouse = false;
|
||||
|
||||
get inputModel => gFFI.inputModel;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
gFFI.connect(widget.id);
|
||||
gFFI.start(widget.id);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
|
||||
gFFI.dialogManager
|
||||
@ -59,14 +62,14 @@ class _RemotePageState extends State<RemotePage> {
|
||||
Wakelock.enable();
|
||||
_physicalFocusNode.requestFocus();
|
||||
gFFI.ffiModel.updateEventListener(widget.id);
|
||||
gFFI.listenToMouse(true);
|
||||
gFFI.inputModel.listenToMouse(true);
|
||||
gFFI.qualityMonitorModel.checkShowQualityMonitor(widget.id);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
gFFI.dialogManager.hideMobileActionsOverlay();
|
||||
gFFI.listenToMouse(false);
|
||||
gFFI.inputModel.listenToMouse(false);
|
||||
gFFI.invokeMethod("enable_soft_keyboard", true);
|
||||
_mobileFocusNode.dispose();
|
||||
_physicalFocusNode.dispose();
|
||||
@ -81,7 +84,7 @@ class _RemotePageState extends State<RemotePage> {
|
||||
}
|
||||
|
||||
void resetTool() {
|
||||
gFFI.resetModifiers();
|
||||
inputModel.resetModifiers();
|
||||
}
|
||||
|
||||
bool isKeyboardShown() {
|
||||
@ -133,7 +136,7 @@ class _RemotePageState extends State<RemotePage> {
|
||||
newValue[common] == oldValue[common];
|
||||
++common) {}
|
||||
for (i = 0; i < oldValue.length - common; ++i) {
|
||||
gFFI.inputKey('VK_BACK');
|
||||
inputModel.inputKey('VK_BACK');
|
||||
}
|
||||
if (newValue.length > common) {
|
||||
var s = newValue.substring(common);
|
||||
@ -156,7 +159,7 @@ class _RemotePageState extends State<RemotePage> {
|
||||
// ?
|
||||
} else if (newValue.length < oldValue.length) {
|
||||
final char = 'VK_BACK';
|
||||
gFFI.inputKey(char);
|
||||
inputModel.inputKey(char);
|
||||
} else {
|
||||
final content = newValue.substring(oldValue.length);
|
||||
if (content.length > 1) {
|
||||
@ -189,7 +192,7 @@ class _RemotePageState extends State<RemotePage> {
|
||||
} else if (char == ' ') {
|
||||
char = 'VK_SPACE';
|
||||
}
|
||||
gFFI.inputKey(char);
|
||||
inputModel.inputKey(char);
|
||||
}
|
||||
|
||||
void openKeyboard() {
|
||||
@ -216,7 +219,7 @@ class _RemotePageState extends State<RemotePage> {
|
||||
final label = logicalKeyMap[e.logicalKey.keyId] ??
|
||||
physicalKeyMap[e.physicalKey.usbHidUsage] ??
|
||||
e.logicalKey.keyLabel;
|
||||
gFFI.inputKey(label, down: down, press: press ?? false);
|
||||
inputModel.inputKey(label, down: down, press: press ?? false);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -296,7 +299,7 @@ class _RemotePageState extends State<RemotePage> {
|
||||
});
|
||||
}
|
||||
if (_isPhysicalMouse) {
|
||||
gFFI.handleMouse(getEvent(e, 'mousemove'));
|
||||
inputModel.handleMouse(getEvent(e, 'mousemove'));
|
||||
}
|
||||
},
|
||||
onPointerDown: (e) {
|
||||
@ -308,19 +311,19 @@ class _RemotePageState extends State<RemotePage> {
|
||||
}
|
||||
}
|
||||
if (_isPhysicalMouse) {
|
||||
gFFI.handleMouse(getEvent(e, 'mousedown'));
|
||||
inputModel.handleMouse(getEvent(e, 'mousedown'));
|
||||
}
|
||||
},
|
||||
onPointerUp: (e) {
|
||||
if (e.kind != ui.PointerDeviceKind.mouse) return;
|
||||
if (_isPhysicalMouse) {
|
||||
gFFI.handleMouse(getEvent(e, 'mouseup'));
|
||||
inputModel.handleMouse(getEvent(e, 'mouseup'));
|
||||
}
|
||||
},
|
||||
onPointerMove: (e) {
|
||||
if (e.kind != ui.PointerDeviceKind.mouse) return;
|
||||
if (_isPhysicalMouse) {
|
||||
gFFI.handleMouse(getEvent(e, 'mousemove'));
|
||||
inputModel.handleMouse(getEvent(e, 'mousemove'));
|
||||
}
|
||||
},
|
||||
onPointerSignal: (e) {
|
||||
@ -331,7 +334,7 @@ class _RemotePageState extends State<RemotePage> {
|
||||
} else if (e.scrollDelta.dy < 0) {
|
||||
dy = 1;
|
||||
}
|
||||
gFFI.scroll(dy);
|
||||
inputModel.scroll(dy);
|
||||
}
|
||||
},
|
||||
child: MouseRegion(
|
||||
@ -353,14 +356,14 @@ class _RemotePageState extends State<RemotePage> {
|
||||
sendRawKey(e, press: true);
|
||||
} else {
|
||||
sendRawKey(e, down: true);
|
||||
if (e.isAltPressed && !gFFI.alt) {
|
||||
gFFI.alt = true;
|
||||
} else if (e.isControlPressed && !gFFI.ctrl) {
|
||||
gFFI.ctrl = true;
|
||||
} else if (e.isShiftPressed && !gFFI.shift) {
|
||||
gFFI.shift = true;
|
||||
} else if (e.isMetaPressed && !gFFI.command) {
|
||||
gFFI.command = true;
|
||||
if (e.isAltPressed && !inputModel.alt) {
|
||||
inputModel.alt = true;
|
||||
} else if (e.isControlPressed && !inputModel.ctrl) {
|
||||
inputModel.ctrl = true;
|
||||
} else if (e.isShiftPressed && !inputModel.shift) {
|
||||
inputModel.shift = true;
|
||||
} else if (e.isMetaPressed && !inputModel.command) {
|
||||
inputModel.command = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -368,16 +371,16 @@ class _RemotePageState extends State<RemotePage> {
|
||||
if (!_showEdit && e is RawKeyUpEvent) {
|
||||
if (key == LogicalKeyboardKey.altLeft ||
|
||||
key == LogicalKeyboardKey.altRight) {
|
||||
gFFI.alt = false;
|
||||
inputModel.alt = false;
|
||||
} else if (key == LogicalKeyboardKey.controlLeft ||
|
||||
key == LogicalKeyboardKey.controlRight) {
|
||||
gFFI.ctrl = false;
|
||||
inputModel.ctrl = false;
|
||||
} else if (key == LogicalKeyboardKey.shiftRight ||
|
||||
key == LogicalKeyboardKey.shiftLeft) {
|
||||
gFFI.shift = false;
|
||||
inputModel.shift = false;
|
||||
} else if (key == LogicalKeyboardKey.metaLeft ||
|
||||
key == LogicalKeyboardKey.metaRight) {
|
||||
gFFI.command = false;
|
||||
inputModel.command = false;
|
||||
}
|
||||
sendRawKey(e);
|
||||
}
|
||||
@ -489,10 +492,10 @@ class _RemotePageState extends State<RemotePage> {
|
||||
child: getBodyForMobile(),
|
||||
onTapUp: (d) {
|
||||
if (touchMode) {
|
||||
gFFI.cursorModel.touch(
|
||||
d.localPosition.dx, d.localPosition.dy, MouseButtons.left);
|
||||
gFFI.cursorModel.move(d.localPosition.dx, d.localPosition.dy);
|
||||
inputModel.tap(MouseButtons.left);
|
||||
} else {
|
||||
gFFI.tap(MouseButtons.left);
|
||||
inputModel.tap(MouseButtons.left);
|
||||
}
|
||||
},
|
||||
onDoubleTapDown: (d) {
|
||||
@ -501,8 +504,8 @@ class _RemotePageState extends State<RemotePage> {
|
||||
}
|
||||
},
|
||||
onDoubleTap: () {
|
||||
gFFI.tap(MouseButtons.left);
|
||||
gFFI.tap(MouseButtons.left);
|
||||
inputModel.tap(MouseButtons.left);
|
||||
inputModel.tap(MouseButtons.left);
|
||||
},
|
||||
onLongPressDown: (d) {
|
||||
if (touchMode) {
|
||||
@ -515,16 +518,16 @@ class _RemotePageState extends State<RemotePage> {
|
||||
gFFI.cursorModel
|
||||
.move(_cacheLongPressPosition.dx, _cacheLongPressPosition.dy);
|
||||
}
|
||||
gFFI.tap(MouseButtons.right);
|
||||
inputModel.tap(MouseButtons.right);
|
||||
},
|
||||
onDoubleFinerTap: (d) {
|
||||
if (!touchMode) {
|
||||
gFFI.tap(MouseButtons.right);
|
||||
inputModel.tap(MouseButtons.right);
|
||||
}
|
||||
},
|
||||
onHoldDragStart: (d) {
|
||||
if (!touchMode) {
|
||||
gFFI.sendMouse('down', MouseButtons.left);
|
||||
inputModel.sendMouse('down', MouseButtons.left);
|
||||
}
|
||||
},
|
||||
onHoldDragUpdate: (d) {
|
||||
@ -534,13 +537,13 @@ class _RemotePageState extends State<RemotePage> {
|
||||
},
|
||||
onHoldDragEnd: (_) {
|
||||
if (!touchMode) {
|
||||
gFFI.sendMouse('up', MouseButtons.left);
|
||||
inputModel.sendMouse('up', MouseButtons.left);
|
||||
}
|
||||
},
|
||||
onOneFingerPanStart: (d) {
|
||||
if (touchMode) {
|
||||
gFFI.cursorModel.move(d.localPosition.dx, d.localPosition.dy);
|
||||
gFFI.sendMouse('down', MouseButtons.left);
|
||||
inputModel.sendMouse('down', MouseButtons.left);
|
||||
} else {
|
||||
final cursorX = gFFI.cursorModel.x;
|
||||
final cursorY = gFFI.cursorModel.y;
|
||||
@ -557,7 +560,7 @@ class _RemotePageState extends State<RemotePage> {
|
||||
},
|
||||
onOneFingerPanEnd: (d) {
|
||||
if (touchMode) {
|
||||
gFFI.sendMouse('up', MouseButtons.left);
|
||||
inputModel.sendMouse('up', MouseButtons.left);
|
||||
}
|
||||
},
|
||||
// scale + pan event
|
||||
@ -576,10 +579,10 @@ class _RemotePageState extends State<RemotePage> {
|
||||
: (d) {
|
||||
_mouseScrollIntegral += d.delta.dy / 4;
|
||||
if (_mouseScrollIntegral > 1) {
|
||||
gFFI.scroll(1);
|
||||
inputModel.scroll(1);
|
||||
_mouseScrollIntegral = 0;
|
||||
} else if (_mouseScrollIntegral < -1) {
|
||||
gFFI.scroll(-1);
|
||||
inputModel.scroll(-1);
|
||||
_mouseScrollIntegral = 0;
|
||||
}
|
||||
});
|
||||
@ -627,15 +630,16 @@ class _RemotePageState extends State<RemotePage> {
|
||||
|
||||
int lastMouseDownButtons = 0;
|
||||
|
||||
// 重复
|
||||
Map<String, dynamic> getEvent(PointerEvent evt, String type) {
|
||||
final Map<String, dynamic> out = {};
|
||||
out['type'] = type;
|
||||
out['x'] = evt.position.dx;
|
||||
out['y'] = evt.position.dy;
|
||||
if (gFFI.alt) out['alt'] = 'true';
|
||||
if (gFFI.shift) out['shift'] = 'true';
|
||||
if (gFFI.ctrl) out['ctrl'] = 'true';
|
||||
if (gFFI.command) out['command'] = 'true';
|
||||
if (inputModel.alt) out['alt'] = 'true';
|
||||
if (inputModel.shift) out['shift'] = 'true';
|
||||
if (inputModel.ctrl) out['ctrl'] = 'true';
|
||||
if (inputModel.command) out['command'] = 'true';
|
||||
out['buttons'] = evt
|
||||
.buttons; // left button: 1, right button: 2, middle button: 4, 1 | 2 = 3 (left + right)
|
||||
if (evt.buttons != 0) {
|
||||
@ -776,7 +780,7 @@ class _RemotePageState extends State<RemotePage> {
|
||||
return SizedBox();
|
||||
}
|
||||
final size = MediaQuery.of(context).size;
|
||||
var wrap = (String text, void Function() onPressed,
|
||||
wrap(String text, void Function() onPressed,
|
||||
[bool? active, IconData? icon]) {
|
||||
return TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
@ -795,22 +799,23 @@ class _RemotePageState extends State<RemotePage> {
|
||||
: Text(translate(text),
|
||||
style: TextStyle(color: Colors.white, fontSize: 11)),
|
||||
onPressed: onPressed);
|
||||
};
|
||||
}
|
||||
|
||||
final pi = gFFI.ffiModel.pi;
|
||||
final isMac = pi.platform == "Mac OS";
|
||||
final modifiers = <Widget>[
|
||||
wrap('Ctrl ', () {
|
||||
setState(() => gFFI.ctrl = !gFFI.ctrl);
|
||||
}, gFFI.ctrl),
|
||||
setState(() => inputModel.ctrl = !inputModel.ctrl);
|
||||
}, inputModel.ctrl),
|
||||
wrap(' Alt ', () {
|
||||
setState(() => gFFI.alt = !gFFI.alt);
|
||||
}, gFFI.alt),
|
||||
setState(() => inputModel.alt = !inputModel.alt);
|
||||
}, inputModel.alt),
|
||||
wrap('Shift', () {
|
||||
setState(() => gFFI.shift = !gFFI.shift);
|
||||
}, gFFI.shift),
|
||||
setState(() => inputModel.shift = !inputModel.shift);
|
||||
}, inputModel.shift),
|
||||
wrap(isMac ? ' Cmd ' : ' Win ', () {
|
||||
setState(() => gFFI.command = !gFFI.command);
|
||||
}, gFFI.command),
|
||||
setState(() => inputModel.command = !inputModel.command);
|
||||
}, inputModel.command),
|
||||
];
|
||||
final keys = <Widget>[
|
||||
wrap(
|
||||
@ -842,44 +847,44 @@ class _RemotePageState extends State<RemotePage> {
|
||||
for (var i = 1; i <= 12; ++i) {
|
||||
final name = 'F' + i.toString();
|
||||
fn.add(wrap(name, () {
|
||||
gFFI.inputKey('VK_' + name);
|
||||
inputModel.inputKey('VK_' + name);
|
||||
}));
|
||||
}
|
||||
final more = <Widget>[
|
||||
SizedBox(width: 9999),
|
||||
wrap('Esc', () {
|
||||
gFFI.inputKey('VK_ESCAPE');
|
||||
inputModel.inputKey('VK_ESCAPE');
|
||||
}),
|
||||
wrap('Tab', () {
|
||||
gFFI.inputKey('VK_TAB');
|
||||
inputModel.inputKey('VK_TAB');
|
||||
}),
|
||||
wrap('Home', () {
|
||||
gFFI.inputKey('VK_HOME');
|
||||
inputModel.inputKey('VK_HOME');
|
||||
}),
|
||||
wrap('End', () {
|
||||
gFFI.inputKey('VK_END');
|
||||
inputModel.inputKey('VK_END');
|
||||
}),
|
||||
wrap('Del', () {
|
||||
gFFI.inputKey('VK_DELETE');
|
||||
inputModel.inputKey('VK_DELETE');
|
||||
}),
|
||||
wrap('PgUp', () {
|
||||
gFFI.inputKey('VK_PRIOR');
|
||||
inputModel.inputKey('VK_PRIOR');
|
||||
}),
|
||||
wrap('PgDn', () {
|
||||
gFFI.inputKey('VK_NEXT');
|
||||
inputModel.inputKey('VK_NEXT');
|
||||
}),
|
||||
SizedBox(width: 9999),
|
||||
wrap('', () {
|
||||
gFFI.inputKey('VK_LEFT');
|
||||
inputModel.inputKey('VK_LEFT');
|
||||
}, false, Icons.keyboard_arrow_left),
|
||||
wrap('', () {
|
||||
gFFI.inputKey('VK_UP');
|
||||
inputModel.inputKey('VK_UP');
|
||||
}, false, Icons.keyboard_arrow_up),
|
||||
wrap('', () {
|
||||
gFFI.inputKey('VK_DOWN');
|
||||
inputModel.inputKey('VK_DOWN');
|
||||
}, false, Icons.keyboard_arrow_down),
|
||||
wrap('', () {
|
||||
gFFI.inputKey('VK_RIGHT');
|
||||
inputModel.inputKey('VK_RIGHT');
|
||||
}, false, Icons.keyboard_arrow_right),
|
||||
wrap(isMac ? 'Cmd+C' : 'Ctrl+C', () {
|
||||
sendPrompt(isMac, 'VK_C');
|
||||
@ -1202,16 +1207,16 @@ void showSetOSPassword(
|
||||
}
|
||||
|
||||
void sendPrompt(bool isMac, String key) {
|
||||
final old = isMac ? gFFI.command : gFFI.ctrl;
|
||||
final old = isMac ? gFFI.inputModel.command : gFFI.inputModel.ctrl;
|
||||
if (isMac) {
|
||||
gFFI.command = true;
|
||||
gFFI.inputModel.command = true;
|
||||
} else {
|
||||
gFFI.ctrl = true;
|
||||
gFFI.inputModel.ctrl = true;
|
||||
}
|
||||
gFFI.inputKey(key);
|
||||
gFFI.inputModel.inputKey(key);
|
||||
if (isMac) {
|
||||
gFFI.command = old;
|
||||
gFFI.inputModel.command = old;
|
||||
} else {
|
||||
gFFI.ctrl = old;
|
||||
gFFI.inputModel.ctrl = old;
|
||||
}
|
||||
}
|
||||
|
@ -50,10 +50,9 @@ class ChatModel with ChangeNotifier {
|
||||
|
||||
bool get isShowChatPage => _isShowChatPage;
|
||||
|
||||
WeakReference<FFI> _ffi;
|
||||
final WeakReference<FFI> parent;
|
||||
|
||||
/// Constructor
|
||||
ChatModel(this._ffi);
|
||||
ChatModel(this.parent);
|
||||
|
||||
ChatUser get currentUser {
|
||||
final user = messages[currentID]?.chatUser;
|
||||
@ -182,7 +181,7 @@ class ChatModel with ChangeNotifier {
|
||||
_currentID = id;
|
||||
notifyListeners();
|
||||
} else {
|
||||
final client = _ffi.target?.serverModel.clients
|
||||
final client = parent.target?.serverModel.clients
|
||||
.firstWhere((client) => client.id == id);
|
||||
if (client == null) {
|
||||
return debugPrint(
|
||||
@ -208,23 +207,23 @@ class ChatModel with ChangeNotifier {
|
||||
if (!_isShowChatPage) {
|
||||
toggleCMChatPage(id);
|
||||
}
|
||||
_ffi.target?.serverModel.jumpTo(id);
|
||||
parent.target?.serverModel.jumpTo(id);
|
||||
|
||||
late final chatUser;
|
||||
if (id == clientModeID) {
|
||||
chatUser = ChatUser(
|
||||
firstName: _ffi.target?.ffiModel.pi.username,
|
||||
firstName: parent.target?.ffiModel.pi.username,
|
||||
id: await bind.mainGetLastRemoteId(),
|
||||
);
|
||||
} else {
|
||||
final client = _ffi.target?.serverModel.clients
|
||||
final client = parent.target?.serverModel.clients
|
||||
.firstWhere((client) => client.id == id);
|
||||
if (client == null) {
|
||||
return debugPrint("Failed to receive msg,user doesn't exist");
|
||||
}
|
||||
if (isDesktop) {
|
||||
window_on_top(null);
|
||||
var index = _ffi.target?.serverModel.clients
|
||||
var index = parent.target?.serverModel.clients
|
||||
.indexWhere((client) => client.id == id);
|
||||
if (index != null && index >= 0) {
|
||||
gFFI.serverModel.tabController.jumpTo(index);
|
||||
@ -246,8 +245,8 @@ class ChatModel with ChangeNotifier {
|
||||
if (message.text.isNotEmpty) {
|
||||
_messages[_currentID]?.insert(message);
|
||||
if (_currentID == clientModeID) {
|
||||
if (_ffi.target != null) {
|
||||
bind.sessionSendChat(id: _ffi.target!.id, text: message.text);
|
||||
if (parent.target != null) {
|
||||
bind.sessionSendChat(id: parent.target!.id, text: message.text);
|
||||
}
|
||||
} else {
|
||||
bind.cmSendChat(connId: _currentID, msg: message.text);
|
||||
|
@ -1,55 +1,85 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get/get_core/src/get_main.dart';
|
||||
|
||||
import '../../models/model.dart';
|
||||
import '../../models/platform_model.dart';
|
||||
import '../common.dart';
|
||||
import '../consts.dart';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
class Keyboard {
|
||||
late FFI _ffi;
|
||||
late String _id;
|
||||
/// Mouse button enum.
|
||||
enum MouseButtons { left, right, wheel }
|
||||
|
||||
extension ToString on MouseButtons {
|
||||
String get value {
|
||||
switch (this) {
|
||||
case MouseButtons.left:
|
||||
return 'left';
|
||||
case MouseButtons.right:
|
||||
return 'right';
|
||||
case MouseButtons.wheel:
|
||||
return 'wheel';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class InputModel {
|
||||
final WeakReference<FFI> parent;
|
||||
String keyboardMode = "legacy";
|
||||
|
||||
Keyboard(FFI ffi, String id) {
|
||||
_ffi = ffi;
|
||||
_id = id;
|
||||
}
|
||||
// keyboard
|
||||
var shift = false;
|
||||
var ctrl = false;
|
||||
var alt = false;
|
||||
var command = false;
|
||||
|
||||
// mouse
|
||||
var _isPhysicalMouse = false;
|
||||
int _lastMouseDownButtons = 0;
|
||||
|
||||
get id => parent.target?.id ?? "";
|
||||
|
||||
InputModel(this.parent);
|
||||
|
||||
KeyEventResult handleRawKeyEvent(FocusNode data, RawKeyEvent e) {
|
||||
bind.sessionGetKeyboardName(id: _id).then((result) {
|
||||
bind.sessionGetKeyboardName(id: id).then((result) {
|
||||
keyboardMode = result.toString();
|
||||
});
|
||||
|
||||
final key = e.logicalKey;
|
||||
if (e is RawKeyDownEvent) {
|
||||
if (!e.repeat){
|
||||
if (e.isAltPressed && !_ffi.alt) {
|
||||
_ffi.alt = true;
|
||||
} else if (e.isControlPressed && !_ffi.ctrl) {
|
||||
_ffi.ctrl = true;
|
||||
} else if (e.isShiftPressed && !_ffi.shift) {
|
||||
_ffi.shift = true;
|
||||
} else if (e.isMetaPressed && !_ffi.command) {
|
||||
_ffi.command = true;
|
||||
if (!e.repeat) {
|
||||
if (e.isAltPressed && !alt) {
|
||||
alt = true;
|
||||
} else if (e.isControlPressed && !ctrl) {
|
||||
ctrl = true;
|
||||
} else if (e.isShiftPressed && !shift) {
|
||||
shift = true;
|
||||
} else if (e.isMetaPressed && !command) {
|
||||
command = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (e is RawKeyUpEvent) {
|
||||
if (key == LogicalKeyboardKey.altLeft ||
|
||||
key == LogicalKeyboardKey.altRight) {
|
||||
_ffi.alt = false;
|
||||
alt = false;
|
||||
} else if (key == LogicalKeyboardKey.controlLeft ||
|
||||
key == LogicalKeyboardKey.controlRight) {
|
||||
_ffi.ctrl = false;
|
||||
ctrl = false;
|
||||
} else if (key == LogicalKeyboardKey.shiftRight ||
|
||||
key == LogicalKeyboardKey.shiftLeft) {
|
||||
_ffi.shift = false;
|
||||
shift = false;
|
||||
} else if (key == LogicalKeyboardKey.metaLeft ||
|
||||
key == LogicalKeyboardKey.metaRight ||
|
||||
key == LogicalKeyboardKey.superKey) {
|
||||
_ffi.command = false;
|
||||
command = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,12 +121,20 @@ class Keyboard {
|
||||
} else {
|
||||
down = false;
|
||||
}
|
||||
inputRawKey(e.character ?? "", keyCode, scanCode, down);
|
||||
}
|
||||
|
||||
_ffi.inputRawKey(e.character ?? "", keyCode, scanCode, down);
|
||||
/// Send raw Key Event
|
||||
void inputRawKey(String name, int keyCode, int scanCode, bool down) {
|
||||
bind.sessionHandleFlutterKeyEvent(
|
||||
id: id,
|
||||
name: name,
|
||||
keycode: keyCode,
|
||||
scancode: scanCode,
|
||||
downOrUp: down);
|
||||
}
|
||||
|
||||
void legacyKeyboardMode(RawKeyEvent e) {
|
||||
final key = e.logicalKey;
|
||||
if (e is RawKeyDownEvent) {
|
||||
if (e.repeat) {
|
||||
sendRawKey(e, press: true);
|
||||
@ -114,22 +152,23 @@ class Keyboard {
|
||||
final label = physicalKeyMap[e.physicalKey.usbHidUsage] ??
|
||||
logicalKeyMap[e.logicalKey.keyId] ??
|
||||
e.logicalKey.keyLabel;
|
||||
_ffi.inputKey(label, down: down, press: press ?? false);
|
||||
inputKey(label, down: down, press: press ?? false);
|
||||
}
|
||||
}
|
||||
|
||||
class Mouse {
|
||||
var _isPhysicalMouse = false;
|
||||
int _lastMouseDownButtons = 0;
|
||||
|
||||
late FFI _ffi;
|
||||
late String _id;
|
||||
late double tabBarHeight;
|
||||
|
||||
Mouse(FFI ffi, String id, double tabBarHeight_) {
|
||||
_ffi = ffi;
|
||||
_id = id;
|
||||
tabBarHeight = tabBarHeight_;
|
||||
/// Send key stroke event.
|
||||
/// [down] indicates the key's state(down or up).
|
||||
/// [press] indicates a click event(down and up).
|
||||
void inputKey(String name, {bool? down, bool? press}) {
|
||||
if (!parent.target!.ffiModel.keyboard()) return;
|
||||
bind.sessionInputKey(
|
||||
id: id,
|
||||
name: name,
|
||||
down: down ?? false,
|
||||
press: press ?? true,
|
||||
alt: alt,
|
||||
ctrl: ctrl,
|
||||
shift: shift,
|
||||
command: command);
|
||||
}
|
||||
|
||||
Map<String, dynamic> getEvent(PointerEvent evt, String type) {
|
||||
@ -137,10 +176,10 @@ class Mouse {
|
||||
out['type'] = type;
|
||||
out['x'] = evt.position.dx;
|
||||
out['y'] = evt.position.dy;
|
||||
if (_ffi.alt) out['alt'] = 'true';
|
||||
if (_ffi.shift) out['shift'] = 'true';
|
||||
if (_ffi.ctrl) out['ctrl'] = 'true';
|
||||
if (_ffi.command) out['command'] = 'true';
|
||||
if (alt) out['alt'] = 'true';
|
||||
if (shift) out['shift'] = 'true';
|
||||
if (ctrl) out['ctrl'] = 'true';
|
||||
if (command) out['command'] = 'true';
|
||||
out['buttons'] = evt
|
||||
.buttons; // left button: 1, right button: 2, middle button: 4, 1 | 2 = 3 (left + right)
|
||||
if (evt.buttons != 0) {
|
||||
@ -151,38 +190,92 @@ class Mouse {
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Send a mouse tap event(down and up).
|
||||
void tap(MouseButtons button) {
|
||||
sendMouse('down', button);
|
||||
sendMouse('up', button);
|
||||
}
|
||||
|
||||
/// Send scroll event with scroll distance [y].
|
||||
void scroll(int y) {
|
||||
bind.sessionSendMouse(
|
||||
id: id,
|
||||
msg: json
|
||||
.encode(modify({'id': id, 'type': 'wheel', 'y': y.toString()})));
|
||||
}
|
||||
|
||||
/// Reset key modifiers to false, including [shift], [ctrl], [alt] and [command].
|
||||
void resetModifiers() {
|
||||
shift = ctrl = alt = command = false;
|
||||
}
|
||||
|
||||
/// Modify the given modifier map [evt] based on current modifier key status.
|
||||
Map<String, String> modify(Map<String, String> evt) {
|
||||
if (ctrl) evt['ctrl'] = 'true';
|
||||
if (shift) evt['shift'] = 'true';
|
||||
if (alt) evt['alt'] = 'true';
|
||||
if (command) evt['command'] = 'true';
|
||||
return evt;
|
||||
}
|
||||
|
||||
/// Send mouse press event.
|
||||
void sendMouse(String type, MouseButtons button) {
|
||||
if (!parent.target!.ffiModel.keyboard()) return;
|
||||
bind.sessionSendMouse(
|
||||
id: id,
|
||||
msg: json.encode(modify({'type': type, 'buttons': button.value})));
|
||||
}
|
||||
|
||||
void enterOrLeave(bool enter) {
|
||||
// Fix status
|
||||
if (!enter) {
|
||||
resetModifiers();
|
||||
}
|
||||
bind.sessionEnterOrLeave(id: id, enter: enter);
|
||||
}
|
||||
|
||||
/// Send mouse movement event with distance in [x] and [y].
|
||||
void moveMouse(double x, double y) {
|
||||
if (!parent.target!.ffiModel.keyboard()) return;
|
||||
var x2 = x.toInt();
|
||||
var y2 = y.toInt();
|
||||
bind.sessionSendMouse(
|
||||
id: id, msg: json.encode(modify({'x': '$x2', 'y': '$y2'})));
|
||||
}
|
||||
|
||||
void onPointHoverImage(PointerHoverEvent e) {
|
||||
if (e.kind != ui.PointerDeviceKind.mouse) return;
|
||||
if (!_isPhysicalMouse) {
|
||||
_isPhysicalMouse = true;
|
||||
}
|
||||
if (_isPhysicalMouse) {
|
||||
_ffi.handleMouse(getEvent(e, 'mousemove'), tabBarHeight: tabBarHeight);
|
||||
handleMouse(getEvent(e, 'mousemove'));
|
||||
}
|
||||
}
|
||||
|
||||
void onPointDownImage(PointerDownEvent e) {
|
||||
debugPrint("onPointDownImage");
|
||||
if (e.kind != ui.PointerDeviceKind.mouse) {
|
||||
if (_isPhysicalMouse) {
|
||||
_isPhysicalMouse = false;
|
||||
}
|
||||
}
|
||||
if (_isPhysicalMouse) {
|
||||
_ffi.handleMouse(getEvent(e, 'mousedown'), tabBarHeight: tabBarHeight);
|
||||
handleMouse(getEvent(e, 'mousedown'));
|
||||
}
|
||||
}
|
||||
|
||||
void onPointUpImage(PointerUpEvent e) {
|
||||
if (e.kind != ui.PointerDeviceKind.mouse) return;
|
||||
if (_isPhysicalMouse) {
|
||||
_ffi.handleMouse(getEvent(e, 'mouseup'), tabBarHeight: tabBarHeight);
|
||||
handleMouse(getEvent(e, 'mouseup'));
|
||||
}
|
||||
}
|
||||
|
||||
void onPointMoveImage(PointerMoveEvent e) {
|
||||
if (e.kind != ui.PointerDeviceKind.mouse) return;
|
||||
if (_isPhysicalMouse) {
|
||||
_ffi.handleMouse(getEvent(e, 'mousemove'), tabBarHeight: tabBarHeight);
|
||||
handleMouse(getEvent(e, 'mousemove'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,7 +294,93 @@ class Mouse {
|
||||
dy = 1;
|
||||
}
|
||||
bind.sessionSendMouse(
|
||||
id: _id, msg: '{"type": "wheel", "x": "$dx", "y": "$dy"}');
|
||||
id: id, msg: '{"type": "wheel", "x": "$dx", "y": "$dy"}');
|
||||
}
|
||||
}
|
||||
|
||||
void handleMouse(Map<String, dynamic> evt) {
|
||||
var type = '';
|
||||
var isMove = false;
|
||||
switch (evt['type']) {
|
||||
case 'mousedown':
|
||||
type = 'down';
|
||||
break;
|
||||
case 'mouseup':
|
||||
type = 'up';
|
||||
break;
|
||||
case 'mousemove':
|
||||
isMove = true;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
evt['type'] = type;
|
||||
double x = evt['x'];
|
||||
double y = max(0.0, evt['y']);
|
||||
if (isDesktop) {
|
||||
final RxBool fullscreen = Get.find(tag: 'fullscreen');
|
||||
final tabBarHeight = fullscreen.isTrue ? 0 : kDesktopRemoteTabBarHeight;
|
||||
y = y - tabBarHeight;
|
||||
}
|
||||
final canvasModel = parent.target!.canvasModel;
|
||||
final ffiModel = parent.target!.ffiModel;
|
||||
if (isMove) {
|
||||
canvasModel.moveDesktopMouse(x, y);
|
||||
}
|
||||
final d = ffiModel.display;
|
||||
if (canvasModel.scrollStyle == ScrollStyle.scrollbar) {
|
||||
final imageWidth = d.width * canvasModel.scale;
|
||||
final imageHeight = d.height * canvasModel.scale;
|
||||
x += imageWidth * canvasModel.scrollX;
|
||||
y += imageHeight * canvasModel.scrollY;
|
||||
|
||||
// boxed size is a center widget
|
||||
if (canvasModel.size.width > imageWidth) {
|
||||
x -= ((canvasModel.size.width - imageWidth) / 2);
|
||||
}
|
||||
if (canvasModel.size.height > imageHeight) {
|
||||
y -= ((canvasModel.size.height - imageHeight) / 2);
|
||||
}
|
||||
} else {
|
||||
x -= canvasModel.x;
|
||||
y -= canvasModel.y;
|
||||
}
|
||||
|
||||
x /= canvasModel.scale;
|
||||
y /= canvasModel.scale;
|
||||
x += d.x;
|
||||
y += d.y;
|
||||
if (type != '') {
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
// fix mouse out of bounds
|
||||
x = min(max(0.0, x), d.width.toDouble());
|
||||
y = min(max(0.0, y), d.height.toDouble());
|
||||
evt['x'] = '${x.round()}';
|
||||
evt['y'] = '${y.round()}';
|
||||
var buttons = '';
|
||||
switch (evt['buttons']) {
|
||||
case 1:
|
||||
buttons = 'left';
|
||||
break;
|
||||
case 2:
|
||||
buttons = 'right';
|
||||
break;
|
||||
case 4:
|
||||
buttons = 'wheel';
|
||||
break;
|
||||
}
|
||||
evt['buttons'] = buttons;
|
||||
bind.sessionSendMouse(id: id, msg: json.encode(evt));
|
||||
}
|
||||
|
||||
/// Web only
|
||||
void listenToMouse(bool yesOrNo) {
|
||||
if (yesOrNo) {
|
||||
platformFFI.startDesktopWebListener();
|
||||
} else {
|
||||
platformFFI.stopDesktopWebListener();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import '../common.dart';
|
||||
import '../common/shared_state.dart';
|
||||
import '../utils/image.dart' as img;
|
||||
import '../mobile/widgets/dialog.dart';
|
||||
import 'input_model.dart';
|
||||
import 'platform_model.dart';
|
||||
|
||||
typedef HandleMsgBox = Function(Map<String, dynamic> evt, String id);
|
||||
@ -723,15 +724,9 @@ class CursorModel with ChangeNotifier {
|
||||
return h - thresh;
|
||||
}
|
||||
|
||||
touch(double x, double y, MouseButtons button) {
|
||||
moveLocal(x, y);
|
||||
parent.target?.moveMouse(_x, _y);
|
||||
parent.target?.tap(button);
|
||||
}
|
||||
|
||||
move(double x, double y) {
|
||||
moveLocal(x, y);
|
||||
parent.target?.moveMouse(_x, _y);
|
||||
parent.target?.inputModel.moveMouse(_x, _y);
|
||||
}
|
||||
|
||||
moveLocal(double x, double y) {
|
||||
@ -746,7 +741,7 @@ class CursorModel with ChangeNotifier {
|
||||
reset() {
|
||||
_x = _displayOriginX;
|
||||
_y = _displayOriginY;
|
||||
parent.target?.moveMouse(_x, _y);
|
||||
parent.target?.inputModel.moveMouse(_x, _y);
|
||||
parent.target?.canvasModel.clear(true);
|
||||
notifyListeners();
|
||||
}
|
||||
@ -757,7 +752,7 @@ class CursorModel with ChangeNotifier {
|
||||
final scale = parent.target?.canvasModel.scale ?? 1.0;
|
||||
_x += dx / scale;
|
||||
_y += dy / scale;
|
||||
parent.target?.moveMouse(_x, _y);
|
||||
parent.target?.inputModel.moveMouse(_x, _y);
|
||||
notifyListeners();
|
||||
return;
|
||||
}
|
||||
@ -822,7 +817,7 @@ class CursorModel with ChangeNotifier {
|
||||
parent.target?.canvasModel.panY(-dy);
|
||||
}
|
||||
|
||||
parent.target?.moveMouse(_x, _y);
|
||||
parent.target?.inputModel.moveMouse(_x, _y);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@ -892,7 +887,7 @@ class CursorModel with ChangeNotifier {
|
||||
_displayOriginY = y;
|
||||
_x = x + 1;
|
||||
_y = y + 1;
|
||||
parent.target?.moveMouse(x, y);
|
||||
parent.target?.inputModel.moveMouse(x, y);
|
||||
parent.target?.canvasModel.resetOffset();
|
||||
notifyListeners();
|
||||
}
|
||||
@ -903,7 +898,7 @@ class CursorModel with ChangeNotifier {
|
||||
_displayOriginY = y;
|
||||
_x = xCursor;
|
||||
_y = yCursor;
|
||||
parent.target?.moveMouse(x, y);
|
||||
parent.target?.inputModel.moveMouse(x, y);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@ -1009,31 +1004,11 @@ class RecordingModel with ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
/// Mouse button enum.
|
||||
enum MouseButtons { left, right, wheel }
|
||||
|
||||
extension ToString on MouseButtons {
|
||||
String get value {
|
||||
switch (this) {
|
||||
case MouseButtons.left:
|
||||
return 'left';
|
||||
case MouseButtons.right:
|
||||
return 'right';
|
||||
case MouseButtons.wheel:
|
||||
return 'wheel';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum ConnType { defaultConn, fileTransfer, portForward, rdp }
|
||||
|
||||
/// Flutter state manager and data communication with the Rust core.
|
||||
class FFI {
|
||||
var id = '';
|
||||
var shift = false;
|
||||
var ctrl = false;
|
||||
var alt = false;
|
||||
var command = false;
|
||||
var version = '';
|
||||
var connType = ConnType.defaultConn;
|
||||
|
||||
@ -1051,6 +1026,7 @@ class FFI {
|
||||
late final UserModel userModel; // global
|
||||
late final QualityMonitorModel qualityMonitorModel; // session
|
||||
late final RecordingModel recordingModel; // recording
|
||||
late final InputModel inputModel; // session
|
||||
|
||||
FFI() {
|
||||
imageModel = ImageModel(WeakReference(this));
|
||||
@ -1064,89 +1040,11 @@ class FFI {
|
||||
userModel = UserModel(WeakReference(this));
|
||||
qualityMonitorModel = QualityMonitorModel(WeakReference(this));
|
||||
recordingModel = RecordingModel(WeakReference(this));
|
||||
inputModel = InputModel(WeakReference(this));
|
||||
}
|
||||
|
||||
/// Send a mouse tap event(down and up).
|
||||
tap(MouseButtons button) {
|
||||
sendMouse('down', button);
|
||||
sendMouse('up', button);
|
||||
}
|
||||
|
||||
/// Send scroll event with scroll distance [y].
|
||||
scroll(int y) {
|
||||
bind.sessionSendMouse(
|
||||
id: id,
|
||||
msg: json
|
||||
.encode(modify({'id': id, 'type': 'wheel', 'y': y.toString()})));
|
||||
}
|
||||
|
||||
/// Reset key modifiers to false, including [shift], [ctrl], [alt] and [command].
|
||||
resetModifiers() {
|
||||
shift = ctrl = alt = command = false;
|
||||
}
|
||||
|
||||
/// Modify the given modifier map [evt] based on current modifier key status.
|
||||
Map<String, String> modify(Map<String, String> evt) {
|
||||
if (ctrl) evt['ctrl'] = 'true';
|
||||
if (shift) evt['shift'] = 'true';
|
||||
if (alt) evt['alt'] = 'true';
|
||||
if (command) evt['command'] = 'true';
|
||||
return evt;
|
||||
}
|
||||
|
||||
/// Send mouse press event.
|
||||
sendMouse(String type, MouseButtons button) {
|
||||
if (!ffiModel.keyboard()) return;
|
||||
bind.sessionSendMouse(
|
||||
id: id,
|
||||
msg: json.encode(modify({'type': type, 'buttons': button.value})));
|
||||
}
|
||||
|
||||
/// Send raw Key Event
|
||||
inputRawKey(String name, int keyCode, int scanCode, bool down) {
|
||||
bind.sessionHandleFlutterKeyEvent(
|
||||
id: id,
|
||||
name: name,
|
||||
keycode: keyCode,
|
||||
scancode: scanCode,
|
||||
downOrUp: down);
|
||||
}
|
||||
|
||||
enterOrLeave(bool enter) {
|
||||
// Fix status
|
||||
if (!enter) {
|
||||
resetModifiers();
|
||||
}
|
||||
bind.sessionEnterOrLeave(id: id, enter: enter);
|
||||
}
|
||||
|
||||
/// Send key stroke event.
|
||||
/// [down] indicates the key's state(down or up).
|
||||
/// [press] indicates a click event(down and up).
|
||||
inputKey(String name, {bool? down, bool? press}) {
|
||||
if (!ffiModel.keyboard()) return;
|
||||
bind.sessionInputKey(
|
||||
id: id,
|
||||
name: name,
|
||||
down: down ?? false,
|
||||
press: press ?? true,
|
||||
alt: alt,
|
||||
ctrl: ctrl,
|
||||
shift: shift,
|
||||
command: command);
|
||||
}
|
||||
|
||||
/// Send mouse movement event with distance in [x] and [y].
|
||||
moveMouse(double x, double y) {
|
||||
if (!ffiModel.keyboard()) return;
|
||||
var x2 = x.toInt();
|
||||
var y2 = y.toInt();
|
||||
bind.sessionSendMouse(
|
||||
id: id, msg: json.encode(modify({'x': '$x2', 'y': '$y2'})));
|
||||
}
|
||||
|
||||
/// Connect with the given [id]. Only transfer file if [isFileTransfer], only port forward if [isPortForward].
|
||||
connect(String id,
|
||||
/// Start with the given [id]. Only transfer file if [isFileTransfer], only port forward if [isPortForward].
|
||||
void start(String id,
|
||||
{bool isFileTransfer = false,
|
||||
bool isPortForward = false,
|
||||
double tabBarHeight = 0.0}) {
|
||||
@ -1190,7 +1088,7 @@ class FFI {
|
||||
}
|
||||
|
||||
/// Login with [password], choose if the client should [remember] it.
|
||||
login(String id, String password, bool remember) {
|
||||
void login(String id, String password, bool remember) {
|
||||
bind.sessionLogin(id: id, password: password, remember: remember);
|
||||
}
|
||||
|
||||
@ -1207,89 +1105,11 @@ class FFI {
|
||||
cursorModel.clear();
|
||||
ffiModel.clear();
|
||||
canvasModel.clear();
|
||||
resetModifiers();
|
||||
inputModel.resetModifiers();
|
||||
debugPrint('model $id closed');
|
||||
}
|
||||
|
||||
handleMouse(Map<String, dynamic> evt, {double tabBarHeight = 0.0}) {
|
||||
var type = '';
|
||||
var isMove = false;
|
||||
switch (evt['type']) {
|
||||
case 'mousedown':
|
||||
type = 'down';
|
||||
break;
|
||||
case 'mouseup':
|
||||
type = 'up';
|
||||
break;
|
||||
case 'mousemove':
|
||||
isMove = true;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
evt['type'] = type;
|
||||
double x = evt['x'];
|
||||
double y = max(0.0, (evt['y'] as double) - tabBarHeight);
|
||||
if (isMove) {
|
||||
canvasModel.moveDesktopMouse(x, y);
|
||||
}
|
||||
final d = ffiModel.display;
|
||||
if (canvasModel.scrollStyle == ScrollStyle.scrollbar) {
|
||||
final imageWidth = d.width * canvasModel.scale;
|
||||
final imageHeight = d.height * canvasModel.scale;
|
||||
x += imageWidth * canvasModel.scrollX;
|
||||
y += imageHeight * canvasModel.scrollY;
|
||||
|
||||
// boxed size is a center widget
|
||||
if (canvasModel.size.width > imageWidth) {
|
||||
x -= ((canvasModel.size.width - imageWidth) / 2);
|
||||
}
|
||||
if (canvasModel.size.height > imageHeight) {
|
||||
y -= ((canvasModel.size.height - imageHeight) / 2);
|
||||
}
|
||||
} else {
|
||||
x -= canvasModel.x;
|
||||
y -= canvasModel.y;
|
||||
}
|
||||
|
||||
x /= canvasModel.scale;
|
||||
y /= canvasModel.scale;
|
||||
x += d.x;
|
||||
y += d.y;
|
||||
if (type != '') {
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
// fix mouse out of bounds
|
||||
x = min(max(0.0, x), d.width.toDouble());
|
||||
y = min(max(0.0, y), d.height.toDouble());
|
||||
evt['x'] = '${x.round()}';
|
||||
evt['y'] = '${y.round()}';
|
||||
var buttons = '';
|
||||
switch (evt['buttons']) {
|
||||
case 1:
|
||||
buttons = 'left';
|
||||
break;
|
||||
case 2:
|
||||
buttons = 'right';
|
||||
break;
|
||||
case 4:
|
||||
buttons = 'wheel';
|
||||
break;
|
||||
}
|
||||
evt['buttons'] = buttons;
|
||||
bind.sessionSendMouse(id: id, msg: json.encode(evt));
|
||||
}
|
||||
|
||||
listenToMouse(bool yesOrNo) {
|
||||
if (yesOrNo) {
|
||||
platformFFI.startDesktopWebListener();
|
||||
} else {
|
||||
platformFFI.stopDesktopWebListener();
|
||||
}
|
||||
}
|
||||
|
||||
setMethodCallHandler(FMethod callback) {
|
||||
void setMethodCallHandler(FMethod callback) {
|
||||
platformFFI.setMethodCallHandler(callback);
|
||||
}
|
||||
|
||||
@ -1324,8 +1144,8 @@ class PeerInfo {
|
||||
List<Display> displays = [];
|
||||
}
|
||||
|
||||
savePreference(String id, double xCursor, double yCursor, double xCanvas,
|
||||
double yCanvas, double scale, int currentDisplay) async {
|
||||
Future<void> savePreference(String id, double xCursor, double yCursor,
|
||||
double xCanvas, double yCanvas, double scale, int currentDisplay) async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
final p = <String, dynamic>{};
|
||||
p['xCursor'] = xCursor;
|
||||
@ -1346,12 +1166,12 @@ Future<Map<String, dynamic>?> getPreference(String id) async {
|
||||
return m;
|
||||
}
|
||||
|
||||
removePreference(String id) async {
|
||||
void removePreference(String id) async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
prefs.remove('peer$id');
|
||||
}
|
||||
|
||||
initializeCursorAndCanvas(FFI ffi) async {
|
||||
Future<void> initializeCursorAndCanvas(FFI ffi) async {
|
||||
var p = await getPreference(ffi.id);
|
||||
int currentDisplay = 0;
|
||||
if (p != null) {
|
||||
@ -1371,16 +1191,3 @@ initializeCursorAndCanvas(FFI ffi) async {
|
||||
ffi.ffiModel.display.x, ffi.ffiModel.display.y, xCursor, yCursor);
|
||||
ffi.canvasModel.update(xCanvas, yCanvas, scale);
|
||||
}
|
||||
|
||||
/// Translate text based on the pre-defined dictionary.
|
||||
/// note: params [FFI?] can be used to replace global FFI implementation
|
||||
/// for example: during global initialization, gFFI not exists yet.
|
||||
// String translate(String name, {FFI? ffi}) {
|
||||
// if (name.startsWith('Failed to') && name.contains(': ')) {
|
||||
// return name.split(': ').map((x) => translate(x)).join(': ');
|
||||
// }
|
||||
// var a = 'translate';
|
||||
// var b = '{"locale": "$localeName", "text": "$name"}';
|
||||
//
|
||||
// return (ffi ?? gFFI).getByName(a, b);
|
||||
// }
|
||||
|
Loading…
Reference in New Issue
Block a user