From 5696c8ce97f73810e8cc5b3a5fe3f6d6a3a49fa7 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Sat, 21 Aug 2021 17:18:14 +0800 Subject: [PATCH] touch mode and reset canvas --- flutter_hbb/lib/model.dart | 37 ++++- flutter_hbb/lib/remote_page.dart | 266 +++++++++++++++++-------------- 2 files changed, 183 insertions(+), 120 deletions(-) diff --git a/flutter_hbb/lib/model.dart b/flutter_hbb/lib/model.dart index 01d251070..397b5b3fc 100644 --- a/flutter_hbb/lib/model.dart +++ b/flutter_hbb/lib/model.dart @@ -299,6 +299,7 @@ class CanvasModel with ChangeNotifier { _x = 0; _y = 0; _scale = 1.0; + notifyListeners(); } } @@ -341,8 +342,40 @@ class CursorModel with ChangeNotifier { return h - thresh; } - void updatePan(double dx, double dy) { + void touch(double x, double y, bool right) { + final scale = FFI.canvasModel.scale; + final xoffset = FFI.canvasModel.x; + final yoffset = FFI.canvasModel.y; + _x = (x - xoffset) / scale + _displayOriginX; + _y = (y - yoffset) / scale + _displayOriginY; + FFI.moveMouse(_x, _y); + FFI.tap(right); + notifyListeners(); + } + + void reset() { + _x = _displayOriginX; + _y = _displayOriginY; + FFI.moveMouse(_x, _y); + FFI.canvasModel.clear(); + notifyListeners(); + } + + void updatePan(double dx, double dy, bool touchMode, bool drag) { if (FFI.imageModel.image == null) return; + if (touchMode) { + if (drag) { + final scale = FFI.canvasModel.scale; + _x += dx / scale; + _y += dy / scale; + FFI.moveMouse(_x, _y); + notifyListeners(); + } else { + FFI.canvasModel.panX(dx); + FFI.canvasModel.panY(dy); + } + return; + } final scale = FFI.canvasModel.scale; dx /= scale; dy /= scale; @@ -750,6 +783,8 @@ final langs = >{ 'Paste': '粘贴', 'Are you sure to close the connection?': '是否确认关闭连接?', 'Download new version': '下载新版本', + 'Touch mode': '触屏模式', + 'Reset canvas': '重置画布', }, 'en': {} }; diff --git a/flutter_hbb/lib/remote_page.dart b/flutter_hbb/lib/remote_page.dart index afff9ab9d..f936a075f 100644 --- a/flutter_hbb/lib/remote_page.dart +++ b/flutter_hbb/lib/remote_page.dart @@ -40,6 +40,7 @@ class _RemotePageState extends State { final FocusNode _focusNode = FocusNode(); var _showKeyboard = false; var _reconnects = 1; + var _touchMode = false; @override void initState() { @@ -53,6 +54,7 @@ class _RemotePageState extends State { }); Wakelock.enable(); loadingCancelCallback = () => _interval.cancel(); + _touchMode = FFI.getByName('peer_option', "touch-mode") != ''; } @override @@ -306,59 +308,65 @@ class _RemotePageState extends State { ) : null, body: FlutterEasyLoading( - child: GestureDetector( - onLongPress: () { - if (_drag || _scroll) return; - FFI.tap(true); - }, - onTap: () { - if (_drag || _scroll) return; - FFI.tap(_right); - }, - onScaleStart: (details) { - _scale = 1; - _xOffset = details.focalPoint.dx; - _yOffset = _yOffset0 = details.focalPoint.dy; - if (_drag) { - FFI.sendMouse('down', 'left'); - } - }, - onScaleUpdate: (details) { - var scale = details.scale; - if (scale == 1) { - if (!_scroll) { - var x = details.focalPoint.dx; - var y = details.focalPoint.dy; - var dx = x - _xOffset; - var dy = y - _yOffset; - FFI.cursorModel.updatePan(dx, dy); - _xOffset = x; - _yOffset = y; - } else { - _xOffset = details.focalPoint.dx; - _yOffset = details.focalPoint.dy; - } - } else if (!_drag && !_scroll) { - FFI.canvasModel.updateScale(scale / _scale); - _scale = scale; - } - }, - onScaleEnd: (details) { - if (_drag) { - FFI.sendMouse('up', 'left'); - setState(resetMouse); - } else if (_scroll) { - var dy = (_yOffset - _yOffset0) / 10; - if (dy.abs() > 0.1) { - if (dy > 0 && dy < 1) dy = 1; - if (dy < 0 && dy > -1) dy = -1; - FFI.scroll(dy); - } - } - }, - child: Container( - color: Colors.black, - child: SafeArea( + child: Container( + color: Colors.black, + child: SafeArea( + child: GestureDetector( + onLongPress: () { + if (_drag || _scroll) return; + FFI.tap(true); + }, + onTapUp: (details) { + if (_drag || _scroll) return; + if (_touchMode) { + FFI.cursorModel.touch(details.localPosition.dx, + details.localPosition.dy, _right); + } else { + FFI.tap(_right); + } + }, + onScaleStart: (details) { + _scale = 1; + _xOffset = details.focalPoint.dx; + _yOffset = _yOffset0 = details.focalPoint.dy; + if (_drag) { + FFI.sendMouse('down', 'left'); + } + }, + onScaleUpdate: (details) { + var scale = details.scale; + if (scale == 1) { + if (!_scroll) { + var x = details.focalPoint.dx; + var y = details.focalPoint.dy; + var dx = x - _xOffset; + var dy = y - _yOffset; + FFI.cursorModel + .updatePan(dx, dy, _touchMode, _drag); + _xOffset = x; + _yOffset = y; + } else { + _xOffset = details.focalPoint.dx; + _yOffset = details.focalPoint.dy; + } + } else if (!_drag && !_scroll) { + FFI.canvasModel.updateScale(scale / _scale); + _scale = scale; + } + }, + onScaleEnd: (details) { + if (_drag) { + FFI.sendMouse('up', 'left'); + setState(resetMouse); + } else if (_scroll) { + var dy = (_yOffset - _yOffset0) / 10; + if (dy.abs() > 0.1) { + if (dy > 0 && dy < 1) dy = 1; + if (dy < 0 && dy > -1) dy = -1; + FFI.scroll(dy); + } + } + }, child: Container( color: MyTheme.canvasColor, child: Stack(children: [ @@ -388,6 +396,92 @@ class _RemotePageState extends State { ); } + void showActions(BuildContext context) { + final size = MediaQuery.of(context).size; + final x = 120.0; + final y = size.height; + final more = >[]; + if (FFI.ffiModel.pi.version.isNotEmpty) { + more.add(PopupMenuItem( + child: Text(translate('Refresh')), value: 'refresh')); + } + if (FFI.ffiModel.permissions['keyboard'] != false && + FFI.ffiModel.permissions['clipboard'] != false) { + more.add(PopupMenuItem( + child: Text(translate('Paste')), value: 'paste')); + } + more.add(PopupMenuItem( + child: Row( + children: ([ + Container(width: 100.0, child: Text(translate('OS Password'))), + TextButton( + style: flatButtonStyle, + onPressed: () { + Navigator.pop(context); + showSetOSPassword(context, false); + }, + child: Icon(Icons.edit, color: MyTheme.accent), + ) + ])), + value: 'enter_os_password')); + more.add(PopupMenuItem( + child: Row( + children: ([ + Container(width: 100.0, child: Text(translate('Touch mode'))), + Padding(padding: EdgeInsets.symmetric(horizontal: 16.0)), + Icon( + _touchMode + ? Icons.check_box_outlined + : Icons.check_box_outline_blank, + color: MyTheme.accent) + ])), + value: 'touch_mode')); + more.add(PopupMenuItem( + child: Text(translate('Reset canvas')), value: 'reset_canvas')); + () async { + var value = await showMenu( + context: context, + position: RelativeRect.fromLTRB(x, y, x, y), + items: [ + PopupMenuItem( + child: Text(translate('Insert') + ' Ctrl + Alt + Del'), + value: 'cad'), + PopupMenuItem( + child: Text(translate('Insert Lock')), value: 'lock'), + ] + + more, + elevation: 8, + ); + if (value == 'cad') { + FFI.setByName('ctrl_alt_del'); + } else if (value == 'lock') { + FFI.setByName('lock_screen'); + } else if (value == 'refresh') { + FFI.setByName('refresh'); + } else if (value == 'paste') { + () async { + ClipboardData data = await Clipboard.getData(Clipboard.kTextPlain); + if (data.text != null) { + FFI.setByName('input_string', '${data.text}'); + } + }(); + } else if (value == 'enter_os_password') { + var password = FFI.getByName('peer_option', "os-password"); + if (password != "") { + FFI.setByName('input_os_password', password); + } else { + showSetOSPassword(context, true); + } + } else if (value == 'touch_mode') { + _touchMode = !_touchMode; + final v = _touchMode ? 'Y' : ''; + FFI.setByName('peer_option', '{"name": "touch-mode", "value": "${v}"}'); + } else if (value == 'reset_canvas') { + FFI.cursorModel.reset(); + } + }(); + } + void close() { msgbox('', 'Close', 'Are you sure to close the connection?', context); } @@ -806,72 +900,6 @@ void showOptions(BuildContext context) { }, () async => true, true, 0); } -void showActions(BuildContext context) { - final size = MediaQuery.of(context).size; - final x = 120.0; - final y = size.height; - final more = >[]; - if (FFI.ffiModel.pi.version.isNotEmpty) { - more.add(PopupMenuItem( - child: Text(translate('Refresh')), value: 'refresh')); - } - if (FFI.ffiModel.permissions['keyboard'] != false && - FFI.ffiModel.permissions['clipboard'] != false) { - more.add( - PopupMenuItem(child: Text(translate('Paste')), value: 'paste')); - } - more.add(PopupMenuItem( - child: Row( - children: ([ - Text(translate('OS Password')), - TextButton( - style: flatButtonStyle, - onPressed: () { - Navigator.pop(context); - showSetOSPassword(context, false); - }, - child: Icon(Icons.edit), - ) - ])), - value: 'enter_os_password')); - () async { - var value = await showMenu( - context: context, - position: RelativeRect.fromLTRB(x, y, x, y), - items: [ - PopupMenuItem( - child: Text(translate('Insert') + ' Ctrl + Alt + Del'), - value: 'cad'), - PopupMenuItem( - child: Text(translate('Insert Lock')), value: 'lock'), - ] + - more, - elevation: 8, - ); - if (value == 'cad') { - FFI.setByName('ctrl_alt_del'); - } else if (value == 'lock') { - FFI.setByName('lock_screen'); - } else if (value == 'refresh') { - FFI.setByName('refresh'); - } else if (value == 'paste') { - () async { - ClipboardData data = await Clipboard.getData(Clipboard.kTextPlain); - if (data.text != null) { - FFI.setByName('input_string', '${data.text}'); - } - }(); - } else if (value == 'enter_os_password') { - var password = FFI.getByName('peer_option', "os-password"); - if (password != "") { - FFI.setByName('input_os_password', password); - } else { - showSetOSPassword(context, true); - } - } - }(); -} - void showSetOSPassword(BuildContext context, bool login) { final controller = TextEditingController(); var password = FFI.getByName('peer_option', "os-password");