Merge pull request #5489 from fufesou/fix/enable_menu_before_image

Fix/enable menu before image
This commit is contained in:
RustDesk 2023-08-24 19:57:23 +08:00 committed by GitHub
commit c450b41e8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 108 additions and 59 deletions

View File

@ -228,49 +228,67 @@ class _RemotePageState extends State<RemotePage>
removeSharedStates(widget.id); removeSharedStates(widget.id);
} }
Widget buildBody(BuildContext context) { Widget emptyOverlay() => BlockableOverlay(
return Scaffold( /// the Overlay key will be set with _blockableOverlayState in BlockableOverlay
backgroundColor: Theme.of(context).colorScheme.background, /// see override build() in [BlockableOverlay]
/// the Overlay key will be set with _blockableOverlayState in BlockableOverlay
/// see override build() in [BlockableOverlay]
body: BlockableOverlay(
state: _blockableOverlayState, state: _blockableOverlayState,
underlying: Container( underlying: Container(
color: Colors.black, color: Colors.transparent,
child: RawKeyFocusScope( ),
focusNode: _rawKeyFocusNode, );
onFocusChange: (bool imageFocused) {
debugPrint( Widget buildBody(BuildContext context) {
"onFocusChange(window active:${!_isWindowBlur}) $imageFocused"); remoteToolbar(BuildContext context) => RemoteToolbar(
// See [onWindowBlur]. id: widget.id,
if (Platform.isWindows) { ffi: _ffi,
if (_isWindowBlur) { state: widget.toolbarState,
imageFocused = false; onEnterOrLeaveImageSetter: (func) =>
Future.delayed(Duration.zero, () { _onEnterOrLeaveImage4Toolbar = func,
_rawKeyFocusNode.unfocus(); onEnterOrLeaveImageCleaner: () => _onEnterOrLeaveImage4Toolbar = null,
}); );
return Scaffold(
backgroundColor: Theme.of(context).colorScheme.background,
body: Stack(
children: [
Container(
color: Colors.black,
child: RawKeyFocusScope(
focusNode: _rawKeyFocusNode,
onFocusChange: (bool imageFocused) {
debugPrint(
"onFocusChange(window active:${!_isWindowBlur}) $imageFocused");
// See [onWindowBlur].
if (Platform.isWindows) {
if (_isWindowBlur) {
imageFocused = false;
Future.delayed(Duration.zero, () {
_rawKeyFocusNode.unfocus();
});
}
if (imageFocused) {
_ffi.inputModel.enterOrLeave(true);
} else {
_ffi.inputModel.enterOrLeave(false);
}
} }
if (imageFocused) { },
_ffi.inputModel.enterOrLeave(true); inputModel: _ffi.inputModel,
} else { child: getBodyForDesktop(context))),
_ffi.inputModel.enterOrLeave(false); Obx(() => Stack(
} children: [
} _ffi.ffiModel.pi.isSet.isTrue &&
}, _ffi.ffiModel.waitForFirstImage.isTrue
inputModel: _ffi.inputModel, ? emptyOverlay()
child: getBodyForDesktop(context))), : Offstage(),
upperLayer: [ // Use Overlay to enable rebuild every time on menu button click.
OverlayEntry( _ffi.ffiModel.pi.isSet.isTrue
builder: (context) => RemoteToolbar( ? Overlay(initialEntries: [
id: widget.id, OverlayEntry(builder: remoteToolbar)
ffi: _ffi, ])
state: widget.toolbarState, : remoteToolbar(context),
onEnterOrLeaveImageSetter: (func) => _ffi.ffiModel.pi.isSet.isFalse ? emptyOverlay() : Offstage(),
_onEnterOrLeaveImage4Toolbar = func, ],
onEnterOrLeaveImageCleaner: () => )),
_onEnterOrLeaveImage4Toolbar = null,
))
], ],
), ),
); );

View File

@ -266,7 +266,11 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
if (e.kind != ui.PointerDeviceKind.mouse) { if (e.kind != ui.PointerDeviceKind.mouse) {
return; return;
} }
if (e.buttons == 2) { final remotePage = tabController.state.value.tabs
.firstWhere((tab) => tab.key == key)
.page as RemotePage;
if (remotePage.ffi.ffiModel.pi.isSet.isTrue &&
e.buttons == 2) {
showRightMenu( showRightMenu(
(CancelFunc cancelFunc) { (CancelFunc cancelFunc) {
return _tabMenuBuilder(key, cancelFunc); return _tabMenuBuilder(key, cancelFunc);

View File

@ -77,7 +77,7 @@ CancelFunc showRightMenu(ToastBuilder builder,
targetContext: context, targetContext: context,
verticalOffset: 0, verticalOffset: 0,
horizontalOffset: 0, horizontalOffset: 0,
duration: Duration(seconds: 4), duration: Duration(seconds: 300),
animationDuration: Duration(milliseconds: 0), animationDuration: Duration(milliseconds: 0),
animationReverseDuration: Duration(milliseconds: 0), animationReverseDuration: Duration(milliseconds: 0),
preferDirection: PreferDirection.rightTop, preferDirection: PreferDirection.rightTop,

View File

@ -38,8 +38,6 @@ import 'platform_model.dart';
typedef HandleMsgBox = Function(Map<String, dynamic> evt, String id); typedef HandleMsgBox = Function(Map<String, dynamic> evt, String id);
typedef ReconnectHandle = Function(OverlayDialogManager, SessionID, bool); typedef ReconnectHandle = Function(OverlayDialogManager, SessionID, bool);
final _waitForImageDialogShow = <UuidValue, bool>{};
final _waitForFirstImage = <UuidValue, bool>{};
final _constSessionId = Uuid().v4obj(); final _constSessionId = Uuid().v4obj();
class CachedPeerData { class CachedPeerData {
@ -100,6 +98,10 @@ class FfiModel with ChangeNotifier {
WeakReference<FFI> parent; WeakReference<FFI> parent;
late final SessionID sessionId; late final SessionID sessionId;
RxBool waitForImageDialogShow = true.obs;
Timer? waitForImageTimer;
RxBool waitForFirstImage = true.obs;
Map<String, bool> get permissions => _permissions; Map<String, bool> get permissions => _permissions;
Display get display => _display; Display get display => _display;
@ -158,6 +160,7 @@ class FfiModel with ChangeNotifier {
_timer?.cancel(); _timer?.cancel();
_timer = null; _timer = null;
clearPermissions(); clearPermissions();
waitForImageTimer?.cancel();
} }
setConnectionType(String peerId, bool secure, bool direct) { setConnectionType(String peerId, bool secure, bool direct) {
@ -498,7 +501,7 @@ class FfiModel with ChangeNotifier {
closeConnection(); closeConnection();
} }
if (_waitForFirstImage[sessionId] == false) return; if (waitForFirstImage.isFalse) return;
dialogManager.show( dialogManager.show(
(setState, close, context) => CustomAlertDialog( (setState, close, context) => CustomAlertDialog(
title: null, title: null,
@ -509,7 +512,12 @@ class FfiModel with ChangeNotifier {
onCancel: onClose), onCancel: onClose),
tag: '$sessionId-waiting-for-image', tag: '$sessionId-waiting-for-image',
); );
_waitForImageDialogShow[sessionId] = true; waitForImageDialogShow.value = true;
waitForImageTimer = Timer(Duration(milliseconds: 1500), () {
if (waitForFirstImage.isTrue) {
bind.sessionInputOsPassword(sessionId: sessionId, value: '');
}
});
bind.sessionOnWaitingForImageDialogShow(sessionId: sessionId); bind.sessionOnWaitingForImageDialogShow(sessionId: sessionId);
} }
@ -578,7 +586,7 @@ class FfiModel with ChangeNotifier {
} }
if (displays.isNotEmpty) { if (displays.isNotEmpty) {
_reconnects = 1; _reconnects = 1;
_waitForFirstImage[sessionId] = true; waitForFirstImage.value = true;
} }
Map<String, dynamic> features = json.decode(evt['features']); Map<String, dynamic> features = json.decode(evt['features']);
_pi.features.privacyMode = features['privacy_mode'] == 1; _pi.features.privacyMode = features['privacy_mode'] == 1;
@ -602,6 +610,7 @@ class FfiModel with ChangeNotifier {
} }
} }
_pi.isSet.value = true;
stateGlobal.resetLastResolutionGroupValues(peerId); stateGlobal.resetLastResolutionGroupValues(peerId);
notifyListeners(); notifyListeners();
@ -1814,12 +1823,13 @@ class FFI {
} }
void onEvent2UIRgba() async { void onEvent2UIRgba() async {
if (_waitForImageDialogShow[sessionId] == true) { if (ffiModel.waitForImageDialogShow.isTrue) {
_waitForImageDialogShow[sessionId] = false; ffiModel.waitForImageDialogShow.value = false;
ffiModel.waitForImageTimer?.cancel();
clearWaitingForImage(dialogManager, sessionId); clearWaitingForImage(dialogManager, sessionId);
} }
if (_waitForFirstImage[sessionId] == true) { if (ffiModel.waitForFirstImage.value == true) {
_waitForFirstImage[sessionId] = false; ffiModel.waitForFirstImage.value = false;
dialogManager.dismissAll(); dialogManager.dismissAll();
await canvasModel.updateViewStyle(); await canvasModel.updateViewStyle();
await canvasModel.updateScrollStyle(); await canvasModel.updateScrollStyle();
@ -1934,7 +1944,7 @@ class Features {
bool privacyMode = false; bool privacyMode = false;
} }
class PeerInfo { class PeerInfo with ChangeNotifier {
String version = ''; String version = '';
String username = ''; String username = '';
String hostname = ''; String hostname = '';
@ -1946,6 +1956,8 @@ class PeerInfo {
List<Resolution> resolutions = []; List<Resolution> resolutions = [];
Map<String, dynamic> platform_additions = {}; Map<String, dynamic> platform_additions = {};
RxBool isSet = false.obs;
bool get is_wayland => platform_additions['is_wayland'] == true; bool get is_wayland => platform_additions['is_wayland'] == true;
bool get is_headless => platform_additions['headless'] == true; bool get is_headless => platform_additions['headless'] == true;
} }

View File

@ -57,7 +57,10 @@ use scrap::{
ImageFormat, ImageRgb, ImageFormat, ImageRgb,
}; };
use crate::is_keyboard_mode_supported; use crate::{
common::input::{MOUSE_BUTTON_LEFT, MOUSE_TYPE_DOWN, MOUSE_TYPE_UP},
is_keyboard_mode_supported,
};
#[cfg(not(feature = "flutter"))] #[cfg(not(feature = "flutter"))]
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
@ -2057,13 +2060,20 @@ pub fn send_pointer_device_event(
/// # Arguments /// # Arguments
/// ///
/// * `interface` - The interface for sending data. /// * `interface` - The interface for sending data.
fn activate_os(interface: &impl Interface) { /// * `send_click` - Whether to send a click event.
fn activate_os(interface: &impl Interface, send_click: bool) {
let left_down = MOUSE_BUTTON_LEFT << 3 | MOUSE_TYPE_DOWN;
let left_up = MOUSE_BUTTON_LEFT << 3 | MOUSE_TYPE_UP;
send_mouse(left_up, 0, 0, false, false, false, false, interface);
std::thread::sleep(Duration::from_millis(50));
send_mouse(0, 0, 0, false, false, false, false, interface); send_mouse(0, 0, 0, false, false, false, false, interface);
std::thread::sleep(Duration::from_millis(50)); std::thread::sleep(Duration::from_millis(50));
send_mouse(0, 3, 3, false, false, false, false, interface); send_mouse(0, 3, 3, false, false, false, false, interface);
std::thread::sleep(Duration::from_millis(50)); if send_click {
send_mouse(1 | 1 << 3, 0, 0, false, false, false, false, interface); std::thread::sleep(Duration::from_millis(50));
send_mouse(2 | 1 << 3, 0, 0, false, false, false, false, interface); send_mouse(left_down, 0, 0, false, false, false, false, interface);
send_mouse(left_up, 0, 0, false, false, false, false, interface);
}
/* /*
let mut key_event = KeyEvent::new(); let mut key_event = KeyEvent::new();
// do not use Esc, which has problem with Linux // do not use Esc, which has problem with Linux
@ -2096,10 +2106,15 @@ pub fn input_os_password(p: String, activate: bool, interface: impl Interface) {
/// * `activate` - Whether to activate OS. /// * `activate` - Whether to activate OS.
/// * `interface` - The interface for sending data. /// * `interface` - The interface for sending data.
fn _input_os_password(p: String, activate: bool, interface: impl Interface) { fn _input_os_password(p: String, activate: bool, interface: impl Interface) {
let input_password = !p.is_empty();
if activate { if activate {
activate_os(&interface); // Click event is used to bring up the password input box.
activate_os(&interface, input_password);
std::thread::sleep(Duration::from_millis(1200)); std::thread::sleep(Duration::from_millis(1200));
} }
if !input_password {
return;
}
let mut key_event = KeyEvent::new(); let mut key_event = KeyEvent::new();
key_event.press = true; key_event.press = true;
let mut msg_out = Message::new(); let mut msg_out = Message::new();

View File

@ -25,7 +25,7 @@ use hbb_common::{
protobuf::Enum, protobuf::Enum,
protobuf::Message as _, protobuf::Message as _,
rendezvous_proto::*, rendezvous_proto::*,
sleep, socket_client, socket_client,
tcp::FramedStream, tcp::FramedStream,
tokio, ResultType, tokio, ResultType,
}; };