| 
									
										
										
										
											2022-11-20 22:46:27 +08:00
										 |  |  | import 'dart:async'; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  | import 'dart:convert'; | 
					
						
							|  |  |  | import 'dart:math'; | 
					
						
							| 
									
										
										
										
											2022-11-02 22:23:23 +08:00
										 |  |  | import 'dart:ui' as ui; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  | import 'package:flutter/gestures.dart'; | 
					
						
							|  |  |  | import 'package:flutter/services.dart'; | 
					
						
							|  |  |  | import 'package:flutter/widgets.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  | import 'package:get/get.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | import '../../models/model.dart'; | 
					
						
							|  |  |  | import '../../models/platform_model.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  | import '../common.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  | import '../consts.dart'; | 
					
						
							| 
									
										
										
										
											2022-11-01 17:01:43 +08:00
										 |  |  | import './state_model.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  | /// Mouse button enum.
 | 
					
						
							|  |  |  | enum MouseButtons { left, right, wheel } | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-04 20:06:48 +08:00
										 |  |  | const _kMouseEventDown = 'mousedown'; | 
					
						
							|  |  |  | const _kMouseEventUp = 'mouseup'; | 
					
						
							|  |  |  | const _kMouseEventMove = 'mousemove'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  | extension ToString on MouseButtons { | 
					
						
							|  |  |  |   String get value { | 
					
						
							|  |  |  |     switch (this) { | 
					
						
							|  |  |  |       case MouseButtons.left: | 
					
						
							|  |  |  |         return 'left'; | 
					
						
							|  |  |  |       case MouseButtons.right: | 
					
						
							|  |  |  |         return 'right'; | 
					
						
							|  |  |  |       case MouseButtons.wheel: | 
					
						
							|  |  |  |         return 'wheel'; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class InputModel { | 
					
						
							|  |  |  |   final WeakReference<FFI> parent; | 
					
						
							|  |  |  |   String keyboardMode = "legacy"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // keyboard
 | 
					
						
							|  |  |  |   var shift = false; | 
					
						
							|  |  |  |   var ctrl = false; | 
					
						
							|  |  |  |   var alt = false; | 
					
						
							|  |  |  |   var command = false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-20 22:46:27 +08:00
										 |  |  |   // trackpad
 | 
					
						
							|  |  |  |   var trackpadScrollDistance = Offset.zero; | 
					
						
							|  |  |  |   Timer? _flingTimer; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |   // mouse
 | 
					
						
							| 
									
										
										
										
											2022-09-27 22:16:27 +08:00
										 |  |  |   final isPhysicalMouse = false.obs; | 
					
						
							| 
									
										
										
										
											2023-01-05 14:58:38 +08:00
										 |  |  |   int _lastButtons = 0; | 
					
						
							| 
									
										
										
										
											2022-11-14 15:05:44 +08:00
										 |  |  |   Offset lastMousePos = Offset.zero; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   get id => parent.target?.id ?? ""; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   InputModel(this.parent); | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   KeyEventResult handleRawKeyEvent(FocusNode data, RawKeyEvent e) { | 
					
						
							| 
									
										
										
										
											2023-02-09 23:14:24 +09:00
										 |  |  |     // * Currently mobile does not enable map mode
 | 
					
						
							|  |  |  |     if (isDesktop) { | 
					
						
							|  |  |  |       bind.sessionGetKeyboardMode(id: id).then((result) { | 
					
						
							|  |  |  |         keyboardMode = result.toString(); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-26 20:01:01 -07:00
										 |  |  |     final key = e.logicalKey; | 
					
						
							|  |  |  |     if (e is RawKeyDownEvent) { | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |       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; | 
					
						
							| 
									
										
										
										
											2022-09-26 20:01:01 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (e is RawKeyUpEvent) { | 
					
						
							|  |  |  |       if (key == LogicalKeyboardKey.altLeft || | 
					
						
							|  |  |  |           key == LogicalKeyboardKey.altRight) { | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |         alt = false; | 
					
						
							| 
									
										
										
										
											2022-09-26 20:01:01 -07:00
										 |  |  |       } else if (key == LogicalKeyboardKey.controlLeft || | 
					
						
							|  |  |  |           key == LogicalKeyboardKey.controlRight) { | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |         ctrl = false; | 
					
						
							| 
									
										
										
										
											2022-09-26 20:01:01 -07:00
										 |  |  |       } else if (key == LogicalKeyboardKey.shiftRight || | 
					
						
							|  |  |  |           key == LogicalKeyboardKey.shiftLeft) { | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |         shift = false; | 
					
						
							| 
									
										
										
										
											2022-09-26 20:01:01 -07:00
										 |  |  |       } else if (key == LogicalKeyboardKey.metaLeft || | 
					
						
							|  |  |  |           key == LogicalKeyboardKey.metaRight || | 
					
						
							|  |  |  |           key == LogicalKeyboardKey.superKey) { | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |         command = false; | 
					
						
							| 
									
										
										
										
											2022-09-26 20:01:01 -07:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-09 23:14:24 +09:00
										 |  |  |     // * Currently mobile does not enable map mode
 | 
					
						
							|  |  |  |     if (isDesktop && keyboardMode == 'map') { | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  |       mapKeyboardMode(e); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       legacyKeyboardMode(e); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return KeyEventResult.handled; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void mapKeyboardMode(RawKeyEvent e) { | 
					
						
							|  |  |  |     int scanCode; | 
					
						
							|  |  |  |     int keyCode; | 
					
						
							|  |  |  |     bool down; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (e.data is RawKeyEventDataMacOs) { | 
					
						
							|  |  |  |       RawKeyEventDataMacOs newData = e.data as RawKeyEventDataMacOs; | 
					
						
							|  |  |  |       scanCode = newData.keyCode; | 
					
						
							|  |  |  |       keyCode = newData.keyCode; | 
					
						
							|  |  |  |     } else if (e.data is RawKeyEventDataWindows) { | 
					
						
							|  |  |  |       RawKeyEventDataWindows newData = e.data as RawKeyEventDataWindows; | 
					
						
							|  |  |  |       scanCode = newData.scanCode; | 
					
						
							|  |  |  |       keyCode = newData.keyCode; | 
					
						
							|  |  |  |     } else if (e.data is RawKeyEventDataLinux) { | 
					
						
							|  |  |  |       RawKeyEventDataLinux newData = e.data as RawKeyEventDataLinux; | 
					
						
							| 
									
										
										
										
											2023-01-10 14:11:49 +08:00
										 |  |  |       // scanCode and keyCode of RawKeyEventDataLinux are incorrect.
 | 
					
						
							|  |  |  |       // 1. scanCode means keycode
 | 
					
						
							|  |  |  |       // 2. keyCode means keysym
 | 
					
						
							|  |  |  |       scanCode = 0; | 
					
						
							|  |  |  |       keyCode = newData.scanCode; | 
					
						
							| 
									
										
										
										
											2022-09-29 18:56:47 +08:00
										 |  |  |     } else if (e.data is RawKeyEventDataAndroid) { | 
					
						
							| 
									
										
										
										
											2022-09-28 00:12:08 -07:00
										 |  |  |       RawKeyEventDataAndroid newData = e.data as RawKeyEventDataAndroid; | 
					
						
							|  |  |  |       scanCode = newData.scanCode + 8; | 
					
						
							|  |  |  |       keyCode = newData.keyCode; | 
					
						
							| 
									
										
										
										
											2022-09-29 18:56:47 +08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  |       scanCode = -1; | 
					
						
							|  |  |  |       keyCode = -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (e is RawKeyDownEvent) { | 
					
						
							|  |  |  |       down = true; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       down = false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-01-10 14:11:49 +08:00
										 |  |  |     inputRawKey(e.character ?? '', keyCode, scanCode, down); | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |   /// Send raw Key Event
 | 
					
						
							|  |  |  |   void inputRawKey(String name, int keyCode, int scanCode, bool down) { | 
					
						
							| 
									
										
										
										
											2023-01-10 14:11:49 +08:00
										 |  |  |     const capslock = 1; | 
					
						
							|  |  |  |     const numlock = 2; | 
					
						
							|  |  |  |     const scrolllock = 3; | 
					
						
							|  |  |  |     int lockModes = 0; | 
					
						
							|  |  |  |     if (HardwareKeyboard.instance.lockModesEnabled | 
					
						
							|  |  |  |         .contains(KeyboardLockMode.capsLock)) { | 
					
						
							|  |  |  |       lockModes |= (1 << capslock); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (HardwareKeyboard.instance.lockModesEnabled | 
					
						
							|  |  |  |         .contains(KeyboardLockMode.numLock)) { | 
					
						
							|  |  |  |       lockModes |= (1 << numlock); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (HardwareKeyboard.instance.lockModesEnabled | 
					
						
							|  |  |  |         .contains(KeyboardLockMode.scrollLock)) { | 
					
						
							|  |  |  |       lockModes |= (1 << scrolllock); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |     bind.sessionHandleFlutterKeyEvent( | 
					
						
							|  |  |  |         id: id, | 
					
						
							|  |  |  |         name: name, | 
					
						
							|  |  |  |         keycode: keyCode, | 
					
						
							|  |  |  |         scancode: scanCode, | 
					
						
							| 
									
										
										
										
											2023-01-10 14:11:49 +08:00
										 |  |  |         lockModes: lockModes, | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |         downOrUp: down); | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void legacyKeyboardMode(RawKeyEvent e) { | 
					
						
							|  |  |  |     if (e is RawKeyDownEvent) { | 
					
						
							|  |  |  |       if (e.repeat) { | 
					
						
							|  |  |  |         sendRawKey(e, press: true); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         sendRawKey(e, down: true); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (e is RawKeyUpEvent) { | 
					
						
							|  |  |  |       sendRawKey(e); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void sendRawKey(RawKeyEvent e, {bool? down, bool? press}) { | 
					
						
							|  |  |  |     // for maximum compatibility
 | 
					
						
							| 
									
										
										
										
											2022-09-26 00:50:12 -07:00
										 |  |  |     final label = physicalKeyMap[e.physicalKey.usbHidUsage] ?? | 
					
						
							|  |  |  |         logicalKeyMap[e.logicalKey.keyId] ?? | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  |         e.logicalKey.keyLabel; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |     inputKey(label, down: down, press: press ?? false); | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |   /// 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); | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Map<String, dynamic> getEvent(PointerEvent evt, String type) { | 
					
						
							|  |  |  |     final Map<String, dynamic> out = {}; | 
					
						
							|  |  |  |     out['x'] = evt.position.dx; | 
					
						
							|  |  |  |     out['y'] = evt.position.dy; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |     if (alt) out['alt'] = 'true'; | 
					
						
							|  |  |  |     if (shift) out['shift'] = 'true'; | 
					
						
							|  |  |  |     if (ctrl) out['ctrl'] = 'true'; | 
					
						
							|  |  |  |     if (command) out['command'] = 'true'; | 
					
						
							| 
									
										
										
										
											2023-01-04 20:06:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Check update event type and set buttons to be sent.
 | 
					
						
							| 
									
										
										
										
											2023-01-05 14:58:38 +08:00
										 |  |  |     int buttons = _lastButtons; | 
					
						
							| 
									
										
										
										
											2023-01-04 20:06:48 +08:00
										 |  |  |     if (type == _kMouseEventMove) { | 
					
						
							| 
									
										
										
										
											2023-01-09 02:30:18 -05:00
										 |  |  |       // flutter may emit move event if one button is pressed and another button
 | 
					
						
							| 
									
										
										
										
											2023-01-04 20:06:48 +08:00
										 |  |  |       // is pressing or releasing.
 | 
					
						
							| 
									
										
										
										
											2023-01-05 14:58:38 +08:00
										 |  |  |       if (evt.buttons != _lastButtons) { | 
					
						
							| 
									
										
										
										
											2023-01-04 20:06:48 +08:00
										 |  |  |         // For simplicity
 | 
					
						
							|  |  |  |         // Just consider 3 - 1 ((Left + Right buttons) - Left button)
 | 
					
						
							|  |  |  |         // Do not consider 2 - 1 (Right button - Left button)
 | 
					
						
							|  |  |  |         // or 6 - 5 ((Right + Mid buttons) - (Left + Mid buttons))
 | 
					
						
							|  |  |  |         // and so on
 | 
					
						
							| 
									
										
										
										
											2023-01-05 14:58:38 +08:00
										 |  |  |         buttons = evt.buttons - _lastButtons; | 
					
						
							| 
									
										
										
										
											2023-01-04 20:06:48 +08:00
										 |  |  |         if (buttons > 0) { | 
					
						
							|  |  |  |           type = _kMouseEventDown; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           type = _kMouseEventUp; | 
					
						
							|  |  |  |           buttons = -buttons; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2023-01-04 20:06:48 +08:00
										 |  |  |       if (evt.buttons != 0) { | 
					
						
							|  |  |  |         buttons = evt.buttons; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-01-05 14:58:38 +08:00
										 |  |  |     _lastButtons = evt.buttons; | 
					
						
							| 
									
										
										
										
											2023-01-04 20:06:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     out['buttons'] = buttons; | 
					
						
							|  |  |  |     out['type'] = type; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  |     return out; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |   /// 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(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-11-20 22:46:27 +08:00
										 |  |  |     _flingTimer?.cancel(); | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |     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'}))); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  |   void onPointHoverImage(PointerHoverEvent e) { | 
					
						
							|  |  |  |     if (e.kind != ui.PointerDeviceKind.mouse) return; | 
					
						
							| 
									
										
										
										
											2022-09-27 22:16:27 +08:00
										 |  |  |     if (!isPhysicalMouse.value) { | 
					
						
							|  |  |  |       isPhysicalMouse.value = true; | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-27 22:16:27 +08:00
										 |  |  |     if (isPhysicalMouse.value) { | 
					
						
							| 
									
										
										
										
											2023-01-04 20:06:48 +08:00
										 |  |  |       handleMouse(getEvent(e, _kMouseEventMove)); | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-20 22:46:27 +08:00
										 |  |  |   int _signOrZero(num x) { | 
					
						
							|  |  |  |     if (x == 0) { | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return x > 0 ? 1 : -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void onPointerPanZoomStart(PointerPanZoomStartEvent e) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // https://docs.flutter.dev/release/breaking-changes/trackpad-gestures
 | 
					
						
							|  |  |  |   // TODO(support zoom in/out)
 | 
					
						
							|  |  |  |   void onPointerPanZoomUpdate(PointerPanZoomUpdateEvent e) { | 
					
						
							|  |  |  |     var delta = e.panDelta; | 
					
						
							|  |  |  |     trackpadScrollDistance += delta; | 
					
						
							|  |  |  |     bind.sessionSendMouse( | 
					
						
							|  |  |  |         id: id, | 
					
						
							|  |  |  |         msg: | 
					
						
							|  |  |  |             '{"type": "trackpad", "x": "${delta.dx.toInt()}", "y": "${delta.dy.toInt()}"}'); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Simple simulation for fling.
 | 
					
						
							|  |  |  |   void _scheduleFling(var x, y, dx, dy) { | 
					
						
							|  |  |  |     if (dx <= 0 && dy <= 0) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     _flingTimer = Timer(Duration(milliseconds: 10), () { | 
					
						
							|  |  |  |       bind.sessionSendMouse( | 
					
						
							|  |  |  |           id: id, msg: '{"type": "trackpad", "x": "$x", "y": "$y"}'); | 
					
						
							|  |  |  |       dx--; | 
					
						
							|  |  |  |       dy--; | 
					
						
							|  |  |  |       if (dx == 0) { | 
					
						
							|  |  |  |         x = 0; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (dy == 0) { | 
					
						
							|  |  |  |         y = 0; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       _scheduleFling(x, y, dx, dy); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void onPointerPanZoomEnd(PointerPanZoomEndEvent e) { | 
					
						
							|  |  |  |     var x = _signOrZero(trackpadScrollDistance.dx); | 
					
						
							|  |  |  |     var y = _signOrZero(trackpadScrollDistance.dy); | 
					
						
							|  |  |  |     var dx = trackpadScrollDistance.dx.abs() ~/ 40; | 
					
						
							|  |  |  |     var dy = trackpadScrollDistance.dy.abs() ~/ 40; | 
					
						
							|  |  |  |     _scheduleFling(x, y, dx, dy); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     trackpadScrollDistance = Offset.zero; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-02-01 16:29:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  |   void onPointDownImage(PointerDownEvent e) { | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |     debugPrint("onPointDownImage"); | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  |     if (e.kind != ui.PointerDeviceKind.mouse) { | 
					
						
							| 
									
										
										
										
											2022-09-27 22:16:27 +08:00
										 |  |  |       if (isPhysicalMouse.value) { | 
					
						
							|  |  |  |         isPhysicalMouse.value = false; | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-27 22:16:27 +08:00
										 |  |  |     if (isPhysicalMouse.value) { | 
					
						
							| 
									
										
										
										
											2023-01-04 20:06:48 +08:00
										 |  |  |       handleMouse(getEvent(e, _kMouseEventDown)); | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void onPointUpImage(PointerUpEvent e) { | 
					
						
							|  |  |  |     if (e.kind != ui.PointerDeviceKind.mouse) return; | 
					
						
							| 
									
										
										
										
											2022-09-27 22:16:27 +08:00
										 |  |  |     if (isPhysicalMouse.value) { | 
					
						
							| 
									
										
										
										
											2023-01-04 20:06:48 +08:00
										 |  |  |       handleMouse(getEvent(e, _kMouseEventUp)); | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void onPointMoveImage(PointerMoveEvent e) { | 
					
						
							|  |  |  |     if (e.kind != ui.PointerDeviceKind.mouse) return; | 
					
						
							| 
									
										
										
										
											2022-09-27 22:16:27 +08:00
										 |  |  |     if (isPhysicalMouse.value) { | 
					
						
							| 
									
										
										
										
											2023-01-04 20:06:48 +08:00
										 |  |  |       handleMouse(getEvent(e, _kMouseEventMove)); | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void onPointerSignalImage(PointerSignalEvent e) { | 
					
						
							|  |  |  |     if (e is PointerScrollEvent) { | 
					
						
							|  |  |  |       var dx = e.scrollDelta.dx.toInt(); | 
					
						
							|  |  |  |       var dy = e.scrollDelta.dy.toInt(); | 
					
						
							|  |  |  |       if (dx > 0) { | 
					
						
							|  |  |  |         dx = -1; | 
					
						
							|  |  |  |       } else if (dx < 0) { | 
					
						
							|  |  |  |         dx = 1; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (dy > 0) { | 
					
						
							|  |  |  |         dy = -1; | 
					
						
							|  |  |  |       } else if (dy < 0) { | 
					
						
							|  |  |  |         dy = 1; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       bind.sessionSendMouse( | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |           id: id, msg: '{"type": "wheel", "x": "$dx", "y": "$dy"}'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-30 22:12:36 +08:00
										 |  |  |   void refreshMousePos() => handleMouse({ | 
					
						
							|  |  |  |         'x': lastMousePos.dx, | 
					
						
							|  |  |  |         'y': lastMousePos.dy, | 
					
						
							|  |  |  |         'buttons': 0, | 
					
						
							|  |  |  |         'type': _kMouseEventMove, | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |   void handleMouse(Map<String, dynamic> evt) { | 
					
						
							| 
									
										
										
										
											2022-11-08 12:01:51 +08:00
										 |  |  |     double x = evt['x']; | 
					
						
							|  |  |  |     double y = max(0.0, evt['y']); | 
					
						
							|  |  |  |     final cursorModel = parent.target!.cursorModel; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-14 15:05:44 +08:00
										 |  |  |     if (cursorModel.isPeerControlProtected) { | 
					
						
							|  |  |  |       lastMousePos = ui.Offset(x, y); | 
					
						
							| 
									
										
										
										
											2022-11-08 13:37:08 +08:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-14 15:05:44 +08:00
										 |  |  |     if (!cursorModel.gotMouseControl) { | 
					
						
							|  |  |  |       bool selfGetControl = | 
					
						
							|  |  |  |           (x - lastMousePos.dx).abs() > kMouseControlDistance || | 
					
						
							|  |  |  |               (y - lastMousePos.dy).abs() > kMouseControlDistance; | 
					
						
							|  |  |  |       if (selfGetControl) { | 
					
						
							|  |  |  |         cursorModel.gotMouseControl = true; | 
					
						
							| 
									
										
										
										
											2022-11-08 12:01:51 +08:00
										 |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2022-11-14 15:05:44 +08:00
										 |  |  |         lastMousePos = ui.Offset(x, y); | 
					
						
							| 
									
										
										
										
											2022-11-08 12:01:51 +08:00
										 |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-11-14 15:05:44 +08:00
										 |  |  |     lastMousePos = ui.Offset(x, y); | 
					
						
							| 
									
										
										
										
											2022-11-08 12:01:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |     var type = ''; | 
					
						
							|  |  |  |     var isMove = false; | 
					
						
							|  |  |  |     switch (evt['type']) { | 
					
						
							| 
									
										
										
										
											2023-01-04 20:06:48 +08:00
										 |  |  |       case _kMouseEventDown: | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |         type = 'down'; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2023-01-04 20:06:48 +08:00
										 |  |  |       case _kMouseEventUp: | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |         type = 'up'; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2023-01-04 20:06:48 +08:00
										 |  |  |       case _kMouseEventMove: | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |         isMove = true; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     evt['type'] = type; | 
					
						
							|  |  |  |     if (isDesktop) { | 
					
						
							| 
									
										
										
										
											2022-11-01 17:01:43 +08:00
										 |  |  |       y = y - stateGlobal.tabBarHeight; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |     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; | 
					
						
							| 
									
										
										
										
											2023-02-10 21:32:51 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (x < d.x || y < d.y || x > (d.x + d.width) || y > (d.y + d.height)) { | 
					
						
							|  |  |  |       // If left mouse up, no early return.
 | 
					
						
							|  |  |  |       if (evt['buttons'] != kPrimaryMouseButton || type != 'up') { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |     if (type != '') { | 
					
						
							|  |  |  |       x = 0; | 
					
						
							|  |  |  |       y = 0; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-02-10 21:32:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |     evt['x'] = '${x.round()}'; | 
					
						
							|  |  |  |     evt['y'] = '${y.round()}'; | 
					
						
							|  |  |  |     var buttons = ''; | 
					
						
							|  |  |  |     switch (evt['buttons']) { | 
					
						
							| 
									
										
										
										
											2023-01-05 17:14:44 +08:00
										 |  |  |       case kPrimaryMouseButton: | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |         buttons = 'left'; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2023-01-05 17:14:44 +08:00
										 |  |  |       case kSecondaryMouseButton: | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |         buttons = 'right'; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2023-01-05 17:14:44 +08:00
										 |  |  |       case kMiddleMouseButton: | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |         buttons = 'wheel'; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2023-01-05 17:14:44 +08:00
										 |  |  |       case kBackMouseButton: | 
					
						
							|  |  |  |         buttons = 'back'; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case kForwardMouseButton: | 
					
						
							|  |  |  |         buttons = 'forward'; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |     evt['buttons'] = buttons; | 
					
						
							|  |  |  |     bind.sessionSendMouse(id: id, msg: json.encode(evt)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /// Web only
 | 
					
						
							|  |  |  |   void listenToMouse(bool yesOrNo) { | 
					
						
							|  |  |  |     if (yesOrNo) { | 
					
						
							|  |  |  |       platformFFI.startDesktopWebListener(); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       platformFFI.stopDesktopWebListener(); | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |