commit
						829b3b59f9
					
				| @ -2,6 +2,7 @@ import 'package:flutter/material.dart'; | |||||||
| import 'package:flutter/services.dart'; | import 'package:flutter/services.dart'; | ||||||
| import 'package:flutter_hbb/models/state_model.dart'; | import 'package:flutter_hbb/models/state_model.dart'; | ||||||
| 
 | 
 | ||||||
|  | import '../../common.dart'; | ||||||
| import '../../models/input_model.dart'; | import '../../models/input_model.dart'; | ||||||
| 
 | 
 | ||||||
| class RawKeyFocusScope extends StatelessWidget { | class RawKeyFocusScope extends StatelessWidget { | ||||||
| @ -19,6 +20,13 @@ class RawKeyFocusScope extends StatelessWidget { | |||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|  |     final FocusOnKeyCallback? onKey; | ||||||
|  |     if (isAndroid) { | ||||||
|  |       onKey = inputModel.handleRawKeyEvent; | ||||||
|  |     } else { | ||||||
|  |       onKey = stateGlobal.grabKeyboard ? inputModel.handleRawKeyEvent : null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     return FocusScope( |     return FocusScope( | ||||||
|         autofocus: true, |         autofocus: true, | ||||||
|         child: Focus( |         child: Focus( | ||||||
| @ -26,8 +34,7 @@ class RawKeyFocusScope extends StatelessWidget { | |||||||
|             canRequestFocus: true, |             canRequestFocus: true, | ||||||
|             focusNode: focusNode, |             focusNode: focusNode, | ||||||
|             onFocusChange: onFocusChange, |             onFocusChange: onFocusChange, | ||||||
|             onKey: |             onKey: onKey, | ||||||
|                 stateGlobal.grabKeyboard ? inputModel.handleRawKeyEvent : null, |  | ||||||
|             child: child)); |             child: child)); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -21,6 +21,7 @@ import '../../mobile/widgets/dialog.dart'; | |||||||
| import '../../models/model.dart'; | import '../../models/model.dart'; | ||||||
| import '../../models/platform_model.dart'; | import '../../models/platform_model.dart'; | ||||||
| import '../../common/shared_state.dart'; | import '../../common/shared_state.dart'; | ||||||
|  | import '../../utils/image.dart'; | ||||||
| import '../widgets/remote_menubar.dart'; | import '../widgets/remote_menubar.dart'; | ||||||
| import '../widgets/kb_layout_type_chooser.dart'; | import '../widgets/kb_layout_type_chooser.dart'; | ||||||
| 
 | 
 | ||||||
| @ -685,40 +686,3 @@ class CursorPaint extends StatelessWidget { | |||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 |  | ||||||
| class ImagePainter extends CustomPainter { |  | ||||||
|   ImagePainter({ |  | ||||||
|     required this.image, |  | ||||||
|     required this.x, |  | ||||||
|     required this.y, |  | ||||||
|     required this.scale, |  | ||||||
|   }); |  | ||||||
| 
 |  | ||||||
|   ui.Image? image; |  | ||||||
|   double x; |  | ||||||
|   double y; |  | ||||||
|   double scale; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   void paint(Canvas canvas, Size size) { |  | ||||||
|     if (image == null) return; |  | ||||||
|     if (x.isNaN || y.isNaN) return; |  | ||||||
|     canvas.scale(scale, scale); |  | ||||||
|     // https://github.com/flutter/flutter/issues/76187#issuecomment-784628161 |  | ||||||
|     // https://api.flutter-io.cn/flutter/dart-ui/FilterQuality.html |  | ||||||
|     var paint = Paint(); |  | ||||||
|     if ((scale - 1.0).abs() > 0.001) { |  | ||||||
|       paint.filterQuality = FilterQuality.medium; |  | ||||||
|       if (scale > 10.00000) { |  | ||||||
|         paint.filterQuality = FilterQuality.high; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     canvas.drawImage( |  | ||||||
|         image!, Offset(x.toInt().toDouble(), y.toInt().toDouble()), paint); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   bool shouldRepaint(CustomPainter oldDelegate) { |  | ||||||
|     return oldDelegate != this; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -17,6 +17,7 @@ import '../../common/widgets/remote_input.dart'; | |||||||
| import '../../models/input_model.dart'; | import '../../models/input_model.dart'; | ||||||
| import '../../models/model.dart'; | import '../../models/model.dart'; | ||||||
| import '../../models/platform_model.dart'; | import '../../models/platform_model.dart'; | ||||||
|  | import '../../utils/image.dart'; | ||||||
| import '../widgets/dialog.dart'; | import '../widgets/dialog.dart'; | ||||||
| import '../widgets/gestures.dart'; | import '../widgets/gestures.dart'; | ||||||
| 
 | 
 | ||||||
| @ -228,13 +229,18 @@ class _RemotePageState extends State<RemotePage> { | |||||||
|         return false; |         return false; | ||||||
|       }, |       }, | ||||||
|       child: getRawPointerAndKeyBody(Scaffold( |       child: getRawPointerAndKeyBody(Scaffold( | ||||||
|           // resizeToAvoidBottomInset: true, |           // workaround for https://github.com/rustdesk/rustdesk/issues/3131 | ||||||
|  |           floatingActionButtonLocation: hideKeyboard | ||||||
|  |               ? FABLocation(FloatingActionButtonLocation.endFloat, 0, -35) | ||||||
|  |               : null, | ||||||
|           floatingActionButton: !showActionButton |           floatingActionButton: !showActionButton | ||||||
|               ? null |               ? null | ||||||
|               : FloatingActionButton( |               : FloatingActionButton( | ||||||
|                   mini: !hideKeyboard, |                   mini: !hideKeyboard, | ||||||
|                   child: Icon( |                   child: Icon( | ||||||
|                       hideKeyboard ? Icons.expand_more : Icons.expand_less), |                     hideKeyboard ? Icons.expand_more : Icons.expand_less, | ||||||
|  |                     color: Colors.white, | ||||||
|  |                   ), | ||||||
|                   backgroundColor: MyTheme.accent, |                   backgroundColor: MyTheme.accent, | ||||||
|                   onPressed: () { |                   onPressed: () { | ||||||
|                     setState(() { |                     setState(() { | ||||||
| @ -575,9 +581,10 @@ class _RemotePageState extends State<RemotePage> { | |||||||
|           child: Text(translate('Reset canvas')), value: 'reset_canvas')); |           child: Text(translate('Reset canvas')), value: 'reset_canvas')); | ||||||
|     } |     } | ||||||
|     if (perms['keyboard'] != false) { |     if (perms['keyboard'] != false) { | ||||||
|       more.add(PopupMenuItem<String>( |       // * Currently mobile does not enable map mode | ||||||
|           child: Text(translate('Physical Keyboard Input Mode')), |       // more.add(PopupMenuItem<String>( | ||||||
|           value: 'input-mode')); |       //     child: Text(translate('Physical Keyboard Input Mode')), | ||||||
|  |       //     value: 'input-mode')); | ||||||
|       if (pi.platform == kPeerPlatformLinux || pi.sasEnabled) { |       if (pi.platform == kPeerPlatformLinux || pi.sasEnabled) { | ||||||
|         more.add(PopupMenuItem<String>( |         more.add(PopupMenuItem<String>( | ||||||
|             child: Text('${translate('Insert')} Ctrl + Alt + Del'), |             child: Text('${translate('Insert')} Ctrl + Alt + Del'), | ||||||
| @ -632,8 +639,9 @@ class _RemotePageState extends State<RemotePage> { | |||||||
|       ); |       ); | ||||||
|       if (value == 'cad') { |       if (value == 'cad') { | ||||||
|         bind.sessionCtrlAltDel(id: widget.id); |         bind.sessionCtrlAltDel(id: widget.id); | ||||||
|       } else if (value == 'input-mode') { |         // * Currently mobile does not enable map mode | ||||||
|         changePhysicalKeyboardInputMode(); |         // } else if (value == 'input-mode') { | ||||||
|  |         //   changePhysicalKeyboardInputMode(); | ||||||
|       } else if (value == 'lock') { |       } else if (value == 'lock') { | ||||||
|         bind.sessionLockScreen(id: widget.id); |         bind.sessionLockScreen(id: widget.id); | ||||||
|       } else if (value == 'block-input') { |       } else if (value == 'block-input') { | ||||||
| @ -695,26 +703,26 @@ class _RemotePageState extends State<RemotePage> { | |||||||
|             })); |             })); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   void changePhysicalKeyboardInputMode() async { |   // * Currently mobile does not enable map mode | ||||||
|     var current = await bind.sessionGetKeyboardMode(id: widget.id) ?? "legacy"; |   // void changePhysicalKeyboardInputMode() async { | ||||||
|     gFFI.dialogManager.show((setState, close) { |   //   var current = await bind.sessionGetKeyboardMode(id: widget.id) ?? "legacy"; | ||||||
|       void setMode(String? v) async { |   //   gFFI.dialogManager.show((setState, close) { | ||||||
|         await bind.sessionPeerOption( |   //     void setMode(String? v) async { | ||||||
|             id: widget.id, name: "keyboard-mode", value: v ?? ""); |   //       await bind.sessionSetKeyboardMode(id: widget.id, value: v ?? ""); | ||||||
|         setState(() => current = v ?? ''); |   //       setState(() => current = v ?? ''); | ||||||
|         Future.delayed(Duration(milliseconds: 300), close); |   //       Future.delayed(Duration(milliseconds: 300), close); | ||||||
|       } |   //     } | ||||||
| 
 |   // | ||||||
|       return CustomAlertDialog( |   //     return CustomAlertDialog( | ||||||
|           title: Text(translate('Physical Keyboard Input Mode')), |   //         title: Text(translate('Physical Keyboard Input Mode')), | ||||||
|           content: Column(mainAxisSize: MainAxisSize.min, children: [ |   //         content: Column(mainAxisSize: MainAxisSize.min, children: [ | ||||||
|             getRadio('Legacy mode', 'legacy', current, setMode, |   //           getRadio('Legacy mode', 'legacy', current, setMode, | ||||||
|                 contentPadding: EdgeInsets.zero), |   //               contentPadding: EdgeInsets.zero), | ||||||
|             getRadio('Map mode', 'map', current, setMode, |   //           getRadio('Map mode', 'map', current, setMode, | ||||||
|                 contentPadding: EdgeInsets.zero), |   //               contentPadding: EdgeInsets.zero), | ||||||
|           ])); |   //         ])); | ||||||
|     }, clickMaskDismiss: true); |   //   }, clickMaskDismiss: true); | ||||||
|   } |   // } | ||||||
| 
 | 
 | ||||||
|   Widget getHelpTools() { |   Widget getHelpTools() { | ||||||
|     final keyboard = isKeyboardShown(); |     final keyboard = isKeyboardShown(); | ||||||
| @ -806,6 +814,9 @@ class _RemotePageState extends State<RemotePage> { | |||||||
|       wrap('End', () { |       wrap('End', () { | ||||||
|         inputModel.inputKey('VK_END'); |         inputModel.inputKey('VK_END'); | ||||||
|       }), |       }), | ||||||
|  |       wrap('Ins', () { | ||||||
|  |         inputModel.inputKey('VK_INSERT'); | ||||||
|  |       }), | ||||||
|       wrap('Del', () { |       wrap('Del', () { | ||||||
|         inputModel.inputKey('VK_DELETE'); |         inputModel.inputKey('VK_DELETE'); | ||||||
|       }), |       }), | ||||||
| @ -893,32 +904,6 @@ class CursorPaint extends StatelessWidget { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class ImagePainter extends CustomPainter { |  | ||||||
|   ImagePainter({ |  | ||||||
|     required this.image, |  | ||||||
|     required this.x, |  | ||||||
|     required this.y, |  | ||||||
|     required this.scale, |  | ||||||
|   }); |  | ||||||
| 
 |  | ||||||
|   ui.Image? image; |  | ||||||
|   double x; |  | ||||||
|   double y; |  | ||||||
|   double scale; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   void paint(Canvas canvas, Size size) { |  | ||||||
|     if (image == null) return; |  | ||||||
|     canvas.scale(scale, scale); |  | ||||||
|     canvas.drawImage(image!, Offset(x, y), Paint()); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   bool shouldRepaint(CustomPainter oldDelegate) { |  | ||||||
|     return oldDelegate != this; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void showOptions( | void showOptions( | ||||||
|     BuildContext context, String id, OverlayDialogManager dialogManager) async { |     BuildContext context, String id, OverlayDialogManager dialogManager) async { | ||||||
|   String quality = |   String quality = | ||||||
| @ -1134,3 +1119,16 @@ void sendPrompt(bool isMac, String key) { | |||||||
|     gFFI.inputModel.ctrl = old; |     gFFI.inputModel.ctrl = old; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | class FABLocation extends FloatingActionButtonLocation { | ||||||
|  |   FloatingActionButtonLocation location; | ||||||
|  |   double offsetX; | ||||||
|  |   double offsetY; | ||||||
|  |   FABLocation(this.location, this.offsetX, this.offsetY); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Offset getOffset(ScaffoldPrelayoutGeometry scaffoldGeometry) { | ||||||
|  |     final offset = location.getOffset(scaffoldGeometry); | ||||||
|  |     return Offset(offset.dx + offsetX, offset.dy + offsetY); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | |||||||
| @ -2,8 +2,6 @@ import 'package:flutter/material.dart'; | |||||||
| import 'package:flutter_hbb/common.dart'; | import 'package:flutter_hbb/common.dart'; | ||||||
| import 'package:toggle_switch/toggle_switch.dart'; | import 'package:toggle_switch/toggle_switch.dart'; | ||||||
| 
 | 
 | ||||||
| import '../../models/model.dart'; |  | ||||||
| 
 |  | ||||||
| class GestureIcons { | class GestureIcons { | ||||||
|   static const String _family = 'gestureicons'; |   static const String _family = 'gestureicons'; | ||||||
| 
 | 
 | ||||||
| @ -79,7 +77,10 @@ class _GestureHelpState extends State<GestureHelp> { | |||||||
|               children: <Widget>[ |               children: <Widget>[ | ||||||
|                 ToggleSwitch( |                 ToggleSwitch( | ||||||
|                   initialLabelIndex: _selectedIndex, |                   initialLabelIndex: _selectedIndex, | ||||||
|                   inactiveBgColor: MyTheme.darkGray, |                   activeFgColor: Colors.white, | ||||||
|  |                   inactiveFgColor: Colors.white60, | ||||||
|  |                   activeBgColor: [MyTheme.accent], | ||||||
|  |                   inactiveBgColor: Theme.of(context).hintColor, | ||||||
|                   totalSwitches: 2, |                   totalSwitches: 2, | ||||||
|                   minWidth: 150, |                   minWidth: 150, | ||||||
|                   fontSize: 15, |                   fontSize: 15, | ||||||
| @ -188,7 +189,7 @@ class GestureInfo extends StatelessWidget { | |||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return Container( |     return Container( | ||||||
|         width: this.width, |         width: width, | ||||||
|         child: Column( |         child: Column( | ||||||
|           children: [ |           children: [ | ||||||
|             Icon( |             Icon( | ||||||
| @ -199,11 +200,14 @@ class GestureInfo extends StatelessWidget { | |||||||
|             SizedBox(height: 6), |             SizedBox(height: 6), | ||||||
|             Text(fromText, |             Text(fromText, | ||||||
|                 textAlign: TextAlign.center, |                 textAlign: TextAlign.center, | ||||||
|                 style: TextStyle(fontSize: 9, color: Colors.grey)), |                 style: | ||||||
|  |                     TextStyle(fontSize: 9, color: Theme.of(context).hintColor)), | ||||||
|             SizedBox(height: 3), |             SizedBox(height: 3), | ||||||
|             Text(toText, |             Text(toText, | ||||||
|                 textAlign: TextAlign.center, |                 textAlign: TextAlign.center, | ||||||
|                 style: TextStyle(fontSize: 12, color: Colors.black)) |                 style: TextStyle( | ||||||
|  |                     fontSize: 12, | ||||||
|  |                     color: Theme.of(context).textTheme.bodySmall?.color)) | ||||||
|           ], |           ], | ||||||
|         )); |         )); | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -58,9 +58,12 @@ class InputModel { | |||||||
|   InputModel(this.parent); |   InputModel(this.parent); | ||||||
| 
 | 
 | ||||||
|   KeyEventResult handleRawKeyEvent(FocusNode data, RawKeyEvent e) { |   KeyEventResult handleRawKeyEvent(FocusNode data, RawKeyEvent e) { | ||||||
|     bind.sessionGetKeyboardMode(id: id).then((result) { |     // * Currently mobile does not enable map mode | ||||||
|       keyboardMode = result.toString(); |     if (isDesktop) { | ||||||
|     }); |       bind.sessionGetKeyboardMode(id: id).then((result) { | ||||||
|  |         keyboardMode = result.toString(); | ||||||
|  |       }); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     final key = e.logicalKey; |     final key = e.logicalKey; | ||||||
|     if (e is RawKeyDownEvent) { |     if (e is RawKeyDownEvent) { | ||||||
| @ -93,10 +96,9 @@ class InputModel { | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (keyboardMode == 'map') { |     // * Currently mobile does not enable map mode | ||||||
|  |     if (isDesktop && keyboardMode == 'map') { | ||||||
|       mapKeyboardMode(e); |       mapKeyboardMode(e); | ||||||
|     } else if (keyboardMode == 'translate') { |  | ||||||
|       legacyKeyboardMode(e); |  | ||||||
|     } else { |     } else { | ||||||
|       legacyKeyboardMode(e); |       legacyKeyboardMode(e); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| import 'dart:typed_data'; | import 'dart:typed_data'; | ||||||
| import 'dart:ui' as ui; | import 'dart:ui' as ui; | ||||||
| 
 | 
 | ||||||
|  | import 'package:flutter/widgets.dart'; | ||||||
|  | 
 | ||||||
| Future<ui.Image> decodeImageFromPixels( | Future<ui.Image> decodeImageFromPixels( | ||||||
|   Uint8List pixels, |   Uint8List pixels, | ||||||
|   int width, |   int width, | ||||||
| @ -47,3 +49,40 @@ Future<ui.Image> decodeImageFromPixels( | |||||||
|   descriptor.dispose(); |   descriptor.dispose(); | ||||||
|   return frameInfo.image; |   return frameInfo.image; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | class ImagePainter extends CustomPainter { | ||||||
|  |   ImagePainter({ | ||||||
|  |     required this.image, | ||||||
|  |     required this.x, | ||||||
|  |     required this.y, | ||||||
|  |     required this.scale, | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   ui.Image? image; | ||||||
|  |   double x; | ||||||
|  |   double y; | ||||||
|  |   double scale; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void paint(Canvas canvas, Size size) { | ||||||
|  |     if (image == null) return; | ||||||
|  |     if (x.isNaN || y.isNaN) return; | ||||||
|  |     canvas.scale(scale, scale); | ||||||
|  |     // https://github.com/flutter/flutter/issues/76187#issuecomment-784628161 | ||||||
|  |     // https://api.flutter-io.cn/flutter/dart-ui/FilterQuality.html | ||||||
|  |     var paint = Paint(); | ||||||
|  |     if ((scale - 1.0).abs() > 0.001) { | ||||||
|  |       paint.filterQuality = FilterQuality.medium; | ||||||
|  |       if (scale > 10.00000) { | ||||||
|  |         paint.filterQuality = FilterQuality.high; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     canvas.drawImage( | ||||||
|  |         image!, Offset(x.toInt().toDouble(), y.toInt().toDouble()), paint); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   bool shouldRepaint(CustomPainter oldDelegate) { | ||||||
|  |     return oldDelegate != this; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user