123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452 |
- import 'dart:async';
- import 'dart:convert';
- import 'dart:io';
- import 'dart:math';
- import 'dart:ui' as ui;
- import 'package:desktop_multi_window/desktop_multi_window.dart';
- import 'package:flutter/gestures.dart';
- import 'package:flutter/services.dart';
- import 'package:flutter/widgets.dart';
- import 'package:flutter_hbb/main.dart';
- import 'package:flutter_hbb/utils/multi_window_manager.dart';
- import 'package:get/get.dart';
- import '../../models/model.dart';
- import '../../models/platform_model.dart';
- import '../common.dart';
- import '../consts.dart';
- /// Mouse button enum.
- enum MouseButtons { left, right, wheel }
- const _kMouseEventDown = 'mousedown';
- const _kMouseEventUp = 'mouseup';
- const _kMouseEventMove = 'mousemove';
- class CanvasCoords {
- double x = 0;
- double y = 0;
- double scale = 1.0;
- double scrollX = 0;
- double scrollY = 0;
- ScrollStyle scrollStyle = ScrollStyle.scrollauto;
- Size size = Size.zero;
- CanvasCoords();
- Map<String, dynamic> toJson() {
- return {
- 'x': x,
- 'y': y,
- 'scale': scale,
- 'scrollX': scrollX,
- 'scrollY': scrollY,
- 'scrollStyle':
- scrollStyle == ScrollStyle.scrollauto ? 'scrollauto' : 'scrollbar',
- 'size': {
- 'w': size.width,
- 'h': size.height,
- }
- };
- }
- static CanvasCoords fromJson(Map<String, dynamic> json) {
- final model = CanvasCoords();
- model.x = json['x'];
- model.y = json['y'];
- model.scale = json['scale'];
- model.scrollX = json['scrollX'];
- model.scrollY = json['scrollY'];
- model.scrollStyle = json['scrollStyle'] == 'scrollauto'
- ? ScrollStyle.scrollauto
- : ScrollStyle.scrollbar;
- model.size = Size(json['size']['w'], json['size']['h']);
- return model;
- }
- static CanvasCoords fromCanvasModel(CanvasModel model) {
- final coords = CanvasCoords();
- coords.x = model.x;
- coords.y = model.y;
- coords.scale = model.scale;
- coords.scrollX = model.scrollX;
- coords.scrollY = model.scrollY;
- coords.scrollStyle = model.scrollStyle;
- coords.size = model.size;
- return coords;
- }
- }
- class CursorCoords {
- Offset offset = Offset.zero;
- CursorCoords();
- Map<String, dynamic> toJson() {
- return {
- 'offset_x': offset.dx,
- 'offset_y': offset.dy,
- };
- }
- static CursorCoords fromJson(Map<String, dynamic> json) {
- final model = CursorCoords();
- model.offset = Offset(json['offset_x'], json['offset_y']);
- return model;
- }
- static CursorCoords fromCursorModel(CursorModel model) {
- final coords = CursorCoords();
- coords.offset = model.offset;
- return coords;
- }
- }
- class RemoteWindowCoords {
- RemoteWindowCoords(
- this.windowRect, this.canvas, this.cursor, this.remoteRect);
- Rect windowRect;
- CanvasCoords canvas;
- CursorCoords cursor;
- Rect remoteRect;
- Offset relativeOffset = Offset.zero;
- Map<String, dynamic> toJson() {
- return {
- 'canvas': canvas.toJson(),
- 'cursor': cursor.toJson(),
- 'windowRect': rectToJson(windowRect),
- 'remoteRect': rectToJson(remoteRect),
- };
- }
- static Map<String, dynamic> rectToJson(Rect r) {
- return {
- 'l': r.left,
- 't': r.top,
- 'w': r.width,
- 'h': r.height,
- };
- }
- static Rect rectFromJson(Map<String, dynamic> json) {
- return Rect.fromLTWH(
- json['l'],
- json['t'],
- json['w'],
- json['h'],
- );
- }
- RemoteWindowCoords.fromJson(Map<String, dynamic> json)
- : windowRect = rectFromJson(json['windowRect']),
- canvas = CanvasCoords.fromJson(json['canvas']),
- cursor = CursorCoords.fromJson(json['cursor']),
- remoteRect = rectFromJson(json['remoteRect']);
- }
- 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 PointerEventToRust {
- final String kind;
- final String type;
- final dynamic value;
- PointerEventToRust(this.kind, this.type, this.value);
- Map<String, dynamic> toJson() {
- return {
- 'k': kind,
- 'v': {
- 't': type,
- 'v': value,
- }
- };
- }
- }
- class ToReleaseRawKeys {
- RawKeyEvent? lastLShiftKeyEvent;
- RawKeyEvent? lastRShiftKeyEvent;
- RawKeyEvent? lastLCtrlKeyEvent;
- RawKeyEvent? lastRCtrlKeyEvent;
- RawKeyEvent? lastLAltKeyEvent;
- RawKeyEvent? lastRAltKeyEvent;
- RawKeyEvent? lastLCommandKeyEvent;
- RawKeyEvent? lastRCommandKeyEvent;
- RawKeyEvent? lastSuperKeyEvent;
- reset() {
- lastLShiftKeyEvent = null;
- lastRShiftKeyEvent = null;
- lastLCtrlKeyEvent = null;
- lastRCtrlKeyEvent = null;
- lastLAltKeyEvent = null;
- lastRAltKeyEvent = null;
- lastLCommandKeyEvent = null;
- lastRCommandKeyEvent = null;
- lastSuperKeyEvent = null;
- }
- updateKeyDown(LogicalKeyboardKey logicKey, RawKeyDownEvent e) {
- if (e.isAltPressed) {
- if (logicKey == LogicalKeyboardKey.altLeft) {
- lastLAltKeyEvent = e;
- } else if (logicKey == LogicalKeyboardKey.altRight) {
- lastRAltKeyEvent = e;
- }
- } else if (e.isControlPressed) {
- if (logicKey == LogicalKeyboardKey.controlLeft) {
- lastLCtrlKeyEvent = e;
- } else if (logicKey == LogicalKeyboardKey.controlRight) {
- lastRCtrlKeyEvent = e;
- }
- } else if (e.isShiftPressed) {
- if (logicKey == LogicalKeyboardKey.shiftLeft) {
- lastLShiftKeyEvent = e;
- } else if (logicKey == LogicalKeyboardKey.shiftRight) {
- lastRShiftKeyEvent = e;
- }
- } else if (e.isMetaPressed) {
- if (logicKey == LogicalKeyboardKey.metaLeft) {
- lastLCommandKeyEvent = e;
- } else if (logicKey == LogicalKeyboardKey.metaRight) {
- lastRCommandKeyEvent = e;
- } else if (logicKey == LogicalKeyboardKey.superKey) {
- lastSuperKeyEvent = e;
- }
- }
- }
- updateKeyUp(LogicalKeyboardKey logicKey, RawKeyUpEvent e) {
- if (e.isAltPressed) {
- if (logicKey == LogicalKeyboardKey.altLeft) {
- lastLAltKeyEvent = null;
- } else if (logicKey == LogicalKeyboardKey.altRight) {
- lastRAltKeyEvent = null;
- }
- } else if (e.isControlPressed) {
- if (logicKey == LogicalKeyboardKey.controlLeft) {
- lastLCtrlKeyEvent = null;
- } else if (logicKey == LogicalKeyboardKey.controlRight) {
- lastRCtrlKeyEvent = null;
- }
- } else if (e.isShiftPressed) {
- if (logicKey == LogicalKeyboardKey.shiftLeft) {
- lastLShiftKeyEvent = null;
- } else if (logicKey == LogicalKeyboardKey.shiftRight) {
- lastRShiftKeyEvent = null;
- }
- } else if (e.isMetaPressed) {
- if (logicKey == LogicalKeyboardKey.metaLeft) {
- lastLCommandKeyEvent = null;
- } else if (logicKey == LogicalKeyboardKey.metaRight) {
- lastRCommandKeyEvent = null;
- } else if (logicKey == LogicalKeyboardKey.superKey) {
- lastSuperKeyEvent = null;
- }
- }
- }
- release(KeyEventResult Function(RawKeyEvent e) handleRawKeyEvent) {
- for (final key in [
- lastLShiftKeyEvent,
- lastRShiftKeyEvent,
- lastLCtrlKeyEvent,
- lastRCtrlKeyEvent,
- lastLAltKeyEvent,
- lastRAltKeyEvent,
- lastLCommandKeyEvent,
- lastRCommandKeyEvent,
- lastSuperKeyEvent,
- ]) {
- if (key != null) {
- handleRawKeyEvent(RawKeyUpEvent(
- data: key.data,
- character: key.character,
- ));
- }
- }
- }
- }
- class ToReleaseKeys {
- KeyEvent? lastLShiftKeyEvent;
- KeyEvent? lastRShiftKeyEvent;
- KeyEvent? lastLCtrlKeyEvent;
- KeyEvent? lastRCtrlKeyEvent;
- KeyEvent? lastLAltKeyEvent;
- KeyEvent? lastRAltKeyEvent;
- KeyEvent? lastLCommandKeyEvent;
- KeyEvent? lastRCommandKeyEvent;
- KeyEvent? lastSuperKeyEvent;
- reset() {
- lastLShiftKeyEvent = null;
- lastRShiftKeyEvent = null;
- lastLCtrlKeyEvent = null;
- lastRCtrlKeyEvent = null;
- lastLAltKeyEvent = null;
- lastRAltKeyEvent = null;
- lastLCommandKeyEvent = null;
- lastRCommandKeyEvent = null;
- lastSuperKeyEvent = null;
- }
- release(KeyEventResult Function(KeyEvent e) handleKeyEvent) {
- for (final key in [
- lastLShiftKeyEvent,
- lastRShiftKeyEvent,
- lastLCtrlKeyEvent,
- lastRCtrlKeyEvent,
- lastLAltKeyEvent,
- lastRAltKeyEvent,
- lastLCommandKeyEvent,
- lastRCommandKeyEvent,
- lastSuperKeyEvent,
- ]) {
- if (key != null) {
- handleKeyEvent(key);
- }
- }
- }
- }
- class InputModel {
- final WeakReference<FFI> parent;
- String keyboardMode = '';
- // keyboard
- var shift = false;
- var ctrl = false;
- var alt = false;
- var command = false;
- final ToReleaseRawKeys toReleaseRawKeys = ToReleaseRawKeys();
- final ToReleaseKeys toReleaseKeys = ToReleaseKeys();
- // trackpad
- var _trackpadLastDelta = Offset.zero;
- var _stopFling = true;
- var _fling = false;
- Timer? _flingTimer;
- final _flingBaseDelay = 30;
- // trackpad, peer linux
- final _trackpadSpeed = 0.06;
- var _trackpadScrollUnsent = Offset.zero;
- var _lastScale = 1.0;
- bool _pointerMovedAfterEnter = false;
- // mouse
- final isPhysicalMouse = false.obs;
- int _lastButtons = 0;
- Offset lastMousePos = Offset.zero;
- bool _queryOtherWindowCoords = false;
- Rect? _windowRect;
- List<RemoteWindowCoords> _remoteWindowCoords = [];
- late final SessionID sessionId;
- bool get keyboardPerm => parent.target!.ffiModel.keyboard;
- String get id => parent.target?.id ?? '';
- String? get peerPlatform => parent.target?.ffiModel.pi.platform;
- bool get isViewOnly => parent.target!.ffiModel.viewOnly;
- double get devicePixelRatio => parent.target!.canvasModel.devicePixelRatio;
- InputModel(this.parent) {
- sessionId = parent.target!.sessionId;
- }
- // This function must be called after the peer info is received.
- // Because `sessionGetKeyboardMode` relies on the peer version.
- updateKeyboardMode() async {
- // * Currently mobile does not enable map mode
- if (isDesktop || isWebDesktop) {
- keyboardMode = await bind.sessionGetKeyboardMode(sessionId: sessionId) ??
- kKeyLegacyMode;
- }
- }
- void handleKeyDownEventModifiers(KeyEvent e) {
- KeyUpEvent upEvent(e) => KeyUpEvent(
- physicalKey: e.physicalKey,
- logicalKey: e.logicalKey,
- timeStamp: e.timeStamp,
- );
- if (e.logicalKey == LogicalKeyboardKey.altLeft) {
- if (!alt) {
- alt = true;
- }
- toReleaseKeys.lastLAltKeyEvent = upEvent(e);
- } else if (e.logicalKey == LogicalKeyboardKey.altRight) {
- if (!alt) {
- alt = true;
- }
- toReleaseKeys.lastLAltKeyEvent = upEvent(e);
- } else if (e.logicalKey == LogicalKeyboardKey.controlLeft) {
- if (!ctrl) {
- ctrl = true;
- }
- toReleaseKeys.lastLCtrlKeyEvent = upEvent(e);
- } else if (e.logicalKey == LogicalKeyboardKey.controlRight) {
- if (!ctrl) {
- ctrl = true;
- }
- toReleaseKeys.lastRCtrlKeyEvent = upEvent(e);
- } else if (e.logicalKey == LogicalKeyboardKey.shiftLeft) {
- if (!shift) {
- shift = true;
- }
- toReleaseKeys.lastLShiftKeyEvent = upEvent(e);
- } else if (e.logicalKey == LogicalKeyboardKey.shiftRight) {
- if (!shift) {
- shift = true;
- }
- toReleaseKeys.lastRShiftKeyEvent = upEvent(e);
- } else if (e.logicalKey == LogicalKeyboardKey.metaLeft) {
- if (!command) {
- command = true;
- }
- toReleaseKeys.lastLCommandKeyEvent = upEvent(e);
- } else if (e.logicalKey == LogicalKeyboardKey.metaRight) {
- if (!command) {
- command = true;
- }
- toReleaseKeys.lastRCommandKeyEvent = upEvent(e);
- } else if (e.logicalKey == LogicalKeyboardKey.superKey) {
- if (!command) {
- command = true;
- }
- toReleaseKeys.lastSuperKeyEvent = upEvent(e);
- }
- }
- void handleKeyUpEventModifiers(KeyEvent e) {
- if (e.logicalKey == LogicalKeyboardKey.altLeft) {
- alt = false;
- toReleaseKeys.lastLAltKeyEvent = null;
- } else if (e.logicalKey == LogicalKeyboardKey.altRight) {
- alt = false;
- toReleaseKeys.lastRAltKeyEvent = null;
- } else if (e.logicalKey == LogicalKeyboardKey.controlLeft) {
- ctrl = false;
- toReleaseKeys.lastLCtrlKeyEvent = null;
- } else if (e.logicalKey == LogicalKeyboardKey.controlRight) {
- ctrl = false;
- toReleaseKeys.lastRCtrlKeyEvent = null;
- } else if (e.logicalKey == LogicalKeyboardKey.shiftLeft) {
- shift = false;
- toReleaseKeys.lastLShiftKeyEvent = null;
- } else if (e.logicalKey == LogicalKeyboardKey.shiftRight) {
- shift = false;
- toReleaseKeys.lastRShiftKeyEvent = null;
- } else if (e.logicalKey == LogicalKeyboardKey.metaLeft) {
- command = false;
- toReleaseKeys.lastLCommandKeyEvent = null;
- } else if (e.logicalKey == LogicalKeyboardKey.metaRight) {
- command = false;
- toReleaseKeys.lastRCommandKeyEvent = null;
- } else if (e.logicalKey == LogicalKeyboardKey.superKey) {
- command = false;
- toReleaseKeys.lastSuperKeyEvent = null;
- }
- }
- KeyEventResult handleRawKeyEvent(RawKeyEvent e) {
- if (isViewOnly) return KeyEventResult.handled;
- if (!isInputSourceFlutter) {
- if (isDesktop) {
- return KeyEventResult.handled;
- } else if (isWeb) {
- return KeyEventResult.ignored;
- }
- }
- final key = e.logicalKey;
- if (e is RawKeyDownEvent) {
- 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;
- }
- }
- toReleaseRawKeys.updateKeyDown(key, e);
- }
- if (e is RawKeyUpEvent) {
- if (key == LogicalKeyboardKey.altLeft ||
- key == LogicalKeyboardKey.altRight) {
- alt = false;
- } else if (key == LogicalKeyboardKey.controlLeft ||
- key == LogicalKeyboardKey.controlRight) {
- ctrl = false;
- } else if (key == LogicalKeyboardKey.shiftRight ||
- key == LogicalKeyboardKey.shiftLeft) {
- shift = false;
- } else if (key == LogicalKeyboardKey.metaLeft ||
- key == LogicalKeyboardKey.metaRight ||
- key == LogicalKeyboardKey.superKey) {
- command = false;
- }
- toReleaseRawKeys.updateKeyUp(key, e);
- }
- // * Currently mobile does not enable map mode
- if ((isDesktop || isWebDesktop) && keyboardMode == kKeyMapMode) {
- mapKeyboardModeRaw(e);
- } else {
- legacyKeyboardModeRaw(e);
- }
- return KeyEventResult.handled;
- }
- KeyEventResult handleKeyEvent(KeyEvent e) {
- if (isViewOnly) return KeyEventResult.handled;
- if (!isInputSourceFlutter) {
- if (isDesktop) {
- return KeyEventResult.handled;
- } else if (isWeb) {
- return KeyEventResult.ignored;
- }
- }
- if (isWindows || isLinux) {
- // Ignore meta keys. Because flutter window will loose focus if meta key is pressed.
- if (e.physicalKey == PhysicalKeyboardKey.metaLeft ||
- e.physicalKey == PhysicalKeyboardKey.metaRight) {
- return KeyEventResult.handled;
- }
- }
- if (e is KeyUpEvent) {
- handleKeyUpEventModifiers(e);
- } else if (e is KeyDownEvent) {
- handleKeyDownEventModifiers(e);
- }
- bool isMobileAndMapMode = false;
- if (isMobile) {
- // Do not use map mode if mobile -> Android. Android does not support map mode for now.
- // Because simulating the physical key events(uhid) which requires root permission is not supported.
- if (peerPlatform != kPeerPlatformAndroid) {
- if (isIOS) {
- isMobileAndMapMode = true;
- } else {
- // The physicalKey.usbHidUsage may be not correct for soft keyboard on Android.
- // iOS does not have this issue.
- // 1. Open the soft keyboard on Android
- // 2. Switch to input method like zh/ko/ja
- // 3. Click Backspace and Enter on the soft keyboard or physical keyboard
- // 4. The physicalKey.usbHidUsage is not correct.
- // PhysicalKeyboardKey#8ac83(usbHidUsage: "0x1100000042", debugName: "Key with ID 0x1100000042")
- // LogicalKeyboardKey#2604c(keyId: "0x10000000d", keyLabel: "Enter", debugName: "Enter")
- //
- // The correct PhysicalKeyboardKey should be
- // PhysicalKeyboardKey#e14a9(usbHidUsage: "0x00070028", debugName: "Enter")
- // https://github.com/flutter/flutter/issues/157771
- // We cannot use the debugName to determine the key is correct or not, because it's null in release mode.
- // The normal `usbHidUsage` for keyboard shoud be between [0x00000010, 0x000c029f]
- // https://github.com/flutter/flutter/blob/c051b69e2a2224300e20d93dbd15f4b91e8844d1/packages/flutter/lib/src/services/keyboard_key.g.dart#L5332 - 5600
- final isNormalHsbHidUsage = (e.physicalKey.usbHidUsage >> 20) == 0;
- isMobileAndMapMode = isNormalHsbHidUsage &&
- // No need to check `!['Backspace', 'Enter'].contains(e.logicalKey.keyLabel)`
- // But we still add it for more reliability.
- !['Backspace', 'Enter'].contains(e.logicalKey.keyLabel);
- }
- }
- }
- final isDesktopAndMapMode =
- isDesktop || (isWebDesktop && keyboardMode == kKeyMapMode);
- if (isMobileAndMapMode || isDesktopAndMapMode) {
- // FIXME: e.character is wrong for dead keys, eg: ^ in de
- newKeyboardMode(
- e.character ?? '',
- e.physicalKey.usbHidUsage & 0xFFFF,
- // Show repeat event be converted to "release+press" events?
- e is KeyDownEvent || e is KeyRepeatEvent);
- } else {
- legacyKeyboardMode(e);
- }
- return KeyEventResult.handled;
- }
- /// Send Key Event
- void newKeyboardMode(String character, int usbHid, bool down) {
- 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);
- }
- bind.sessionHandleFlutterKeyEvent(
- sessionId: sessionId,
- character: character,
- usbHid: usbHid,
- lockModes: lockModes,
- downOrUp: down);
- }
- void mapKeyboardModeRaw(RawKeyEvent e) {
- int positionCode = -1;
- int platformCode = -1;
- bool down;
- if (e.data is RawKeyEventDataMacOs) {
- RawKeyEventDataMacOs newData = e.data as RawKeyEventDataMacOs;
- positionCode = newData.keyCode;
- platformCode = newData.keyCode;
- } else if (e.data is RawKeyEventDataWindows) {
- RawKeyEventDataWindows newData = e.data as RawKeyEventDataWindows;
- positionCode = newData.scanCode;
- platformCode = newData.keyCode;
- } else if (e.data is RawKeyEventDataLinux) {
- RawKeyEventDataLinux newData = e.data as RawKeyEventDataLinux;
- // scanCode and keyCode of RawKeyEventDataLinux are incorrect.
- // 1. scanCode means keycode
- // 2. keyCode means keysym
- positionCode = newData.scanCode;
- platformCode = newData.keyCode;
- } else if (e.data is RawKeyEventDataAndroid) {
- RawKeyEventDataAndroid newData = e.data as RawKeyEventDataAndroid;
- positionCode = newData.scanCode + 8;
- platformCode = newData.keyCode;
- } else {}
- if (e is RawKeyDownEvent) {
- down = true;
- } else {
- down = false;
- }
- inputRawKey(e.character ?? '', platformCode, positionCode, down);
- }
- /// Send raw Key Event
- void inputRawKey(String name, int platformCode, int positionCode, bool down) {
- 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);
- }
- bind.sessionHandleFlutterRawKeyEvent(
- sessionId: sessionId,
- name: name,
- platformCode: platformCode,
- positionCode: positionCode,
- lockModes: lockModes,
- downOrUp: down);
- }
- void legacyKeyboardModeRaw(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
- final label = physicalKeyMap[e.physicalKey.usbHidUsage] ??
- logicalKeyMap[e.logicalKey.keyId] ??
- e.logicalKey.keyLabel;
- inputKey(label, down: down, press: press ?? false);
- }
- void legacyKeyboardMode(KeyEvent e) {
- if (e is KeyDownEvent) {
- sendKey(e, down: true);
- } else if (e is KeyRepeatEvent) {
- sendKey(e, press: true);
- } else if (e is KeyUpEvent) {
- sendKey(e);
- }
- }
- void sendKey(KeyEvent e, {bool? down, bool? press}) {
- // for maximum compatibility
- final label = physicalKeyMap[e.physicalKey.usbHidUsage] ??
- logicalKeyMap[e.logicalKey.keyId] ??
- e.logicalKey.keyLabel;
- inputKey(label, down: down, press: press ?? false);
- }
- /// 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 (!keyboardPerm) return;
- bind.sessionInputKey(
- sessionId: sessionId,
- name: name,
- down: down ?? false,
- press: press ?? true,
- alt: alt,
- ctrl: ctrl,
- shift: shift,
- command: command);
- }
- Map<String, dynamic> _getMouseEvent(PointerEvent evt, String type) {
- final Map<String, dynamic> out = {};
- // Check update event type and set buttons to be sent.
- int buttons = _lastButtons;
- if (type == _kMouseEventMove) {
- // flutter may emit move event if one button is pressed and another button
- // is pressing or releasing.
- if (evt.buttons != _lastButtons) {
- // 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
- buttons = evt.buttons - _lastButtons;
- if (buttons > 0) {
- type = _kMouseEventDown;
- } else {
- type = _kMouseEventUp;
- buttons = -buttons;
- }
- }
- } else {
- if (evt.buttons != 0) {
- buttons = evt.buttons;
- }
- }
- _lastButtons = evt.buttons;
- out['buttons'] = buttons;
- out['type'] = type;
- return out;
- }
- /// Send a mouse tap event(down and up).
- Future<void> tap(MouseButtons button) async {
- await sendMouse('down', button);
- await sendMouse('up', button);
- }
- Future<void> tapDown(MouseButtons button) async {
- await sendMouse('down', button);
- }
- Future<void> tapUp(MouseButtons button) async {
- await sendMouse('up', button);
- }
- /// Send scroll event with scroll distance [y].
- Future<void> scroll(int y) async {
- await bind.sessionSendMouse(
- sessionId: sessionId,
- 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, dynamic> modify(Map<String, dynamic> 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.
- Future<void> sendMouse(String type, MouseButtons button) async {
- if (!keyboardPerm) return;
- await bind.sessionSendMouse(
- sessionId: sessionId,
- msg: json.encode(modify({'type': type, 'buttons': button.value})));
- }
- void enterOrLeave(bool enter) {
- toReleaseKeys.release(handleKeyEvent);
- toReleaseRawKeys.release(handleRawKeyEvent);
- _pointerMovedAfterEnter = false;
- // Fix status
- if (!enter) {
- resetModifiers();
- }
- _flingTimer?.cancel();
- if (!isInputSourceFlutter) {
- bind.sessionEnterOrLeave(sessionId: sessionId, enter: enter);
- }
- if (!isWeb && enter) {
- bind.setCurSessionId(sessionId: sessionId);
- }
- }
- /// Send mouse movement event with distance in [x] and [y].
- Future<void> moveMouse(double x, double y) async {
- if (!keyboardPerm) return;
- var x2 = x.toInt();
- var y2 = y.toInt();
- await bind.sessionSendMouse(
- sessionId: sessionId,
- msg: json.encode(modify({'x': '$x2', 'y': '$y2'})));
- }
- void onPointHoverImage(PointerHoverEvent e) {
- _stopFling = true;
- if (isViewOnly) return;
- if (e.kind != ui.PointerDeviceKind.mouse) return;
- if (!isPhysicalMouse.value) {
- isPhysicalMouse.value = true;
- }
- if (isPhysicalMouse.value) {
- handleMouse(_getMouseEvent(e, _kMouseEventMove), e.position);
- }
- }
- void onPointerPanZoomStart(PointerPanZoomStartEvent e) {
- _lastScale = 1.0;
- _stopFling = true;
- if (isViewOnly) return;
- if (peerPlatform == kPeerPlatformAndroid) {
- handlePointerEvent('touch', kMouseEventTypePanStart, e.position);
- }
- }
- // https://docs.flutter.dev/release/breaking-changes/trackpad-gestures
- void onPointerPanZoomUpdate(PointerPanZoomUpdateEvent e) {
- if (isViewOnly) return;
- if (peerPlatform != kPeerPlatformAndroid) {
- final scale = ((e.scale - _lastScale) * 1000).toInt();
- _lastScale = e.scale;
- if (scale != 0) {
- bind.sessionSendPointer(
- sessionId: sessionId,
- msg: json.encode(
- PointerEventToRust(kPointerEventKindTouch, 'scale', scale)
- .toJson()));
- return;
- }
- }
- final delta = e.panDelta;
- _trackpadLastDelta = delta;
- var x = delta.dx.toInt();
- var y = delta.dy.toInt();
- if (peerPlatform == kPeerPlatformLinux) {
- _trackpadScrollUnsent += (delta * _trackpadSpeed);
- x = _trackpadScrollUnsent.dx.truncate();
- y = _trackpadScrollUnsent.dy.truncate();
- _trackpadScrollUnsent -= Offset(x.toDouble(), y.toDouble());
- } else {
- if (x == 0 && y == 0) {
- final thr = 0.1;
- if (delta.dx.abs() > delta.dy.abs()) {
- x = delta.dx > thr ? 1 : (delta.dx < -thr ? -1 : 0);
- } else {
- y = delta.dy > thr ? 1 : (delta.dy < -thr ? -1 : 0);
- }
- }
- }
- if (x != 0 || y != 0) {
- if (peerPlatform == kPeerPlatformAndroid) {
- handlePointerEvent('touch', kMouseEventTypePanUpdate,
- Offset(x.toDouble(), y.toDouble()));
- } else {
- bind.sessionSendMouse(
- sessionId: sessionId,
- msg: '{"type": "trackpad", "x": "$x", "y": "$y"}');
- }
- }
- }
- void _scheduleFling(double x, double y, int delay) {
- if ((x == 0 && y == 0) || _stopFling) {
- _fling = false;
- return;
- }
- _flingTimer = Timer(Duration(milliseconds: delay), () {
- if (_stopFling) {
- _fling = false;
- return;
- }
- final d = 0.97;
- x *= d;
- y *= d;
- // Try set delta (x,y) and delay.
- var dx = x.toInt();
- var dy = y.toInt();
- if (parent.target?.ffiModel.pi.platform == kPeerPlatformLinux) {
- dx = (x * _trackpadSpeed).toInt();
- dy = (y * _trackpadSpeed).toInt();
- }
- var delay = _flingBaseDelay;
- if (dx == 0 && dy == 0) {
- _fling = false;
- return;
- }
- bind.sessionSendMouse(
- sessionId: sessionId,
- msg: '{"type": "trackpad", "x": "$dx", "y": "$dy"}');
- _scheduleFling(x, y, delay);
- });
- }
- void waitLastFlingDone() {
- if (_fling) {
- _stopFling = true;
- }
- for (var i = 0; i < 5; i++) {
- if (!_fling) {
- break;
- }
- sleep(Duration(milliseconds: 10));
- }
- _flingTimer?.cancel();
- }
- void onPointerPanZoomEnd(PointerPanZoomEndEvent e) {
- if (peerPlatform == kPeerPlatformAndroid) {
- handlePointerEvent('touch', kMouseEventTypePanEnd, e.position);
- return;
- }
- bind.sessionSendPointer(
- sessionId: sessionId,
- msg: json.encode(
- PointerEventToRust(kPointerEventKindTouch, 'scale', 0).toJson()));
- waitLastFlingDone();
- _stopFling = false;
- // 2.0 is an experience value
- double minFlingValue = 2.0;
- if (_trackpadLastDelta.dx.abs() > minFlingValue ||
- _trackpadLastDelta.dy.abs() > minFlingValue) {
- _fling = true;
- _scheduleFling(
- _trackpadLastDelta.dx, _trackpadLastDelta.dy, _flingBaseDelay);
- }
- _trackpadLastDelta = Offset.zero;
- }
- void onPointDownImage(PointerDownEvent e) {
- debugPrint("onPointDownImage ${e.kind}");
- _stopFling = true;
- if (isDesktop) _queryOtherWindowCoords = true;
- _remoteWindowCoords = [];
- _windowRect = null;
- if (isViewOnly) return;
- if (e.kind != ui.PointerDeviceKind.mouse) {
- if (isPhysicalMouse.value) {
- isPhysicalMouse.value = false;
- }
- }
- if (isPhysicalMouse.value) {
- handleMouse(_getMouseEvent(e, _kMouseEventDown), e.position);
- }
- }
- void onPointUpImage(PointerUpEvent e) {
- if (isDesktop) _queryOtherWindowCoords = false;
- if (isViewOnly) return;
- if (e.kind != ui.PointerDeviceKind.mouse) return;
- if (isPhysicalMouse.value) {
- handleMouse(_getMouseEvent(e, _kMouseEventUp), e.position);
- }
- }
- void onPointMoveImage(PointerMoveEvent e) {
- if (isViewOnly) return;
- if (e.kind != ui.PointerDeviceKind.mouse) return;
- if (_queryOtherWindowCoords) {
- Future.delayed(Duration.zero, () async {
- _windowRect = await fillRemoteCoordsAndGetCurFrame(_remoteWindowCoords);
- });
- _queryOtherWindowCoords = false;
- }
- if (isPhysicalMouse.value) {
- handleMouse(_getMouseEvent(e, _kMouseEventMove), e.position);
- }
- }
- static Future<Rect?> fillRemoteCoordsAndGetCurFrame(
- List<RemoteWindowCoords> remoteWindowCoords) async {
- final coords =
- await rustDeskWinManager.getOtherRemoteWindowCoordsFromMain();
- final wc = WindowController.fromWindowId(kWindowId!);
- try {
- final frame = await wc.getFrame();
- for (final c in coords) {
- c.relativeOffset = Offset(
- c.windowRect.left - frame.left, c.windowRect.top - frame.top);
- remoteWindowCoords.add(c);
- }
- return frame;
- } catch (e) {
- // Unreachable code
- debugPrint("Failed to get frame of window $kWindowId, it may be hidden");
- }
- return null;
- }
- void onPointerSignalImage(PointerSignalEvent e) {
- if (isViewOnly) return;
- 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(
- sessionId: sessionId,
- msg: '{"type": "wheel", "x": "$dx", "y": "$dy"}');
- }
- }
- void refreshMousePos() => handleMouse({
- 'buttons': 0,
- 'type': _kMouseEventMove,
- }, lastMousePos);
- void tryMoveEdgeOnExit(Offset pos) => handleMouse(
- {
- 'buttons': 0,
- 'type': _kMouseEventMove,
- },
- pos,
- onExit: true,
- );
- static double tryGetNearestRange(double v, double min, double max, double n) {
- if (v < min && v >= min - n) {
- v = min;
- }
- if (v > max && v <= max + n) {
- v = max;
- }
- return v;
- }
- Offset setNearestEdge(double x, double y, Rect rect) {
- double left = x - rect.left;
- double right = rect.right - 1 - x;
- double top = y - rect.top;
- double bottom = rect.bottom - 1 - y;
- if (left < right && left < top && left < bottom) {
- x = rect.left;
- }
- if (right < left && right < top && right < bottom) {
- x = rect.right - 1;
- }
- if (top < left && top < right && top < bottom) {
- y = rect.top;
- }
- if (bottom < left && bottom < right && bottom < top) {
- y = rect.bottom - 1;
- }
- return Offset(x, y);
- }
- void handlePointerEvent(String kind, String type, Offset offset) {
- double x = offset.dx;
- double y = offset.dy;
- if (_checkPeerControlProtected(x, y)) {
- return;
- }
- // Only touch events are handled for now. So we can just ignore buttons.
- // to-do: handle mouse events
- late final dynamic evtValue;
- if (type == kMouseEventTypePanUpdate) {
- evtValue = {
- 'x': x.toInt(),
- 'y': y.toInt(),
- };
- } else {
- final isMoveTypes = [kMouseEventTypePanStart, kMouseEventTypePanEnd];
- final pos = handlePointerDevicePos(
- kPointerEventKindTouch,
- x,
- y,
- isMoveTypes.contains(type),
- type,
- );
- if (pos == null) {
- return;
- }
- evtValue = {
- 'x': pos.x.toInt(),
- 'y': pos.y.toInt(),
- };
- }
- final evt = PointerEventToRust(kind, type, evtValue).toJson();
- bind.sessionSendPointer(
- sessionId: sessionId, msg: json.encode(modify(evt)));
- }
- bool _checkPeerControlProtected(double x, double y) {
- final cursorModel = parent.target!.cursorModel;
- if (cursorModel.isPeerControlProtected) {
- lastMousePos = ui.Offset(x, y);
- return true;
- }
- if (!cursorModel.gotMouseControl) {
- bool selfGetControl =
- (x - lastMousePos.dx).abs() > kMouseControlDistance ||
- (y - lastMousePos.dy).abs() > kMouseControlDistance;
- if (selfGetControl) {
- cursorModel.gotMouseControl = true;
- } else {
- lastMousePos = ui.Offset(x, y);
- return true;
- }
- }
- lastMousePos = ui.Offset(x, y);
- return false;
- }
- void handleMouse(
- Map<String, dynamic> evt,
- Offset offset, {
- bool onExit = false,
- }) {
- double x = offset.dx;
- double y = max(0.0, offset.dy);
- if (_checkPeerControlProtected(x, y)) {
- return;
- }
- var type = kMouseEventTypeDefault;
- var isMove = false;
- switch (evt['type']) {
- case _kMouseEventDown:
- type = kMouseEventTypeDown;
- break;
- case _kMouseEventUp:
- type = kMouseEventTypeUp;
- break;
- case _kMouseEventMove:
- _pointerMovedAfterEnter = true;
- isMove = true;
- break;
- default:
- return;
- }
- evt['type'] = type;
- if (type == kMouseEventTypeDown && !_pointerMovedAfterEnter) {
- // Move mouse to the position of the down event first.
- lastMousePos = ui.Offset(x, y);
- refreshMousePos();
- }
- final pos = handlePointerDevicePos(
- kPointerEventKindMouse,
- x,
- y,
- isMove,
- type,
- onExit: onExit,
- buttons: evt['buttons'],
- );
- if (pos == null) {
- return;
- }
- if (type != '') {
- evt['x'] = '0';
- evt['y'] = '0';
- } else {
- evt['x'] = '${pos.x.toInt()}';
- evt['y'] = '${pos.y.toInt()}';
- }
- Map<int, String> mapButtons = {
- kPrimaryMouseButton: 'left',
- kSecondaryMouseButton: 'right',
- kMiddleMouseButton: 'wheel',
- kBackMouseButton: 'back',
- kForwardMouseButton: 'forward'
- };
- evt['buttons'] = mapButtons[evt['buttons']] ?? '';
- bind.sessionSendMouse(sessionId: sessionId, msg: json.encode(modify(evt)));
- }
- Point? handlePointerDevicePos(
- String kind,
- double x,
- double y,
- bool isMove,
- String evtType, {
- bool onExit = false,
- int buttons = kPrimaryMouseButton,
- }) {
- final ffiModel = parent.target!.ffiModel;
- CanvasCoords canvas =
- CanvasCoords.fromCanvasModel(parent.target!.canvasModel);
- Rect? rect = ffiModel.rect;
- if (isMove) {
- if (_remoteWindowCoords.isNotEmpty &&
- _windowRect != null &&
- !_isInCurrentWindow(x, y)) {
- final coords =
- findRemoteCoords(x, y, _remoteWindowCoords, devicePixelRatio);
- if (coords != null) {
- isMove = false;
- canvas = coords.canvas;
- rect = coords.remoteRect;
- x -= coords.relativeOffset.dx / devicePixelRatio;
- y -= coords.relativeOffset.dy / devicePixelRatio;
- }
- }
- }
- y -= CanvasModel.topToEdge;
- x -= CanvasModel.leftToEdge;
- if (isMove) {
- parent.target!.canvasModel.moveDesktopMouse(x, y);
- }
- return _handlePointerDevicePos(
- kind,
- x,
- y,
- isMove,
- canvas,
- rect,
- evtType,
- onExit: onExit,
- buttons: buttons,
- );
- }
- bool _isInCurrentWindow(double x, double y) {
- final w = _windowRect!.width / devicePixelRatio;
- final h = _windowRect!.width / devicePixelRatio;
- return x >= 0 && y >= 0 && x <= w && y <= h;
- }
- static RemoteWindowCoords? findRemoteCoords(double x, double y,
- List<RemoteWindowCoords> remoteWindowCoords, double devicePixelRatio) {
- x *= devicePixelRatio;
- y *= devicePixelRatio;
- for (final c in remoteWindowCoords) {
- if (x >= c.relativeOffset.dx &&
- y >= c.relativeOffset.dy &&
- x <= c.relativeOffset.dx + c.windowRect.width &&
- y <= c.relativeOffset.dy + c.windowRect.height) {
- return c;
- }
- }
- return null;
- }
- Point? _handlePointerDevicePos(
- String kind,
- double x,
- double y,
- bool moveInCanvas,
- CanvasCoords canvas,
- Rect? rect,
- String evtType, {
- bool onExit = false,
- int buttons = kPrimaryMouseButton,
- }) {
- if (rect == null) {
- return null;
- }
- final nearThr = 3;
- var nearRight = (canvas.size.width - x) < nearThr;
- var nearBottom = (canvas.size.height - y) < nearThr;
- final imageWidth = rect.width * canvas.scale;
- final imageHeight = rect.height * canvas.scale;
- if (canvas.scrollStyle == ScrollStyle.scrollbar) {
- x += imageWidth * canvas.scrollX;
- y += imageHeight * canvas.scrollY;
- // boxed size is a center widget
- if (canvas.size.width > imageWidth) {
- x -= ((canvas.size.width - imageWidth) / 2);
- }
- if (canvas.size.height > imageHeight) {
- y -= ((canvas.size.height - imageHeight) / 2);
- }
- } else {
- x -= canvas.x;
- y -= canvas.y;
- }
- x /= canvas.scale;
- y /= canvas.scale;
- if (canvas.scale > 0 && canvas.scale < 1) {
- final step = 1.0 / canvas.scale - 1;
- if (nearRight) {
- x += step;
- }
- if (nearBottom) {
- y += step;
- }
- }
- x += rect.left;
- y += rect.top;
- if (onExit) {
- final pos = setNearestEdge(x, y, rect);
- x = pos.dx;
- y = pos.dy;
- }
- return InputModel.getPointInRemoteRect(
- true, peerPlatform, kind, evtType, x, y, rect,
- buttons: buttons);
- }
- static Point<double>? getPointInRemoteRect(
- bool isLocalDesktop,
- String? peerPlatform,
- String kind,
- String evtType,
- double evtX,
- double evtY,
- Rect rect,
- {int buttons = kPrimaryMouseButton}) {
- double minX = rect.left;
- // https://github.com/rustdesk/rustdesk/issues/6678
- // For Windows, [0,maxX], [0,maxY] should be set to enable window snapping.
- double maxX = (rect.left + rect.width) -
- (peerPlatform == kPeerPlatformWindows ? 0 : 1);
- double minY = rect.top;
- double maxY = (rect.top + rect.height) -
- (peerPlatform == kPeerPlatformWindows ? 0 : 1);
- evtX = InputModel.tryGetNearestRange(evtX, minX, maxX, 5);
- evtY = InputModel.tryGetNearestRange(evtY, minY, maxY, 5);
- if (isLocalDesktop) {
- if (kind == kPointerEventKindMouse) {
- if (evtX < minX || evtY < minY || evtX > maxX || evtY > maxY) {
- // If left mouse up, no early return.
- if (!(buttons == kPrimaryMouseButton &&
- evtType == kMouseEventTypeUp)) {
- return null;
- }
- }
- }
- } else {
- bool evtXInRange = evtX >= minX && evtX <= maxX;
- bool evtYInRange = evtY >= minY && evtY <= maxY;
- if (!(evtXInRange || evtYInRange)) {
- return null;
- }
- if (evtX < minX) {
- evtX = minX;
- } else if (evtX > maxX) {
- evtX = maxX;
- }
- if (evtY < minY) {
- evtY = minY;
- } else if (evtY > maxY) {
- evtY = maxY;
- }
- }
- return Point(evtX, evtY);
- }
- /// Web only
- void listenToMouse(bool yesOrNo) {
- if (yesOrNo) {
- platformFFI.startDesktopWebListener();
- } else {
- platformFFI.stopDesktopWebListener();
- }
- }
- void onMobileBack() => tap(MouseButtons.right);
- void onMobileHome() => tap(MouseButtons.wheel);
- Future<void> onMobileApps() async {
- sendMouse('down', MouseButtons.wheel);
- await Future.delayed(const Duration(milliseconds: 500));
- sendMouse('up', MouseButtons.wheel);
- }
- // Simulate a key press event.
- // `usbHidUsage` is the USB HID usage code of the key.
- Future<void> tapHidKey(int usbHidUsage) async {
- newKeyboardMode(kKeyFlutterKey, usbHidUsage, true);
- await Future.delayed(Duration(milliseconds: 100));
- newKeyboardMode(kKeyFlutterKey, usbHidUsage, false);
- }
- Future<void> onMobileVolumeUp() async =>
- await tapHidKey(PhysicalKeyboardKey.audioVolumeUp.usbHidUsage & 0xFFFF);
- Future<void> onMobileVolumeDown() async =>
- await tapHidKey(PhysicalKeyboardKey.audioVolumeDown.usbHidUsage & 0xFFFF);
- Future<void> onMobilePower() async =>
- await tapHidKey(PhysicalKeyboardKey.power.usbHidUsage & 0xFFFF);
- }
|