From fb59e9d939400743fd496cc738454a5fcbd119d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Recep=20Ko=CC=88seog=CC=86lu?= Date: Wed, 6 Sep 2023 15:43:57 +0300 Subject: [PATCH] error handling and add custom keyboard key listener --- .../remote_frame_buffer_client_isolate.dart | 2 + .../remote_frame_buffer_gesture_detector.dart | 94 +++++++++++-------- .../remote_frame_buffer_isolate_messages.dart | 1 + ...frame_buffer_isolate_messages.freezed.dart | 41 ++++++-- lib/src/remote_frame_buffer_widget.dart | 68 +++++++++++--- 5 files changed, 148 insertions(+), 58 deletions(-) diff --git a/lib/src/remote_frame_buffer_client_isolate.dart b/lib/src/remote_frame_buffer_client_isolate.dart index d08bb52..f4abaaa 100644 --- a/lib/src/remote_frame_buffer_client_isolate.dart +++ b/lib/src/remote_frame_buffer_client_isolate.dart @@ -86,7 +86,9 @@ Future startRemoteFrameBufferClient( hostname: initMessage.hostName, password: initMessage.password.toNullable(), port: initMessage.port, + timeout: initMessage.timeout, ); + client ..handleIncomingMessages() ..requestUpdate(); diff --git a/lib/src/remote_frame_buffer_gesture_detector.dart b/lib/src/remote_frame_buffer_gesture_detector.dart index c924ab7..f243a2c 100644 --- a/lib/src/remote_frame_buffer_gesture_detector.dart +++ b/lib/src/remote_frame_buffer_gesture_detector.dart @@ -76,51 +76,65 @@ class RemoteFrameBufferGestureDetector extends GestureDetector { GestureTapDownCallback? get onTapDown => (final TapDownDetails details) => _sendPort.match( () {}, - (final SendPort sendPort) => sendPort.send( - RemoteFrameBufferIsolateSendMessage.pointerEvent( - button1Down: true, - button2Down: false, - button3Down: false, - button4Down: false, - button5Down: false, - button6Down: false, - button7Down: false, - button8Down: false, - x: (details.localPosition.dx / - _remoteFrameBufferWidgetSize.width * - _image.width) - .toInt(), - y: (details.localPosition.dy / - _remoteFrameBufferWidgetSize.height * - _image.height) - .toInt(), - ), - ), + (final SendPort sendPort) { + num x = details.localPosition.dx / + _remoteFrameBufferWidgetSize.width * + _image.width; + num y = details.localPosition.dy / + _remoteFrameBufferWidgetSize.height * + _image.height; + + if (x.isInfinite || y.isInfinite) { + return; + } + + sendPort.send( + RemoteFrameBufferIsolateSendMessage.pointerEvent( + button1Down: true, + button2Down: false, + button3Down: false, + button4Down: false, + button5Down: false, + button6Down: false, + button7Down: false, + button8Down: false, + x: x.toInt(), + y: y.toInt(), + ), + ); + }, ); @override GestureTapUpCallback? get onTapUp => (final TapUpDetails details) => _sendPort.match( () {}, - (final SendPort sendPort) => sendPort.send( - RemoteFrameBufferIsolateSendMessage.pointerEvent( - button1Down: false, - button2Down: false, - button3Down: false, - button4Down: false, - button5Down: false, - button6Down: false, - button7Down: false, - button8Down: false, - x: (details.localPosition.dx / - _remoteFrameBufferWidgetSize.width * - _image.width) - .toInt(), - y: (details.localPosition.dy / - _remoteFrameBufferWidgetSize.height * - _image.height) - .toInt(), - ), - ), + (final SendPort sendPort) { + num x = details.localPosition.dx / + _remoteFrameBufferWidgetSize.width * + _image.width; + num y = details.localPosition.dy / + _remoteFrameBufferWidgetSize.height * + _image.height; + + if (x.isInfinite || y.isInfinite) { + return; + } + + sendPort.send( + RemoteFrameBufferIsolateSendMessage.pointerEvent( + button1Down: false, + button2Down: false, + button3Down: false, + button4Down: false, + button5Down: false, + button6Down: false, + button7Down: false, + button8Down: false, + x: x.toInt(), + y: y.toInt(), + ), + ); + }, ); } diff --git a/lib/src/remote_frame_buffer_isolate_messages.dart b/lib/src/remote_frame_buffer_isolate_messages.dart index 09ff52d..ad785b1 100644 --- a/lib/src/remote_frame_buffer_isolate_messages.dart +++ b/lib/src/remote_frame_buffer_isolate_messages.dart @@ -15,6 +15,7 @@ class RemoteFrameBufferIsolateInitMessage required final String hostName, required final Option password, required final int port, + required final Duration? timeout, /// The [SendPort] used for communicating with the caller. required final SendPort sendPort, diff --git a/lib/src/remote_frame_buffer_isolate_messages.freezed.dart b/lib/src/remote_frame_buffer_isolate_messages.freezed.dart index 4e05856..df17666 100644 --- a/lib/src/remote_frame_buffer_isolate_messages.freezed.dart +++ b/lib/src/remote_frame_buffer_isolate_messages.freezed.dart @@ -19,6 +19,7 @@ mixin _$RemoteFrameBufferIsolateInitMessage { String get hostName => throw _privateConstructorUsedError; Option get password => throw _privateConstructorUsedError; int get port => throw _privateConstructorUsedError; + Duration? get timeout => throw _privateConstructorUsedError; /// The [SendPort] used for communicating with the caller. SendPort get sendPort => throw _privateConstructorUsedError; @@ -37,8 +38,13 @@ abstract class $RemoteFrameBufferIsolateInitMessageCopyWith<$Res> { _$RemoteFrameBufferIsolateInitMessageCopyWithImpl<$Res, RemoteFrameBufferIsolateInitMessage>; @useResult - $Res call( - {String hostName, Option password, int port, SendPort sendPort}); + $Res call({ + String hostName, + Option password, + int port, + Duration? timeout, + SendPort sendPort, + }); } /// @nodoc @@ -58,6 +64,7 @@ class _$RemoteFrameBufferIsolateInitMessageCopyWithImpl<$Res, Object? hostName = null, Object? password = null, Object? port = null, + Object? timeout = null, Object? sendPort = null, }) { return _then(_value.copyWith( @@ -73,6 +80,10 @@ class _$RemoteFrameBufferIsolateInitMessageCopyWithImpl<$Res, ? _value.port : port // ignore: cast_nullable_to_non_nullable as int, + timeout: null == timeout + ? _value.timeout + : timeout // ignore: cast_nullable_to_non_nullable + as Duration?, sendPort: null == sendPort ? _value.sendPort : sendPort // ignore: cast_nullable_to_non_nullable @@ -90,8 +101,13 @@ abstract class _$$_RemoteFrameBufferIsolateInitMessageCopyWith<$Res> __$$_RemoteFrameBufferIsolateInitMessageCopyWithImpl<$Res>; @override @useResult - $Res call( - {String hostName, Option password, int port, SendPort sendPort}); + $Res call({ + String hostName, + Option password, + int port, + Duration? timeout, + SendPort sendPort, + }); } /// @nodoc @@ -110,6 +126,7 @@ class __$$_RemoteFrameBufferIsolateInitMessageCopyWithImpl<$Res> Object? hostName = null, Object? password = null, Object? port = null, + Object? timeout = null, Object? sendPort = null, }) { return _then(_$_RemoteFrameBufferIsolateInitMessage( @@ -125,6 +142,10 @@ class __$$_RemoteFrameBufferIsolateInitMessageCopyWithImpl<$Res> ? _value.port : port // ignore: cast_nullable_to_non_nullable as int, + timeout: null == timeout + ? _value.timeout + : timeout // ignore: cast_nullable_to_non_nullable + as Duration?, sendPort: null == sendPort ? _value.sendPort : sendPort // ignore: cast_nullable_to_non_nullable @@ -142,6 +163,7 @@ class _$_RemoteFrameBufferIsolateInitMessage {required this.hostName, required this.password, required this.port, + required this.timeout, required this.sendPort}); @override @@ -150,6 +172,8 @@ class _$_RemoteFrameBufferIsolateInitMessage final Option password; @override final int port; + @override + final Duration? timeout; /// The [SendPort] used for communicating with the caller. @override @@ -157,7 +181,7 @@ class _$_RemoteFrameBufferIsolateInitMessage @override String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { - return 'RemoteFrameBufferIsolateInitMessage(hostName: $hostName, password: $password, port: $port, sendPort: $sendPort)'; + return 'RemoteFrameBufferIsolateInitMessage(hostName: $hostName, password: $password, port: $port, sendPort: $sendPort, timeout: $timeout)'; } @override @@ -168,6 +192,7 @@ class _$_RemoteFrameBufferIsolateInitMessage ..add(DiagnosticsProperty('hostName', hostName)) ..add(DiagnosticsProperty('password', password)) ..add(DiagnosticsProperty('port', port)) + ..add(DiagnosticsProperty('timeout', timeout)) ..add(DiagnosticsProperty('sendPort', sendPort)); } @@ -181,13 +206,14 @@ class _$_RemoteFrameBufferIsolateInitMessage (identical(other.password, password) || other.password == password) && (identical(other.port, port) || other.port == port) && + (identical(other.timeout, timeout) || other.timeout == timeout) && (identical(other.sendPort, sendPort) || other.sendPort == sendPort)); } @override int get hashCode => - Object.hash(runtimeType, hostName, password, port, sendPort); + Object.hash(runtimeType, hostName, password, port, sendPort, timeout); @JsonKey(ignore: true) @override @@ -204,6 +230,7 @@ abstract class _RemoteFrameBufferIsolateInitMessage {required final String hostName, required final Option password, required final int port, + required final Duration? timeout, required final SendPort sendPort}) = _$_RemoteFrameBufferIsolateInitMessage; @@ -214,6 +241,8 @@ abstract class _RemoteFrameBufferIsolateInitMessage @override int get port; @override + Duration? get timeout; + @override /// The [SendPort] used for communicating with the caller. SendPort get sendPort; diff --git a/lib/src/remote_frame_buffer_widget.dart b/lib/src/remote_frame_buffer_widget.dart index be3507e..906c756 100644 --- a/lib/src/remote_frame_buffer_widget.dart +++ b/lib/src/remote_frame_buffer_widget.dart @@ -26,6 +26,9 @@ class RemoteFrameBufferWidget extends StatefulWidget { final Option _onError; final Option _password; final int _port; + final Option>> _keyEventNotifier; + final Option _monitorClipBoard; + final Duration? _timeout; /// Immediately tries to establish a connection to a remote server at /// [hostName]:[port], optionally using [password]. @@ -36,11 +39,17 @@ class RemoteFrameBufferWidget extends StatefulWidget { final void Function(Object error)? onError, final String? password, final int port = 5900, + final ValueNotifier>? keyEventNotifier, + final bool? monitorClipBoard = true, + final Duration? timeout, }) : _connectingWidget = optionOf(connectingWidget), _hostName = hostName, _onError = optionOf(onError), _password = optionOf(password), - _port = port; + _port = port, + _keyEventNotifier = optionOf(keyEventNotifier), + _monitorClipBoard = optionOf(monitorClipBoard), + _timeout = timeout; @override State createState() => @@ -77,7 +86,9 @@ class RemoteFrameBufferWidgetState extends State { @override void dispose() { - _clipBoardMonitorTimer.cancel(); + if (widget._monitorClipBoard.getOrElse(() => false)) { + _clipBoardMonitorTimer.cancel(); + } _streamSubscription.match( () {}, (final StreamSubscription subscription) => @@ -91,6 +102,11 @@ class RemoteFrameBufferWidgetState extends State { () {}, (final Isolate isolate) => isolate.kill(), ); + widget._keyEventNotifier.match( + () {}, + (final ValueNotifier> notifier) => + notifier.removeListener(_keyEventListener), + ); RawKeyboard.instance.removeListener(_rawKeyEventListener); super.dispose(); } @@ -98,7 +114,14 @@ class RemoteFrameBufferWidgetState extends State { @override void initState() { super.initState(); - _monitorClipBoard(); + if (widget._monitorClipBoard.getOrElse(() => false)) { + _monitorClipBoard(); + } + widget._keyEventNotifier.match( + () {}, + (final ValueNotifier> notifier) => + notifier.addListener(_keyEventListener), + ); RawKeyboard.instance.addListener(_rawKeyEventListener); unawaited(_initAsync()); } @@ -277,6 +300,7 @@ class RemoteFrameBufferWidgetState extends State { hostName: widget._hostName, password: widget._password, port: widget._port, + timeout: widget._timeout, sendPort: receivePort.sendPort, ), onError: receivePort.sendPort, @@ -316,16 +340,36 @@ class RemoteFrameBufferWidgetState extends State { ); } - void _rawKeyEventListener(final RawKeyEvent rawKeyEvent) => - _isolateSendPort.match( - () {}, - (final SendPort sendPort) => sendPort.send( - RemoteFrameBufferIsolateSendMessage.keyEvent( - down: rawKeyEvent.isKeyPressed(rawKeyEvent.logicalKey), - key: rawKeyEvent.logicalKey.asXWindowSystemKey(), - ), + void _keyEventListener() { + _isolateSendPort.match( + () {}, + (final SendPort sendPort) { + widget._keyEventNotifier.match(() => null, + (final ValueNotifier> notifier) { + final Map event = notifier.value; + final LogicalKeyboardKey keyboardKey = event['keyboardKey']; + sendPort.send( + RemoteFrameBufferIsolateSendMessage.keyEvent( + down: event['isDown'], + key: keyboardKey.asXWindowSystemKey(), + ), + ); + }); + }, + ); + } + + void _rawKeyEventListener(final RawKeyEvent rawKeyEvent) { + _isolateSendPort.match( + () {}, + (final SendPort sendPort) => sendPort.send( + RemoteFrameBufferIsolateSendMessage.keyEvent( + down: rawKeyEvent.isKeyPressed(rawKeyEvent.logicalKey), + key: rawKeyEvent.logicalKey.asXWindowSystemKey(), ), - ); + ), + ); + } /// Updates [frameBuffer] with the given [rectangle]s. @visibleForTesting