From 4bd4fba533ea31c773342e279e7ac1c22b39a499 Mon Sep 17 00:00:00 2001 From: sjpark Date: Wed, 8 Feb 2023 21:45:10 +0900 Subject: [PATCH 01/65] allow swap key --- .../desktop/pages/desktop_setting_page.dart | 2 + memo.txt | 104 ++++++++++++++++++ src/flutter.rs | 2 + src/keyboard.rs | 47 ++++++++ src/server/connection.rs | 60 ++++++++++ src/ui/index.tis | 1 + src/ui/remote.rs | 2 + src/ui_session_interface.rs | 10 ++ 8 files changed, 228 insertions(+) create mode 100644 memo.txt diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index 4b6cf2a62..67eb0234b 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -278,6 +278,8 @@ class _GeneralState extends State<_General> { _OptionCheckBox(context, 'Confirm before closing multiple tabs', 'enable-confirm-closing-tabs'), _OptionCheckBox(context, 'Adaptive Bitrate', 'enable-abr'), + if (Platform.isMacOS) + _OptionCheckBox(context, 'Swap control-command key', 'allow-swap-key'), if (Platform.isLinux) Tooltip( message: translate('software_render_tip'), diff --git a/memo.txt b/memo.txt new file mode 100644 index 000000000..da23ae423 --- /dev/null +++ b/memo.txt @@ -0,0 +1,104 @@ +#windows +python3 res/inline-sciter.py +cargo build --release --features inline,with_rc --target=aarch64-pc-windows-msvc -vv + +Push-Location flutter ; flutter pub get ; Pop-Location +~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart + +%comspec% /k "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsamd64_arm64.bat" +rustup update +rustup target add aarch64-pc-windows-msvc +rustup target list + +reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug" /v Auto /t REG_DWORD /d 1 /f +reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\rustdesk.exe" /v Debugger /t REG_SZ /d "vsjitdebugger.exe" /f + +#macos +pushd flutter && flutter pub get && popd +~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart +./build.py --flutter +codesign --force --options runtime -s "Developer ID Application" --deep ./flutter/build/macos/Build/Products/Release/RustDesk.app -v +rm -r /Applications/RustDesk.app +cp -r ./flutter/build/macos/Build/Products/Release/RustDesk.app /Applications/RustDesk.app +open -n /Applications/RustDesk.app --args --server + +cargo bundle --release --features inline +cp libsciter.dylib target/release/bundle/osx/RustDesk.app/Contents/MacOS +mv target/release/bundle/osx/RustDesk.app/Contents/Resources/res/* target/release/bundle/osx/RustDesk.app/Contents/Resources +rm -rf target/release/bundle/osx/RustDesk.app/Contents/Resources/res +target/release/bundle/osx/RustDesk.app/Contents/Info.plist + LSUIElement + 1 + +python3 res/inline-sciter.py +cargo build --release --features inline +cp target/release/rustdesk ../Documents/RustDesk.app/Contents/MacOS/rustdesk +codesign -s "Developer ID Application" --force --options runtime ../Documents/RustDesk.app/Contents/MacOS/* +codesign -s "Developer ID Application" --force --options runtime ../Documents/RustDesk.app +rm -r /Applications/RustDesk.app +cp -r ../Documents/RustDesk.app /Applications/RustDesk.app + +csrutil disable +file target\release\rustdesk +sudo lsof -i -n -P | grep rustdesk // netstat +https://github.com/create-dmg/create-dmg +security find-identity -p basic -v + +#android +BINDGEN_EXTRA_CLANG_ARGS_aarch64_linux_android="--target=arm64-apple-macos --sysroot=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk" RUST_LOG=debug cargo ndk --platform 21 --target aarch64-linux-android rustc --lib --features flutter --release +cp target/aarch64-linux-android/release/liblibrustdesk.so flutter/android/app/src/main/jniLibs/arm64-v8a/librustdesk.so +pushd flutter; flutter build apk --target-platform android-arm64 --release; popd +adb install flutter/build/app/outputs/flutter-apk/app-release.apk + +sudo mount -t drvfs '\\192.168.111.10\Macintosh HD' /mnt/mac +cp target/aarch64-linux-android/debug/liblibrustdesk.so /mnt/mac/Users/sjpark/rustdesk/flutter/android/app/src/main/jniLibs/arm64-v8a/librustdesk.so + +adb logcat | grep LOG_SERVICE +adb emu kill + +sudo apt install build-essential +sudo apt install gcc-multilib + +#ios +flutter/ios/Runnder.xcworkspace/View/Navigators/Project/targets:Runner/Signing & Capability/Teams +cargo build --target aarch64-apple-ios --features flutter --release +pushd flutter; flutter build ios --release; popd +xcode/Window/Devices and Simulators/INSTALLED APPS + +xcrun simctl list +open -a Simulator --args -CurrentDeviceUDID 5D1C39DD-708B-41D3-B89A-3F0D9B8E42BF + +# rustdesk +cd C:\Users\sjpark\Documents\rustdesk +set VCPKG_ROOT=C:\Users\sjpark\Documents\vcpkg +set LIBCLANG_PATH=C:\Program Files\LLVM\bin + +# ring +set path=C:\Program Files\LLVM\bin;C:\Strawberry\perl\bin\;%path%; +.\target\tools\windows\nasm\nasm.exe +set RING_PREGENERATE_ASM=1 + +#dependencies +ring = { git = "https://github.com/sj6219/ring", branch = "0.16.20_alpha" } + + +adb shell dumpsys package com.carriez.flutter_hbb +objdump -T ~/rustdesk/target/aarch64-linux-android/release/liblibrustdesk.so + +cat /Users/sjpark/Library/Android/sdk/ndk/22.0.7026061/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/11.0.5/lib/linux/aarch64/lldb-server | adb shell sh -c 'cat > /data/local/tmp/lldb-server && chmod 755 /data/local/tmp/lldb-server' +adb shell run-as com.carriez.flutter_hbb mkdir -p /data/data/com.carriez.flutter_hbb/lldb/bin/ +adb shell "cat /data/local/tmp/lldb-server | run-as com.carriez.flutter_hbb sh -c 'cat > /data/data/com.carriez.flutter_hbb/lldb/bin/lldb-server && chmod 755 /data/data/com.carriez.flutter_hbb/lldb/bin/lldb-server'" + +adb shell ps -e -o PID -o NAME | grep com.carriez.flutter_hbb +adb forward tcp:10086 tcp:10086 +adb shell run-as com.carriez.flutter_hbb /data/data/com.carriez.flutter_hbb/lldb/bin/lldb-server platform --listen "*:10086" --server + +/Users/sjpark/Library/Android/sdk/ndk/22.0.7026061/toolchains/llvm/prebuilt/darwin-x86_64/bin/lldb +platform select remote-android +platform connect connect://localhost:10086 +attach +b connection.rs:624 + +add-dsym /Users/sjpark/ndk-samples/hello-gl2/app/build/intermediates/merged_native_libs/debug/out/lib/arm64-v8a/libgl2jni.so +b gl_code.cpp:151 + diff --git a/src/flutter.rs b/src/flutter.rs index 2d7d3fb86..bee585d93 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -428,8 +428,10 @@ pub fn session_add( let session_id = get_session_id(id.to_owned()); LocalConfig::set_remote_id(&session_id); + let allow_swap_key = hbb_common::config::Config::get_option("allow-swap-key") == "Y"; let session: Session = Session { id: session_id.clone(), + allow_swap_key, ..Default::default() }; diff --git a/src/keyboard.rs b/src/keyboard.rs index 91480ba30..2764a4408 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -210,6 +210,53 @@ pub fn start_grab_loop() { if key == Key::CapsLock || key == Key::NumLock { return Some(event); } + #[cfg(target_os = "macos")] + let mut event = event; + #[cfg(target_os = "macos")] { + let mut allow_swap_key = false; + #[cfg(not(any(feature = "flutter", feature = "cli")))] + if let Some(session) = CUR_SESSION.lock().unwrap().as_ref() { + allow_swap_key = session.allow_swap_key; + } + #[cfg(feature = "flutter")] + if let Some(session) = SESSIONS + .read() + .unwrap() + .get(&*CUR_SESSION_ID.read().unwrap()) + { + allow_swap_key = session.allow_swap_key; + } + if allow_swap_key { + match event.event_type { + EventType::KeyPress( key) => { + let key = match key { + rdev::Key::ControlLeft => rdev::Key::MetaLeft, + rdev::Key::MetaLeft => rdev::Key::ControlLeft, + rdev::Key::ControlRight => rdev::Key::MetaLeft, + rdev::Key::MetaRight => rdev::Key::ControlLeft, + _ => key, + }; + event.event_type = EventType::KeyPress(key); + event.scan_code = rdev::macos_keycode_from_key(key).unwrap_or_default(); + event.code = event.scan_code as _; + } + EventType::KeyRelease(key) => { + let key = match key { + rdev::Key::ControlLeft => rdev::Key::MetaLeft, + rdev::Key::MetaLeft => rdev::Key::ControlLeft, + rdev::Key::ControlRight => rdev::Key::MetaLeft, + rdev::Key::MetaRight => rdev::Key::ControlLeft, + _ => key, + }; + event.event_type = EventType::KeyRelease(key); + event.scan_code = rdev::macos_keycode_from_key(key).unwrap_or_default(); + event.code = event.scan_code as _; + } + _ => {} + }; + }; + }; + let mut _keyboard_mode = KeyboardMode::Map; let scan_code = event.scan_code; diff --git a/src/server/connection.rs b/src/server/connection.rs index 9ce53c960..17d4e3768 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -539,6 +539,9 @@ impl Connection { #[cfg(not(any(target_os = "android", target_os = "ios")))] fn handle_input(receiver: std_mpsc::Receiver, tx: Sender) { + #[cfg(target_os = "macos")] + let allow_swap_key = hbb_common::config::Config::get_option("allow-swap-key") == "Y"; + let mut block_input_mode = false; #[cfg(target_os = "windows")] { @@ -551,9 +554,66 @@ impl Connection { match receiver.recv_timeout(std::time::Duration::from_millis(500)) { Ok(v) => match v { MessageInput::Mouse((msg, id)) => { + #[cfg(target_os = "macos")] + let msg = { + let mut msg = msg; + if allow_swap_key { + msg.modifiers = msg.modifiers.iter().map(|ck| { + let ck = ck.enum_value_or_default(); + let ck = match ck { + ControlKey::Control => ControlKey::Meta, + ControlKey::Meta => ControlKey::Control, + ControlKey::RControl => ControlKey::Meta, + ControlKey::RWin => ControlKey::Control, + _ => ck, + }; + hbb_common::protobuf::EnumOrUnknown::new(ck) + }).collect(); + } + msg + }; + handle_mouse(&msg, id); } MessageInput::Key((mut msg, press)) => { + #[cfg(target_os = "macos")] + if allow_swap_key { + if let Some(key_event::Union::ControlKey(ck)) = msg.union { + let ck = ck.enum_value_or_default(); + let ck = match ck { + ControlKey::Control => ControlKey::Meta, + ControlKey::Meta => ControlKey::Control, + ControlKey::RControl => ControlKey::Meta, + ControlKey::RWin => ControlKey::Control, + _ => ck, + }; + msg.set_control_key(ck); + } + msg.modifiers = msg.modifiers.iter().map(|ck| { + let ck = ck.enum_value_or_default(); + let ck = match ck { + ControlKey::Control => ControlKey::Meta, + ControlKey::Meta => ControlKey::Control, + ControlKey::RControl => ControlKey::Meta, + ControlKey::RWin => ControlKey::Control, + _ => ck, + }; + hbb_common::protobuf::EnumOrUnknown::new(ck) + }).collect(); + + let code = msg.chr(); + if code != 0 { + let key = rdev::key_from_code(code); + let key = match key { + rdev::Key::ControlLeft => rdev::Key::MetaLeft, + rdev::Key::MetaLeft => rdev::Key::ControlLeft, + rdev::Key::ControlRight => rdev::Key::MetaLeft, + rdev::Key::MetaRight => rdev::Key::ControlLeft, + _ => key, + }; + msg.set_chr(rdev::macos_keycode_from_key(key).unwrap_or_default()); + } + } // todo: press and down have similar meanings. if press && msg.mode.unwrap() == KeyboardMode::Legacy { msg.down = true; diff --git a/src/ui/index.tis b/src/ui/index.tis index ec2e0a748..20228ea03 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -214,6 +214,7 @@ class Enhancements: Reactor.Component { {has_hwcodec ?
  • {svg_checkmark}{translate("Hardware Codec")} (beta)
  • : ""}
  • {svg_checkmark}{translate("Adaptive Bitrate")} (beta)
  • {translate("Recording")}
  • + {is_osx ?
  • {svg_checkmark}{translate("Swap control-command key")}
  • : "" } ; } diff --git a/src/ui/remote.rs b/src/ui/remote.rs index 999b409e0..2d0d4d2c0 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -443,10 +443,12 @@ impl sciter::EventHandler for SciterSession { impl SciterSession { pub fn new(cmd: String, id: String, password: String, args: Vec) -> Self { + let allow_swap_key = hbb_common::config::Config::get_option("allow-swap-key") == "Y"; let session: Session = Session { id: id.clone(), password: password.clone(), args, + allow_swap_key, ..Default::default() }; diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index dc0e365ab..a0c4f06b0 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -36,6 +36,7 @@ pub struct Session { pub sender: Arc>>>, pub thread: Arc>>>, pub ui_handler: T, + pub allow_swap_key: bool, } impl Session { @@ -505,6 +506,15 @@ impl Session { shift: bool, command: bool, ) { + #[cfg(target_os = "macos")] + let (ctrl, command) = + if self.allow_swap_key { + (command, ctrl) + } + else { + (ctrl, command) + }; + #[allow(unused_mut)] let mut command = command; #[cfg(windows)] From 4261e988d2c4e37b2d8452d1ea623aeb81fd9d15 Mon Sep 17 00:00:00 2001 From: sjpark Date: Wed, 8 Feb 2023 21:49:53 +0900 Subject: [PATCH 02/65] delete memo --- memo.txt | 104 ------------------------------------------------------- 1 file changed, 104 deletions(-) delete mode 100644 memo.txt diff --git a/memo.txt b/memo.txt deleted file mode 100644 index da23ae423..000000000 --- a/memo.txt +++ /dev/null @@ -1,104 +0,0 @@ -#windows -python3 res/inline-sciter.py -cargo build --release --features inline,with_rc --target=aarch64-pc-windows-msvc -vv - -Push-Location flutter ; flutter pub get ; Pop-Location -~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart - -%comspec% /k "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsamd64_arm64.bat" -rustup update -rustup target add aarch64-pc-windows-msvc -rustup target list - -reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug" /v Auto /t REG_DWORD /d 1 /f -reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\rustdesk.exe" /v Debugger /t REG_SZ /d "vsjitdebugger.exe" /f - -#macos -pushd flutter && flutter pub get && popd -~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart -./build.py --flutter -codesign --force --options runtime -s "Developer ID Application" --deep ./flutter/build/macos/Build/Products/Release/RustDesk.app -v -rm -r /Applications/RustDesk.app -cp -r ./flutter/build/macos/Build/Products/Release/RustDesk.app /Applications/RustDesk.app -open -n /Applications/RustDesk.app --args --server - -cargo bundle --release --features inline -cp libsciter.dylib target/release/bundle/osx/RustDesk.app/Contents/MacOS -mv target/release/bundle/osx/RustDesk.app/Contents/Resources/res/* target/release/bundle/osx/RustDesk.app/Contents/Resources -rm -rf target/release/bundle/osx/RustDesk.app/Contents/Resources/res -target/release/bundle/osx/RustDesk.app/Contents/Info.plist - LSUIElement - 1 - -python3 res/inline-sciter.py -cargo build --release --features inline -cp target/release/rustdesk ../Documents/RustDesk.app/Contents/MacOS/rustdesk -codesign -s "Developer ID Application" --force --options runtime ../Documents/RustDesk.app/Contents/MacOS/* -codesign -s "Developer ID Application" --force --options runtime ../Documents/RustDesk.app -rm -r /Applications/RustDesk.app -cp -r ../Documents/RustDesk.app /Applications/RustDesk.app - -csrutil disable -file target\release\rustdesk -sudo lsof -i -n -P | grep rustdesk // netstat -https://github.com/create-dmg/create-dmg -security find-identity -p basic -v - -#android -BINDGEN_EXTRA_CLANG_ARGS_aarch64_linux_android="--target=arm64-apple-macos --sysroot=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk" RUST_LOG=debug cargo ndk --platform 21 --target aarch64-linux-android rustc --lib --features flutter --release -cp target/aarch64-linux-android/release/liblibrustdesk.so flutter/android/app/src/main/jniLibs/arm64-v8a/librustdesk.so -pushd flutter; flutter build apk --target-platform android-arm64 --release; popd -adb install flutter/build/app/outputs/flutter-apk/app-release.apk - -sudo mount -t drvfs '\\192.168.111.10\Macintosh HD' /mnt/mac -cp target/aarch64-linux-android/debug/liblibrustdesk.so /mnt/mac/Users/sjpark/rustdesk/flutter/android/app/src/main/jniLibs/arm64-v8a/librustdesk.so - -adb logcat | grep LOG_SERVICE -adb emu kill - -sudo apt install build-essential -sudo apt install gcc-multilib - -#ios -flutter/ios/Runnder.xcworkspace/View/Navigators/Project/targets:Runner/Signing & Capability/Teams -cargo build --target aarch64-apple-ios --features flutter --release -pushd flutter; flutter build ios --release; popd -xcode/Window/Devices and Simulators/INSTALLED APPS - -xcrun simctl list -open -a Simulator --args -CurrentDeviceUDID 5D1C39DD-708B-41D3-B89A-3F0D9B8E42BF - -# rustdesk -cd C:\Users\sjpark\Documents\rustdesk -set VCPKG_ROOT=C:\Users\sjpark\Documents\vcpkg -set LIBCLANG_PATH=C:\Program Files\LLVM\bin - -# ring -set path=C:\Program Files\LLVM\bin;C:\Strawberry\perl\bin\;%path%; -.\target\tools\windows\nasm\nasm.exe -set RING_PREGENERATE_ASM=1 - -#dependencies -ring = { git = "https://github.com/sj6219/ring", branch = "0.16.20_alpha" } - - -adb shell dumpsys package com.carriez.flutter_hbb -objdump -T ~/rustdesk/target/aarch64-linux-android/release/liblibrustdesk.so - -cat /Users/sjpark/Library/Android/sdk/ndk/22.0.7026061/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/11.0.5/lib/linux/aarch64/lldb-server | adb shell sh -c 'cat > /data/local/tmp/lldb-server && chmod 755 /data/local/tmp/lldb-server' -adb shell run-as com.carriez.flutter_hbb mkdir -p /data/data/com.carriez.flutter_hbb/lldb/bin/ -adb shell "cat /data/local/tmp/lldb-server | run-as com.carriez.flutter_hbb sh -c 'cat > /data/data/com.carriez.flutter_hbb/lldb/bin/lldb-server && chmod 755 /data/data/com.carriez.flutter_hbb/lldb/bin/lldb-server'" - -adb shell ps -e -o PID -o NAME | grep com.carriez.flutter_hbb -adb forward tcp:10086 tcp:10086 -adb shell run-as com.carriez.flutter_hbb /data/data/com.carriez.flutter_hbb/lldb/bin/lldb-server platform --listen "*:10086" --server - -/Users/sjpark/Library/Android/sdk/ndk/22.0.7026061/toolchains/llvm/prebuilt/darwin-x86_64/bin/lldb -platform select remote-android -platform connect connect://localhost:10086 -attach -b connection.rs:624 - -add-dsym /Users/sjpark/ndk-samples/hello-gl2/app/build/intermediates/merged_native_libs/debug/out/lib/arm64-v8a/libgl2jni.so -b gl_code.cpp:151 - From edff4acbcbf1d932608765ad1ba1b5998517b10b Mon Sep 17 00:00:00 2001 From: sjpark Date: Thu, 9 Feb 2023 11:54:23 +0900 Subject: [PATCH 03/65] swap key update --- .../desktop/pages/desktop_setting_page.dart | 2 - .../lib/desktop/widgets/remote_menubar.dart | 3 + libs/hbb_common/src/config.rs | 4 ++ src/client.rs | 4 ++ src/flutter.rs | 2 - src/keyboard.rs | 23 ++++--- src/server/connection.rs | 60 ------------------- src/ui/header.tis | 1 + src/ui/index.tis | 1 - src/ui/remote.rs | 2 - src/ui_session_interface.rs | 4 +- 11 files changed, 27 insertions(+), 79 deletions(-) diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index 67eb0234b..4b6cf2a62 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -278,8 +278,6 @@ class _GeneralState extends State<_General> { _OptionCheckBox(context, 'Confirm before closing multiple tabs', 'enable-confirm-closing-tabs'), _OptionCheckBox(context, 'Adaptive Bitrate', 'enable-abr'), - if (Platform.isMacOS) - _OptionCheckBox(context, 'Swap control-command key', 'allow-swap-key'), if (Platform.isLinux) Tooltip( message: translate('software_render_tip'), diff --git a/flutter/lib/desktop/widgets/remote_menubar.dart b/flutter/lib/desktop/widgets/remote_menubar.dart index 6bb49000b..7db7d43aa 100644 --- a/flutter/lib/desktop/widgets/remote_menubar.dart +++ b/flutter/lib/desktop/widgets/remote_menubar.dart @@ -1580,6 +1580,9 @@ class _RemoteMenubarState extends State { ), ); } + keyboardMenu.add(_createSwitchMenuEntry( + 'Swap Control-Command Key', 'allow_swap_key', EdgeInsets.zero, true)); + return keyboardMenu; } diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 1e4d80c9f..8b08e1e21 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -223,6 +223,8 @@ pub struct PeerConfig { pub lock_after_session_end: LockAfterSessionEnd, #[serde(flatten)] pub privacy_mode: PrivacyMode, + #[serde(flatten)] + pub allow_swap_key: AllowSwapKey, #[serde(default)] pub port_forwards: Vec<(i32, String, i32)>, #[serde(default)] @@ -1066,6 +1068,8 @@ serde_field_bool!( ); serde_field_bool!(PrivacyMode, "privacy_mode", default_privacy_mode); +serde_field_bool!(AllowSwapKey, "allow_swap_key", default_swap_key); + #[derive(Debug, Default, Serialize, Deserialize, Clone)] pub struct LocalConfig { #[serde(default)] diff --git a/src/client.rs b/src/client.rs index 020bea1f0..fb255176b 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1121,6 +1121,8 @@ impl LoginConfigHandler { option.block_input = BoolOption::No.into(); } else if name == "show-quality-monitor" { config.show_quality_monitor.v = !config.show_quality_monitor.v; + } else if name == "allow_swap_key" { + config.allow_swap_key.v = !config.allow_swap_key.v; } else { let is_set = self .options @@ -1274,6 +1276,8 @@ impl LoginConfigHandler { self.config.disable_clipboard.v } else if name == "show-quality-monitor" { self.config.show_quality_monitor.v + } else if name == "allow_swap_key" { + self.config.allow_swap_key.v } else { !self.get_option(name).is_empty() } diff --git a/src/flutter.rs b/src/flutter.rs index bee585d93..2d7d3fb86 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -428,10 +428,8 @@ pub fn session_add( let session_id = get_session_id(id.to_owned()); LocalConfig::set_remote_id(&session_id); - let allow_swap_key = hbb_common::config::Config::get_option("allow-swap-key") == "Y"; let session: Session = Session { id: session_id.clone(), - allow_swap_key, ..Default::default() }; diff --git a/src/keyboard.rs b/src/keyboard.rs index 18314dbc7..00a2edd74 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -205,18 +205,16 @@ static mut IS_0X021D_DOWN: bool = false; pub fn start_grab_loop() { #[cfg(any(target_os = "windows", target_os = "macos"))] std::thread::spawn(move || { - let try_handle_keyboard = move |event: Event, key: Key, is_press: bool| -> Option { + let try_handle_keyboard = move |mut event: Event, key: Key, is_press: bool| -> Option { // fix #2211:CAPS LOCK don't work if key == Key::CapsLock || key == Key::NumLock { return Some(event); } - #[cfg(target_os = "macos")] - let mut event = event; - #[cfg(target_os = "macos")] { + { let mut allow_swap_key = false; #[cfg(not(any(feature = "flutter", feature = "cli")))] if let Some(session) = CUR_SESSION.lock().unwrap().as_ref() { - allow_swap_key = session.allow_swap_key; + allow_swap_key = session.get_toggle_option("allow_swap_key".to_string()); } #[cfg(feature = "flutter")] if let Some(session) = SESSIONS @@ -224,7 +222,7 @@ pub fn start_grab_loop() { .unwrap() .get(&*CUR_SESSION_ID.read().unwrap()) { - allow_swap_key = session.allow_swap_key; + allow_swap_key = session.get_toggle_option("allow_swap_key".to_string()); } if allow_swap_key { match event.event_type { @@ -237,7 +235,11 @@ pub fn start_grab_loop() { _ => key, }; event.event_type = EventType::KeyPress(key); - event.scan_code = rdev::macos_keycode_from_key(key).unwrap_or_default(); + #[cfg(target_os = "windows")] + let scan_code = rdev::win_scancode_from_key(key).unwrap_or_default(); + #[cfg(target_os = "macos")] + let scan_code = rdev::macos_keycode_from_key(key).unwrap_or_default(); + event.scan_code = scan_code; event.code = event.scan_code as _; } EventType::KeyRelease(key) => { @@ -249,7 +251,11 @@ pub fn start_grab_loop() { _ => key, }; event.event_type = EventType::KeyRelease(key); - event.scan_code = rdev::macos_keycode_from_key(key).unwrap_or_default(); + #[cfg(target_os = "windows")] + let scan_code = rdev::win_scancode_from_key(key).unwrap_or_default(); + #[cfg(target_os = "macos")] + let scan_code = rdev::macos_keycode_from_key(key).unwrap_or_default(); + event.scan_code = scan_code; event.code = event.scan_code as _; } _ => {} @@ -257,7 +263,6 @@ pub fn start_grab_loop() { }; }; - let mut _keyboard_mode = KeyboardMode::Map; let _scan_code = event.scan_code; let res = if KEYBOARD_HOOKED.load(Ordering::SeqCst) { diff --git a/src/server/connection.rs b/src/server/connection.rs index 17d4e3768..9ce53c960 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -539,9 +539,6 @@ impl Connection { #[cfg(not(any(target_os = "android", target_os = "ios")))] fn handle_input(receiver: std_mpsc::Receiver, tx: Sender) { - #[cfg(target_os = "macos")] - let allow_swap_key = hbb_common::config::Config::get_option("allow-swap-key") == "Y"; - let mut block_input_mode = false; #[cfg(target_os = "windows")] { @@ -554,66 +551,9 @@ impl Connection { match receiver.recv_timeout(std::time::Duration::from_millis(500)) { Ok(v) => match v { MessageInput::Mouse((msg, id)) => { - #[cfg(target_os = "macos")] - let msg = { - let mut msg = msg; - if allow_swap_key { - msg.modifiers = msg.modifiers.iter().map(|ck| { - let ck = ck.enum_value_or_default(); - let ck = match ck { - ControlKey::Control => ControlKey::Meta, - ControlKey::Meta => ControlKey::Control, - ControlKey::RControl => ControlKey::Meta, - ControlKey::RWin => ControlKey::Control, - _ => ck, - }; - hbb_common::protobuf::EnumOrUnknown::new(ck) - }).collect(); - } - msg - }; - handle_mouse(&msg, id); } MessageInput::Key((mut msg, press)) => { - #[cfg(target_os = "macos")] - if allow_swap_key { - if let Some(key_event::Union::ControlKey(ck)) = msg.union { - let ck = ck.enum_value_or_default(); - let ck = match ck { - ControlKey::Control => ControlKey::Meta, - ControlKey::Meta => ControlKey::Control, - ControlKey::RControl => ControlKey::Meta, - ControlKey::RWin => ControlKey::Control, - _ => ck, - }; - msg.set_control_key(ck); - } - msg.modifiers = msg.modifiers.iter().map(|ck| { - let ck = ck.enum_value_or_default(); - let ck = match ck { - ControlKey::Control => ControlKey::Meta, - ControlKey::Meta => ControlKey::Control, - ControlKey::RControl => ControlKey::Meta, - ControlKey::RWin => ControlKey::Control, - _ => ck, - }; - hbb_common::protobuf::EnumOrUnknown::new(ck) - }).collect(); - - let code = msg.chr(); - if code != 0 { - let key = rdev::key_from_code(code); - let key = match key { - rdev::Key::ControlLeft => rdev::Key::MetaLeft, - rdev::Key::MetaLeft => rdev::Key::ControlLeft, - rdev::Key::ControlRight => rdev::Key::MetaLeft, - rdev::Key::MetaRight => rdev::Key::ControlLeft, - _ => key, - }; - msg.set_chr(rdev::macos_keycode_from_key(key).unwrap_or_default()); - } - } // todo: press and down have similar meanings. if press && msg.mode.unwrap() == KeyboardMode::Legacy { msg.down = true; diff --git a/src/ui/header.tis b/src/ui/header.tis index 009995f4f..414edab5a 100644 --- a/src/ui/header.tis +++ b/src/ui/header.tis @@ -156,6 +156,7 @@ class Header: Reactor.Component {
  • {svg_checkmark}{translate('Legacy mode')}
  • {svg_checkmark}{translate('Map mode')}
  • +
  • {svg_checkmark}{translate('Swap Control-Command Key')}
  • ; } diff --git a/src/ui/index.tis b/src/ui/index.tis index 20228ea03..ec2e0a748 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -214,7 +214,6 @@ class Enhancements: Reactor.Component { {has_hwcodec ?
  • {svg_checkmark}{translate("Hardware Codec")} (beta)
  • : ""}
  • {svg_checkmark}{translate("Adaptive Bitrate")} (beta)
  • {translate("Recording")}
  • - {is_osx ?
  • {svg_checkmark}{translate("Swap control-command key")}
  • : "" } ; } diff --git a/src/ui/remote.rs b/src/ui/remote.rs index 2d0d4d2c0..999b409e0 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -443,12 +443,10 @@ impl sciter::EventHandler for SciterSession { impl SciterSession { pub fn new(cmd: String, id: String, password: String, args: Vec) -> Self { - let allow_swap_key = hbb_common::config::Config::get_option("allow-swap-key") == "Y"; let session: Session = Session { id: id.clone(), password: password.clone(), args, - allow_swap_key, ..Default::default() }; diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index f20d1470e..96cd98364 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -36,7 +36,6 @@ pub struct Session { pub sender: Arc>>>, pub thread: Arc>>>, pub ui_handler: T, - pub allow_swap_key: bool, } impl Session { @@ -506,9 +505,8 @@ impl Session { shift: bool, command: bool, ) { - #[cfg(target_os = "macos")] let (ctrl, command) = - if self.allow_swap_key { + if self.get_toggle_option("allow_swap_key".to_string()) { (command, ctrl) } else { From f438dd9fd0b3250417f7ccad9d54768298232320 Mon Sep 17 00:00:00 2001 From: sjpark Date: Thu, 9 Feb 2023 20:28:36 +0900 Subject: [PATCH 04/65] swap_modifier_key() --- src/keyboard.rs | 110 +++++++++++++++++++++++++----------------------- 1 file changed, 57 insertions(+), 53 deletions(-) diff --git a/src/keyboard.rs b/src/keyboard.rs index 00a2edd74..56e11f321 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -202,66 +202,70 @@ pub fn update_grab_get_key_name() { #[cfg(target_os = "windows")] static mut IS_0X021D_DOWN: bool = false; +fn swap_modifier_key(mut event: Event) -> Event { + + let mut allow_swap_key = false; + #[cfg(not(any(feature = "flutter", feature = "cli")))] + if let Some(session) = CUR_SESSION.lock().unwrap().as_ref() { + allow_swap_key = session.get_toggle_option("allow_swap_key".to_string()); + } + #[cfg(feature = "flutter")] + if let Some(session) = SESSIONS + .read() + .unwrap() + .get(&*CUR_SESSION_ID.read().unwrap()) + { + allow_swap_key = session.get_toggle_option("allow_swap_key".to_string()); + } + if allow_swap_key { + match event.event_type { + EventType::KeyPress( key) => { + let key = match key { + rdev::Key::ControlLeft => rdev::Key::MetaLeft, + rdev::Key::MetaLeft => rdev::Key::ControlLeft, + rdev::Key::ControlRight => rdev::Key::MetaLeft, + rdev::Key::MetaRight => rdev::Key::ControlLeft, + _ => key, + }; + event.event_type = EventType::KeyPress(key); + #[cfg(target_os = "windows")] + let scan_code = rdev::win_scancode_from_key(key).unwrap_or_default(); + #[cfg(target_os = "macos")] + let scan_code = rdev::macos_keycode_from_key(key).unwrap_or_default(); + event.scan_code = scan_code; + event.code = event.scan_code as _; + } + EventType::KeyRelease(key) => { + let key = match key { + rdev::Key::ControlLeft => rdev::Key::MetaLeft, + rdev::Key::MetaLeft => rdev::Key::ControlLeft, + rdev::Key::ControlRight => rdev::Key::MetaLeft, + rdev::Key::MetaRight => rdev::Key::ControlLeft, + _ => key, + }; + event.event_type = EventType::KeyRelease(key); + #[cfg(target_os = "windows")] + let scan_code = rdev::win_scancode_from_key(key).unwrap_or_default(); + #[cfg(target_os = "macos")] + let scan_code = rdev::macos_keycode_from_key(key).unwrap_or_default(); + event.scan_code = scan_code; + event.code = event.scan_code as _; + } + _ => {} + }; + } + event +} + pub fn start_grab_loop() { #[cfg(any(target_os = "windows", target_os = "macos"))] std::thread::spawn(move || { - let try_handle_keyboard = move |mut event: Event, key: Key, is_press: bool| -> Option { + let try_handle_keyboard = move |event: Event, key: Key, is_press: bool| -> Option { // fix #2211:CAPS LOCK don't work if key == Key::CapsLock || key == Key::NumLock { return Some(event); } - { - let mut allow_swap_key = false; - #[cfg(not(any(feature = "flutter", feature = "cli")))] - if let Some(session) = CUR_SESSION.lock().unwrap().as_ref() { - allow_swap_key = session.get_toggle_option("allow_swap_key".to_string()); - } - #[cfg(feature = "flutter")] - if let Some(session) = SESSIONS - .read() - .unwrap() - .get(&*CUR_SESSION_ID.read().unwrap()) - { - allow_swap_key = session.get_toggle_option("allow_swap_key".to_string()); - } - if allow_swap_key { - match event.event_type { - EventType::KeyPress( key) => { - let key = match key { - rdev::Key::ControlLeft => rdev::Key::MetaLeft, - rdev::Key::MetaLeft => rdev::Key::ControlLeft, - rdev::Key::ControlRight => rdev::Key::MetaLeft, - rdev::Key::MetaRight => rdev::Key::ControlLeft, - _ => key, - }; - event.event_type = EventType::KeyPress(key); - #[cfg(target_os = "windows")] - let scan_code = rdev::win_scancode_from_key(key).unwrap_or_default(); - #[cfg(target_os = "macos")] - let scan_code = rdev::macos_keycode_from_key(key).unwrap_or_default(); - event.scan_code = scan_code; - event.code = event.scan_code as _; - } - EventType::KeyRelease(key) => { - let key = match key { - rdev::Key::ControlLeft => rdev::Key::MetaLeft, - rdev::Key::MetaLeft => rdev::Key::ControlLeft, - rdev::Key::ControlRight => rdev::Key::MetaLeft, - rdev::Key::MetaRight => rdev::Key::ControlLeft, - _ => key, - }; - event.event_type = EventType::KeyRelease(key); - #[cfg(target_os = "windows")] - let scan_code = rdev::win_scancode_from_key(key).unwrap_or_default(); - #[cfg(target_os = "macos")] - let scan_code = rdev::macos_keycode_from_key(key).unwrap_or_default(); - event.scan_code = scan_code; - event.code = event.scan_code as _; - } - _ => {} - }; - }; - }; + let event = swap_modifier_key(event); let mut _keyboard_mode = KeyboardMode::Map; let _scan_code = event.scan_code; From b29236da062bbba89ba3bdd6afeb70e7039100c0 Mon Sep 17 00:00:00 2001 From: sjpark Date: Sat, 11 Feb 2023 10:41:06 +0900 Subject: [PATCH 05/65] swap key renewal --- Cargo.toml | 5 ++ src/client.rs | 2 + src/keyboard.rs | 58 +------------------- src/ui_session_interface.rs | 103 ++++++++++++++++++++++++++++++++---- 4 files changed, 102 insertions(+), 66 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b315024e9..c171e84e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -167,3 +167,8 @@ panic = 'abort' strip = true #opt-level = 'z' # only have smaller size after strip rpath = true + +[patch."https://github.com/fufesou/rdev"] +#rdev = { path = "../rdev" } +rdev = { git = "https://github.com/sj6219/rdev", branch = "sigma" } + diff --git a/src/client.rs b/src/client.rs index fb255176b..b98f9fde4 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1702,6 +1702,7 @@ pub fn send_mouse( if check_scroll_on_mac(mask, x, y) { mouse_event.modifiers.push(ControlKey::Scroll.into()); } + interface.swap_modifier_mouse(&mut mouse_event); msg_out.set_mouse_event(mouse_event); interface.send(Data::Message(msg_out)); } @@ -1928,6 +1929,7 @@ pub trait Interface: Send + Clone + 'static + Sized { fn is_force_relay(&self) -> bool { self.get_login_config_handler().read().unwrap().force_relay } + fn swap_modifier_mouse(&self, msg : &mut hbb_common::protos::message::MouseEvent) {} } /// Data used by the client interface. diff --git a/src/keyboard.rs b/src/keyboard.rs index 56e11f321..105b84400 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -202,70 +202,14 @@ pub fn update_grab_get_key_name() { #[cfg(target_os = "windows")] static mut IS_0X021D_DOWN: bool = false; -fn swap_modifier_key(mut event: Event) -> Event { - - let mut allow_swap_key = false; - #[cfg(not(any(feature = "flutter", feature = "cli")))] - if let Some(session) = CUR_SESSION.lock().unwrap().as_ref() { - allow_swap_key = session.get_toggle_option("allow_swap_key".to_string()); - } - #[cfg(feature = "flutter")] - if let Some(session) = SESSIONS - .read() - .unwrap() - .get(&*CUR_SESSION_ID.read().unwrap()) - { - allow_swap_key = session.get_toggle_option("allow_swap_key".to_string()); - } - if allow_swap_key { - match event.event_type { - EventType::KeyPress( key) => { - let key = match key { - rdev::Key::ControlLeft => rdev::Key::MetaLeft, - rdev::Key::MetaLeft => rdev::Key::ControlLeft, - rdev::Key::ControlRight => rdev::Key::MetaLeft, - rdev::Key::MetaRight => rdev::Key::ControlLeft, - _ => key, - }; - event.event_type = EventType::KeyPress(key); - #[cfg(target_os = "windows")] - let scan_code = rdev::win_scancode_from_key(key).unwrap_or_default(); - #[cfg(target_os = "macos")] - let scan_code = rdev::macos_keycode_from_key(key).unwrap_or_default(); - event.scan_code = scan_code; - event.code = event.scan_code as _; - } - EventType::KeyRelease(key) => { - let key = match key { - rdev::Key::ControlLeft => rdev::Key::MetaLeft, - rdev::Key::MetaLeft => rdev::Key::ControlLeft, - rdev::Key::ControlRight => rdev::Key::MetaLeft, - rdev::Key::MetaRight => rdev::Key::ControlLeft, - _ => key, - }; - event.event_type = EventType::KeyRelease(key); - #[cfg(target_os = "windows")] - let scan_code = rdev::win_scancode_from_key(key).unwrap_or_default(); - #[cfg(target_os = "macos")] - let scan_code = rdev::macos_keycode_from_key(key).unwrap_or_default(); - event.scan_code = scan_code; - event.code = event.scan_code as _; - } - _ => {} - }; - } - event -} - pub fn start_grab_loop() { #[cfg(any(target_os = "windows", target_os = "macos"))] std::thread::spawn(move || { - let try_handle_keyboard = move |event: Event, key: Key, is_press: bool| -> Option { + let try_handle_keyboard = move |event: Event, key: Key, is_press: bool| -> Option { // fix #2211:CAPS LOCK don't work if key == Key::CapsLock || key == Key::NumLock { return Some(event); } - let event = swap_modifier_key(event); let mut _keyboard_mode = KeyboardMode::Map; let _scan_code = event.scan_code; diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index 96cd98364..d55073b9d 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -335,10 +335,87 @@ impl Session { return "".to_owned(); } + pub fn swab_modifier_key(&self, msg: &mut KeyEvent) { + + let allow_swap_key = self.get_toggle_option("allow_swap_key".to_string()); + if allow_swap_key { + if let Some(key_event::Union::ControlKey(ck)) = msg.union { + let ck = ck.enum_value_or_default(); + let ck = match ck { + ControlKey::Control => ControlKey::Meta, + ControlKey::Meta => ControlKey::Control, + ControlKey::RControl => ControlKey::Meta, + ControlKey::RWin => ControlKey::Control, + _ => ck, + }; + msg.set_control_key(ck); + } + msg.modifiers = msg.modifiers.iter().map(|ck| { + let ck = ck.enum_value_or_default(); + let ck = match ck { + ControlKey::Control => ControlKey::Meta, + ControlKey::Meta => ControlKey::Control, + ControlKey::RControl => ControlKey::Meta, + ControlKey::RWin => ControlKey::Control, + _ => ck, + }; + hbb_common::protobuf::EnumOrUnknown::new(ck) + }).collect(); + + + let code = msg.chr(); + if code != 0 { + let mut peer = self.peer_platform().to_lowercase(); + peer.retain(|c| !c.is_whitespace()); + + let key = match peer.as_str() { + "windows" => { + let key = rdev::win_key_from_code(code); + let key = match key { + rdev::Key::ControlLeft => rdev::Key::MetaLeft, + rdev::Key::MetaLeft => rdev::Key::ControlLeft, + rdev::Key::ControlRight => rdev::Key::MetaLeft, + rdev::Key::MetaRight => rdev::Key::ControlLeft, + _ => key, + }; + rdev::win_keycode_from_key(key).unwrap_or_default() + } + "macos" => { + let key = rdev::macos_key_from_code(code); + let key = match key { + rdev::Key::ControlLeft => rdev::Key::MetaLeft, + rdev::Key::MetaLeft => rdev::Key::ControlLeft, + rdev::Key::ControlRight => rdev::Key::MetaLeft, + rdev::Key::MetaRight => rdev::Key::ControlLeft, + _ => key, + }; + rdev::macos_keycode_from_key(key).unwrap_or_default() + } + _ => { + let key = rdev::linux_key_from_code(code); + let key = match key { + rdev::Key::ControlLeft => rdev::Key::MetaLeft, + rdev::Key::MetaLeft => rdev::Key::ControlLeft, + rdev::Key::ControlRight => rdev::Key::MetaLeft, + rdev::Key::MetaRight => rdev::Key::ControlLeft, + _ => key, + }; + rdev::linux_keycode_from_key(key).unwrap_or_default() + } + }; + msg.set_chr(key); + } + } + + } + pub fn send_key_event(&self, evt: &KeyEvent) { // mode: legacy(0), map(1), translate(2), auto(3) + + let mut msg = evt.clone(); + self.swab_modifier_key(&mut msg); let mut msg_out = Message::new(); - msg_out.set_key_event(evt.clone()); + msg_out.set_key_event(msg); self.send(Data::Message(msg_out)); } @@ -505,14 +582,6 @@ impl Session { shift: bool, command: bool, ) { - let (ctrl, command) = - if self.get_toggle_option("allow_swap_key".to_string()) { - (command, ctrl) - } - else { - (ctrl, command) - }; - #[allow(unused_mut)] let mut command = command; #[cfg(windows)] @@ -851,6 +920,22 @@ impl Interface for Session { handle_test_delay(t, peer).await; } } + fn swap_modifier_mouse(&self, msg : &mut hbb_common::protos::message::MouseEvent) { + let allow_swap_key = self.get_toggle_option("allow_swap_key".to_string()); + if allow_swap_key { + msg.modifiers = msg.modifiers.iter().map(|ck| { + let ck = ck.enum_value_or_default(); + let ck = match ck { + ControlKey::Control => ControlKey::Meta, + ControlKey::Meta => ControlKey::Control, + ControlKey::RControl => ControlKey::Meta, + ControlKey::RWin => ControlKey::Control, + _ => ck, + }; + hbb_common::protobuf::EnumOrUnknown::new(ck) + }).collect(); + }; + } } impl Session { From 7fb78ebc743d0f3449cc2a397b3b80b26a55410f Mon Sep 17 00:00:00 2001 From: sjpark Date: Sun, 12 Feb 2023 06:24:04 +0900 Subject: [PATCH 06/65] bug fix --- src/client.rs | 2 +- src/ui_session_interface.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/client.rs b/src/client.rs index b98f9fde4..78feceb7f 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1929,7 +1929,7 @@ pub trait Interface: Send + Clone + 'static + Sized { fn is_force_relay(&self) -> bool { self.get_login_config_handler().read().unwrap().force_relay } - fn swap_modifier_mouse(&self, msg : &mut hbb_common::protos::message::MouseEvent) {} + fn swap_modifier_mouse(&self, _msg : &mut hbb_common::protos::message::MouseEvent) {} } /// Data used by the client interface. diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index d55073b9d..73f16478a 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -370,7 +370,7 @@ impl Session { let key = match peer.as_str() { "windows" => { - let key = rdev::win_key_from_code(code); + let key = rdev::win_key_from_scancode(code); let key = match key { rdev::Key::ControlLeft => rdev::Key::MetaLeft, rdev::Key::MetaLeft => rdev::Key::ControlLeft, @@ -378,7 +378,7 @@ impl Session { rdev::Key::MetaRight => rdev::Key::ControlLeft, _ => key, }; - rdev::win_keycode_from_key(key).unwrap_or_default() + rdev::win_scancode_from_key(key).unwrap_or_default() } "macos" => { let key = rdev::macos_key_from_code(code); From d76a1adfcce59652e3a17ba2d7dff6536ae9fdfa Mon Sep 17 00:00:00 2001 From: sjpark Date: Sat, 25 Feb 2023 11:41:02 +0900 Subject: [PATCH 07/65] swap key update --- .../lib/desktop/widgets/remote_menubar.dart | 18 ++++++++++++++++++ src/ui/header.tis | 4 ++-- src/ui_session_interface.rs | 1 + 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/flutter/lib/desktop/widgets/remote_menubar.dart b/flutter/lib/desktop/widgets/remote_menubar.dart index 4f9a227bd..329df4e19 100644 --- a/flutter/lib/desktop/widgets/remote_menubar.dart +++ b/flutter/lib/desktop/widgets/remote_menubar.dart @@ -895,6 +895,7 @@ class _DisplayMenuState extends State<_DisplayMenu> { disableClipboard(), lockAfterSessionEnd(), privacyMode(), + swapKey(), ]); } @@ -1501,6 +1502,23 @@ class _DisplayMenuState extends State<_DisplayMenu> { ffi: widget.ffi, child: Text(translate('Privacy mode'))); } + + swapKey() { + final visible = perms['keyboard'] != false && + ((Platform.isMacOS && pi.platform != kPeerPlatformMacOS) || + (!Platform.isMacOS && pi.platform == kPeerPlatformMacOS)); + if (!visible) return Offstage(); + final option = 'allow_swap_key'; + final value = bind.sessionGetToggleOptionSync(id: widget.id, arg: option); + return _CheckboxMenuButton( + value: value, + onChanged: (value) { + if (value == null) return; + bind.sessionToggleOption(id: widget.id, value: option); + }, + ffi: widget.ffi, + child: Text(translate('Swap control-command key'))); + } } class _KeyboardMenu extends StatelessWidget { diff --git a/src/ui/header.tis b/src/ui/header.tis index 01808a156..257ba417e 100644 --- a/src/ui/header.tis +++ b/src/ui/header.tis @@ -156,7 +156,6 @@ class Header: Reactor.Component {
  • {svg_checkmark}{translate('Legacy mode')}
  • {svg_checkmark}{translate('Map mode')}
  • -
  • {svg_checkmark}{translate('Swap Control-Command Key')}
  • ; } @@ -199,6 +198,7 @@ class Header: Reactor.Component { {keyboard_enabled && clipboard_enabled ?
  • {svg_checkmark}{translate('Disable clipboard')}
  • : ""} {keyboard_enabled ?
  • {svg_checkmark}{translate('Lock after session end')}
  • : ""} {keyboard_enabled && pi.platform == "Windows" ?
  • {svg_checkmark}{translate('Privacy mode')}
  • : ""} + {keyboard_enabled && ((is_osx && pi.platform != "Mac OS") || (!is_osx && pi.platform == "Mac OS")) ?
  • {svg_checkmark}{translate('Swap control-command key')}
  • : ""} ; } @@ -441,7 +441,7 @@ function toggleMenuState() { for (var el in $$(menu#keyboard-options>li)) { el.attributes.toggleClass("selected", values.indexOf(el.id) >= 0); } - for (var id in ["show-remote-cursor", "show-quality-monitor", "disable-audio", "enable-file-transfer", "disable-clipboard", "lock-after-session-end"]) { + for (var id in ["show-remote-cursor", "show-quality-monitor", "disable-audio", "enable-file-transfer", "disable-clipboard", "lock-after-session-end", "allow_swap_key"]) { var el = self.select('#' + id); if (el) { var value = handler.get_toggle_option(id); diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index 37367c191..f764aa3ed 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -1010,6 +1010,7 @@ impl Interface for Session { handle_test_delay(t, peer).await; } } + fn swap_modifier_mouse(&self, msg : &mut hbb_common::protos::message::MouseEvent) { let allow_swap_key = self.get_toggle_option("allow_swap_key".to_string()); if allow_swap_key { From b83583769b51a01071ea241704607647e5130872 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Sun, 26 Feb 2023 18:49:07 +0800 Subject: [PATCH 08/65] mount rustdesk rather than vdi/host --- Cargo.toml | 1 + vdi/host/.devcontainer/devcontainer.json | 5 +- vdi/host/Cargo.lock | 970 ++++++++++++++++++++++- vdi/host/Cargo.toml | 4 +- 4 files changed, 972 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f93f776a0..b53615c4e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -132,6 +132,7 @@ flutter_rust_bridge = "1.61.1" [workspace] members = ["libs/scrap", "libs/hbb_common", "libs/enigo", "libs/clipboard", "libs/virtual_display", "libs/virtual_display/dylib", "libs/simple_rc", "libs/portable"] +exclude = ["vdi/host"] [package.metadata.winres] LegalCopyright = "Copyright © 2022 Purslane, Inc." diff --git a/vdi/host/.devcontainer/devcontainer.json b/vdi/host/.devcontainer/devcontainer.json index 02c6e589b..f0016b5b1 100644 --- a/vdi/host/.devcontainer/devcontainer.json +++ b/vdi/host/.devcontainer/devcontainer.json @@ -4,8 +4,8 @@ "dockerfile": "./Dockerfile", "context": "." }, - "workspaceMount": "source=${localWorkspaceFolder},target=/home/vscode/rustdesk,type=bind,consistency=cache", - "workspaceFolder": "/home/vscode/rustdesk", + "workspaceMount": "source=${localWorkspaceFolder}/../..,target=/home/vscode/rustdesk,type=bind,consistency=cache", + "workspaceFolder": "/home/vscode/rustdesk/vdi/host", "customizations": { "vscode": { "extensions": [ @@ -15,6 +15,7 @@ "tamasfe.even-better-toml", "serayuzgur.crates", "mhutchie.git-graph", + "formulahendry.terminal", "eamodio.gitlens" ], "settings": { diff --git a/vdi/host/Cargo.lock b/vdi/host/Cargo.lock index d4254717e..7b7cf26bd 100644 --- a/vdi/host/Cargo.lock +++ b/vdi/host/Cargo.lock @@ -2,6 +2,32 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "0.7.20" @@ -11,6 +37,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" + [[package]] name = "async-broadcast" version = "0.3.4" @@ -73,7 +114,7 @@ dependencies = [ "parking", "polling", "slab", - "socket2", + "socket2 0.4.7", "waker-fn", "windows-sys 0.42.0", ] @@ -116,29 +157,73 @@ dependencies = [ "syn", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + [[package]] name = "byteorder" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +dependencies = [ + "serde", +] + [[package]] name = "cc" version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +dependencies = [ + "jobserver", +] [[package]] name = "cfg-if" @@ -146,6 +231,31 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-integer", + "num-traits", + "time", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + [[package]] name = "concurrent-queue" version = "2.1.0" @@ -155,6 +265,57 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "confy" +version = "0.4.0" +source = "git+https://github.com/open-trade/confy#630cc28a396cb7d01eefdd9f3824486fe4d8554b" +dependencies = [ + "directories-next", + "serde", + "thiserror", + "toml", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "crossbeam-channel" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset 0.7.1", + "scopeguard", +] + [[package]] name = "crossbeam-utils" version = "0.8.14" @@ -164,6 +325,50 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "cxx" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86d3488e7665a7a483b57e25bdd90d0aeb2bc7608c8d0346acf2ad3f1caf1d62" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fcaf066a053a41a81dfb14d57d99738b767febb8b735c3016e469fac5da690" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2ef98b8b717a829ca5603af80e1f9e2e48013ab227b68ef37872ef84ee479bf" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "derivative" version = "2.2.0" @@ -175,6 +380,16 @@ dependencies = [ "syn", ] +[[package]] +name = "directories-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + [[package]] name = "dirs" version = "4.0.0" @@ -184,6 +399,16 @@ dependencies = [ "dirs-sys", ] +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + [[package]] name = "dirs-sys" version = "0.3.7" @@ -195,12 +420,38 @@ dependencies = [ "winapi", ] +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "easy-parallel" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6907e25393cdcc1f4f3f513d9aac1e840eb1cc341a0fccb01171f7d14d10b946" +[[package]] +name = "ed25519" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +dependencies = [ + "signature", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + [[package]] name = "enumflags2" version = "0.7.5" @@ -222,6 +473,19 @@ dependencies = [ "syn", ] +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "event-listener" version = "2.5.3" @@ -237,6 +501,18 @@ dependencies = [ "instant", ] +[[package]] +name = "filetime" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys 0.45.0", +] + [[package]] name = "futures" version = "0.3.26" @@ -349,14 +625,78 @@ checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", ] +[[package]] +name = "gimli" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" + [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "hbb_common" +version = "0.1.0" +dependencies = [ + "anyhow", + "backtrace", + "bytes", + "chrono", + "confy", + "directories-next", + "dirs-next", + "env_logger", + "filetime", + "futures", + "futures-util", + "lazy_static", + "libc", + "log", + "mac_address", + "machine-uid", + "osascript", + "protobuf", + "protobuf-codegen", + "rand", + "regex", + "serde", + "serde_derive", + "socket2 0.3.19", + "sodiumoxide", + "sysinfo", + "tokio", + "tokio-socks", + "tokio-util", + "winapi", + "zstd", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] [[package]] name = "hex" @@ -364,6 +704,36 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "iana-time-zone" +version = "0.1.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + [[package]] name = "indexmap" version = "1.9.2" @@ -383,12 +753,54 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "itoa" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" + +[[package]] +name = "jobserver" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +[[package]] +name = "libsodium-sys" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b779387cd56adfbc02ea4a668e704f729be8d6a6abd2c27ca5ee537849a92fd" +dependencies = [ + "cc", + "libc", + "pkg-config", + "walkdir", +] + [[package]] name = "libusb1-sys" version = "0.6.4" @@ -401,6 +813,15 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "link-cplusplus" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +dependencies = [ + "cc", +] + [[package]] name = "lock_api" version = "0.4.9" @@ -420,6 +841,25 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "mac_address" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b238e3235c8382b7653c6408ed1b08dd379bdb9fdf990fb0bbae3db2cc0ae963" +dependencies = [ + "nix 0.23.2", + "winapi", +] + +[[package]] +name = "machine-uid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f1595709b0a7386bcd56ba34d250d626e5503917d05d32cdccddcd68603e212" +dependencies = [ + "winreg", +] + [[package]] name = "memchr" version = "2.5.0" @@ -435,6 +875,49 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.45.0", +] + +[[package]] +name = "nix" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", + "memoffset 0.6.5", +] + [[package]] name = "nix" version = "0.24.3" @@ -444,7 +927,7 @@ dependencies = [ "bitflags", "cfg-if", "libc", - "memoffset", + "memoffset 0.6.5", ] [[package]] @@ -456,6 +939,53 @@ dependencies = [ "memchr", ] +[[package]] +name = "ntapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" +dependencies = [ + "winapi", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi 0.2.6", + "libc", +] + +[[package]] +name = "object" +version = "0.30.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.17.1" @@ -472,6 +1002,17 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "osascript" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38731fa859ef679f1aec66ca9562165926b442f298467f76f5990f431efe87dc" +dependencies = [ + "serde", + "serde_derive", + "serde_json", +] + [[package]] name = "parking" version = "2.0.0" @@ -501,6 +1042,26 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "pin-project" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pin-project-lite" version = "0.2.9" @@ -558,6 +1119,58 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "protobuf" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55bad9126f378a853655831eb7363b7b01b81d19f8cb1218861086ca4a1a61e" +dependencies = [ + "bytes", + "once_cell", + "protobuf-support", + "thiserror", +] + +[[package]] +name = "protobuf-codegen" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd418ac3c91caa4032d37cb80ff0d44e2ebe637b2fb243b6234bf89cdac4901" +dependencies = [ + "anyhow", + "once_cell", + "protobuf", + "protobuf-parse", + "regex", + "tempfile", + "thiserror", +] + +[[package]] +name = "protobuf-parse" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d39b14605eaa1f6a340aec7f320b34064feb26c93aec35d6a9a2272a8ddfa49" +dependencies = [ + "anyhow", + "indexmap", + "log", + "protobuf", + "protobuf-support", + "tempfile", + "thiserror", + "which", +] + +[[package]] +name = "protobuf-support" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d4d7b8601c814cfb36bcebb79f0e61e45e1e93640cf778837833bbed05c372" +dependencies = [ + "thiserror", +] + [[package]] name = "qemu-display" version = "0.1.0" @@ -588,6 +1201,7 @@ dependencies = [ name = "qemu-rustdesk" version = "0.1.0" dependencies = [ + "hbb_common", "qemu-display", ] @@ -630,6 +1244,28 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rayon" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -686,12 +1322,39 @@ dependencies = [ "libusb1-sys", ] +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + +[[package]] +name = "ryu" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scratch" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" + [[package]] name = "serde" version = "1.0.152" @@ -733,6 +1396,17 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "serde_repr" version = "0.1.10" @@ -759,6 +1433,21 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" + [[package]] name = "slab" version = "0.4.8" @@ -774,6 +1463,17 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +[[package]] +name = "socket2" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +dependencies = [ + "cfg-if", + "libc", + "winapi", +] + [[package]] name = "socket2" version = "0.4.7" @@ -784,6 +1484,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "sodiumoxide" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e26be3acb6c2d9a7aac28482586a7856436af4cfe7100031d219de2d2ecb0028" +dependencies = [ + "ed25519", + "libc", + "libsodium-sys", + "serde", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -801,6 +1513,21 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sysinfo" +version = "0.24.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54cb4ebf3d49308b99e6e9dc95e989e2fdbdc210e4f67c39db0bb89ba927001c" +dependencies = [ + "cfg-if", + "core-foundation-sys", + "libc", + "ntapi", + "once_cell", + "rayon", + "winapi", +] + [[package]] name = "tempfile" version = "3.3.0" @@ -815,6 +1542,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + [[package]] name = "thiserror" version = "1.0.38" @@ -835,6 +1571,91 @@ dependencies = [ "syn", ] +[[package]] +name = "time" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "tokio" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.4.7", + "tokio-macros", + "windows-sys 0.42.0", +] + +[[package]] +name = "tokio-macros" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-socks" +version = "0.5.1-1" +source = "git+https://github.com/open-trade/tokio-socks#7034e79263ce25c348be072808d7601d82cd892d" +dependencies = [ + "bytes", + "either", + "futures-core", + "futures-sink", + "futures-util", + "pin-project", + "thiserror", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-util" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +dependencies = [ + "bytes", + "futures-core", + "futures-io", + "futures-sink", + "futures-util", + "hashbrown", + "pin-project-lite", + "slab", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml_datetime" version = "0.5.1" @@ -900,6 +1721,12 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + [[package]] name = "usbredirhost" version = "0.0.1" @@ -948,18 +1775,95 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "waker-fn" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" + [[package]] name = "wepoll-ffi" version = "0.1.2" @@ -969,6 +1873,17 @@ dependencies = [ "cc", ] +[[package]] +name = "which" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" +dependencies = [ + "either", + "libc", + "once_cell", +] + [[package]] name = "winapi" version = "0.3.9" @@ -985,6 +1900,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -1087,6 +2011,15 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +[[package]] +name = "winreg" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" +dependencies = [ + "winapi", +] + [[package]] name = "xml-rs" version = "0.8.4" @@ -1116,7 +2049,7 @@ dependencies = [ "futures-sink", "futures-util", "hex", - "nix", + "nix 0.24.3", "once_cell", "ordered-stream", "rand", @@ -1157,6 +2090,35 @@ dependencies = [ "zvariant", ] +[[package]] +name = "zstd" +version = "0.9.2+zstd.1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2390ea1bf6c038c39674f22d95f0564725fc06034a47129179810b2fc58caa54" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "4.1.3+zstd.1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e99d81b99fb3c2c2c794e3fe56c305c63d5173a16a46b5850b07c935ffc7db79" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "1.6.2+zstd.1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2daf2f248d9ea44454bfcb2516534e8b8ad2fc91bf818a1885495fc42bc8ac9f" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "zvariant" version = "3.11.0" diff --git a/vdi/host/Cargo.toml b/vdi/host/Cargo.toml index 62c964122..6a67813a2 100644 --- a/vdi/host/Cargo.toml +++ b/vdi/host/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" authors = ["rustdesk "] edition = "2021" - [dependencies] -qemu-display = { git = "https://gitlab.com/marcandre.lureau/qemu-display" } \ No newline at end of file +qemu-display = { git = "https://gitlab.com/marcandre.lureau/qemu-display" } +hbb_common = { path = "../../libs/hbb_common" } From 0a52d64900a8f1f182073eb79affdee4cf6a596c Mon Sep 17 00:00:00 2001 From: fufesou Date: Sun, 26 Feb 2023 23:29:36 +0800 Subject: [PATCH 09/65] print stack Signed-off-by: fufesou --- flutter/lib/models/input_model.dart | 23 ++++++++++++++++++----- flutter/lib/models/model.dart | 4 +++- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/flutter/lib/models/input_model.dart b/flutter/lib/models/input_model.dart index fca73eac7..37c4a39dc 100644 --- a/flutter/lib/models/input_model.dart +++ b/flutter/lib/models/input_model.dart @@ -503,8 +503,21 @@ class InputModel { } x += d.x; y += d.y; + var evtX = 0; + var evtY = 0; + try { + x.round(); + y.round(); + } catch (e) { + debugPrintStack( + label: 'canvasModel.scale value ${canvasModel.scale}, $e'); + return; + } - if (x < d.x || y < d.y || x > (d.x + d.width) || y > (d.y + d.height)) { + if (evtX < d.x || + evtY < d.y || + evtX > (d.x + d.width) || + evtY > (d.y + d.height)) { // If left mouse up, no early return. if (evt['buttons'] != kPrimaryMouseButton || type != 'up') { return; @@ -512,12 +525,12 @@ class InputModel { } if (type != '') { - x = 0; - y = 0; + evtX = 0; + evtY = 0; } - evt['x'] = '${x.round()}'; - evt['y'] = '${y.round()}'; + evt['x'] = '$evtX'; + evt['y'] = '$evtY'; var buttons = ''; switch (evt['buttons']) { case kPrimaryMouseButton: diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index e48d74dac..74cc7f14f 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -803,7 +803,9 @@ class CanvasModel with ChangeNotifier { dyOffset = (y - dh * (y / size.height) - _y).toInt(); } } catch (e) { - // Unhandled Exception: Unsupported operation: Infinity or NaN toInt + debugPrintStack( + label: + '(x,y) ($x,$y), (_x,_y) ($_x,$_y), _scale $_scale, display size (${getDisplayWidth()},${getDisplayHeight()}), size $size, , $e'); return; } From 544e39e11cf5127944bd8d112a453f74cfa7f801 Mon Sep 17 00:00:00 2001 From: fufesou Date: Sun, 26 Feb 2023 23:31:11 +0800 Subject: [PATCH 10/65] fix assign Signed-off-by: fufesou --- flutter/lib/models/input_model.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flutter/lib/models/input_model.dart b/flutter/lib/models/input_model.dart index 37c4a39dc..b91453138 100644 --- a/flutter/lib/models/input_model.dart +++ b/flutter/lib/models/input_model.dart @@ -506,8 +506,8 @@ class InputModel { var evtX = 0; var evtY = 0; try { - x.round(); - y.round(); + evtX = x.round(); + evtY = y.round(); } catch (e) { debugPrintStack( label: 'canvasModel.scale value ${canvasModel.scale}, $e'); From 8073fa2386bb4a407203e4a383c2cd14b48b21f9 Mon Sep 17 00:00:00 2001 From: Mr-Update <37781396+Mr-Update@users.noreply.github.com> Date: Sun, 26 Feb 2023 19:43:24 +0100 Subject: [PATCH 11/65] Update de.rs --- src/lang/de.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lang/de.rs b/src/lang/de.rs index ee28fe0e7..3d95832ec 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -454,8 +454,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Stop voice call", "Sprachanruf beenden"), ("relay_hint_tip", "Wenn eine direkte Verbindung nicht möglich ist, können Sie versuchen, eine Verbindung über einen Relay-Server herzustellen. \nWenn Sie eine Relay-Verbindung beim ersten Versuch herstellen möchten, können Sie das Suffix \"/r\" an die ID anhängen oder die Option \"Immer über Relay-Server verbinden\" auf der Gegenstelle auswählen."), ("Reconnect", "Erneut verbinden"), - ("Codec", ""), - ("Resolution", ""), - ("No transfers in progress", ""), - ].iter().cloned().collect(); + ("Codec", "Codec"), + ("Resolution", "Auflösung"), + ("No transfers in progress", "Keine Übertragungen im Gange"), + ].iter().cloned().collect(); } From 5793c730c8f1f9c5c96786a656db6546435fceeb Mon Sep 17 00:00:00 2001 From: Mr-Update <37781396+Mr-Update@users.noreply.github.com> Date: Sun, 26 Feb 2023 19:48:20 +0100 Subject: [PATCH 12/65] Update README-DE.md --- docs/README-DE.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/README-DE.md b/docs/README-DE.md index 8ee4a51fa..dd2aa8609 100644 --- a/docs/README-DE.md +++ b/docs/README-DE.md @@ -17,9 +17,9 @@ RustDesk ist eine in Rust geschriebene Remote-Desktop-Software, die out of the b ![image](https://user-images.githubusercontent.com/71636191/171661982-430285f0-2e12-4b1d-9957-4a58e375304d.png) -RustDesk heißt jegliche Mitarbeit willkommen. Schau dir [`docs/CONTRIBUTING.md`](CONTRIBUTING.md) an, wenn du Unterstützung beim Start brauchst. +RustDesk heißt jegliche Mitarbeit willkommen. Schau dir [CONTRIBUTING-DE.md](CONTRIBUTING-DE.md) an, wenn du Unterstützung beim Start brauchst. -[**Wie arbeitet RustDesk?**](https://github.com/rustdesk/rustdesk/wiki/How-does-RustDesk-work%3F) +[**FAQ**](https://github.com/rustdesk/rustdesk/wiki/FAQ) [**Programm herunterladen**](https://github.com/rustdesk/rustdesk/releases) @@ -41,6 +41,14 @@ Nachfolgend sind die Server gelistet, die du kostenlos nutzen kannst. Es kann se | USA (Ashburn) | 0x101 Cyber Security | 4 vCPU / 8 GB RAM | | Ukraine (Kiew) | dc.volia (2VM) | 2 vCPU / 4 GB RAM | +## Dev-Container + +[![In Dev-Containern öffnen](https://img.shields.io/static/v1?label=Dev%20Container&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/rustdesk/rustdesk) + +Wenn du VS Code und Docker bereits installiert hast, kannst du auf das Abzeichen oben klicken, um loszulegen. Wenn du darauf klickst, wird VS Code automatisch die Dev-Container-Erweiterung installieren, den Quellcode in ein Container-Volume klonen und einen Dev-Container für die Verwendung aufsetzen. + +Weitere Informationen findest du in [DEVCONTAINER-DE.md](DEVCONTAINER-DE.md). + ## Abhängigkeiten Desktop-Versionen verwenden [Sciter](https://sciter.com/) oder Flutter für die GUI, dieses Tutorial ist nur für Sciter. From c580bc16cc86919157d0e327ca97bc26db27cea5 Mon Sep 17 00:00:00 2001 From: Mr-Update <37781396+Mr-Update@users.noreply.github.com> Date: Sun, 26 Feb 2023 19:48:55 +0100 Subject: [PATCH 13/65] Add files via upload --- docs/CONTRIBUTING-DE.md | 50 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 docs/CONTRIBUTING-DE.md diff --git a/docs/CONTRIBUTING-DE.md b/docs/CONTRIBUTING-DE.md new file mode 100644 index 000000000..6258a9a7a --- /dev/null +++ b/docs/CONTRIBUTING-DE.md @@ -0,0 +1,50 @@ +# Beitrge zu RustDesk + +RustDesk begrt Beitrge von jedem. Hier sind die Richtlinien, wenn Sie uns +helfen mchten: + +## Beitrge + +Beitrge zu RustDesk oder seinen Abhngigkeiten sollten in Form von Pull +Requests auf GitHub erfolgen. Jeder Pull Request wird von einem Hauptakteur +(jemand mit der Erlaubnis, Korrekturen einzubringen) geprft und entweder in den +Hauptbaum eingefgt oder Feedback fr notwendige nderungen gegeben. Alle +Beitrge sollten diesem Format folgen, auch die von Hauptakteuren. + +Wenn Sie an einem Problem arbeiten mchten, melden Sie es bitte zuerst an, indem +Sie auf GitHub erklren, dass Sie daran arbeiten mchten. Damit soll verhindert +werden, dass Beitrge zum gleichen Thema doppelt bearbeitet werden. + +## Checkliste fr Pull Requests + +- Verzweigen Sie sich vom Master-Branch und, falls ntig, wechseln Sie zum + aktuellen Master-Branch, bevor Sie Ihren Pull Request einreichen. Wenn das + Zusammenfhren mit dem Master nicht reibungslos funktioniert, werden Sie + mglicherweise aufgefordert, Ihre nderungen zu berarbeiten. + +- Commits sollten so klein wie mglich sein und gleichzeitig sicherstellen, dass + jeder Commit unabhngig voneinander korrekt ist (d. h., jeder Commit sollte + sich bersetzen lassen und Tests bestehen). + +- Commits sollten von einem "Herkunftszertifikat fr Entwickler" + (https://developercertificate.org) begleitet werden, das besagt, dass Sie (und + ggf. Ihr Arbeitgeber) mit den Bedingungen der [Projektlizenz](../LICENCE) + einverstanden sind. In Git ist dies die Option `-s` fr `git commit`. + +- Wenn Ihr Patch nicht begutachtet wird oder Sie eine bestimmte Person zur + Begutachtung bentigen, knnen Sie einem Gutachter mit @ antworten und um eine + Begutachtung des Pull Requests oder einen Kommentar bitten. Sie knnen auch + per [E-Mail](mailto:info@rustdesk.com) um eine Begutachtung bitten. + +- Fgen Sie Tests hinzu, die sich auf den behobenen Fehler oder die neue + Funktion beziehen. + +Spezifische Git-Anweisungen finden Sie im [GitHub-Workflow](https://github.com/servo/servo/wiki/GitHub-workflow). + +## Verhalten + +https://github.com/rustdesk/rustdesk/blob/master/docs/CODE_OF_CONDUCT.md + +## Kommunikation + +RustDesk-Mitarbeiter arbeiten hufig im [Discord](https://discord.gg/nDceKgxnkV). From d25c8df0501cf60ee2dd5e0699475f220fa9fea1 Mon Sep 17 00:00:00 2001 From: Mr-Update <37781396+Mr-Update@users.noreply.github.com> Date: Sun, 26 Feb 2023 19:49:36 +0100 Subject: [PATCH 14/65] Add files via upload --- docs/DEVCONTAINER-DE.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 docs/DEVCONTAINER-DE.md diff --git a/docs/DEVCONTAINER-DE.md b/docs/DEVCONTAINER-DE.md new file mode 100644 index 000000000..2a0d73f17 --- /dev/null +++ b/docs/DEVCONTAINER-DE.md @@ -0,0 +1,14 @@ + +Nach dem Start von Dev-Container im Docker-Container wird ein Linux-Binrprogramm im Debug-Modus erstellt. + +Derzeit bietet Dev-Container Linux- und Android-Builds sowohl im Debug- als auch im Release-Modus an. + +Nachfolgend finden Sie eine Tabelle mit Befehlen, die im Stammverzeichnis des Projekts ausgefhrt werden mssen, um bestimmte Builds zu erstellen. + +Kommando|Build-Typ|Modus +-|-|-| +`.devcontainer/build.sh --debug linux`|Linux|debug +`.devcontainer/build.sh --release linux`|Linux|release +`.devcontainer/build.sh --debug android`|android-arm64|debug +`.devcontainer/build.sh --release android`|android-arm64|release + From b9b4913ca0d5f402db9a7cb2422f7167603f08ce Mon Sep 17 00:00:00 2001 From: 21pages Date: Sat, 25 Feb 2023 04:55:37 -0800 Subject: [PATCH 15/65] mac admin auth check --- src/platform/macos.mm | 30 ++++++++++++++++++++++++++++++ src/platform/macos.rs | 8 ++++++++ src/ui_interface.rs | 6 +++--- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/platform/macos.mm b/src/platform/macos.mm index 8be0c6db5..ac9a69d04 100644 --- a/src/platform/macos.mm +++ b/src/platform/macos.mm @@ -1,6 +1,9 @@ #import #import #import +#include +#include + // https://github.com/codebytere/node-mac-permissions/blob/main/permissions.mm @@ -35,6 +38,33 @@ extern "C" bool InputMonitoringAuthStatus(bool prompt) { return false; } +extern "C" bool MacCheckAdminAuthorization() { + AuthorizationRef authRef; + OSStatus status; + + status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, + kAuthorizationFlagDefaults, &authRef); + if (status != errAuthorizationSuccess) { + printf("Failed to create AuthorizationRef\n"); + return false; + } + + AuthorizationItem authItem = {kAuthorizationRightExecute, 0, NULL, 0}; + AuthorizationRights authRights = {1, &authItem}; + AuthorizationFlags flags = kAuthorizationFlagDefaults | + kAuthorizationFlagInteractionAllowed | + kAuthorizationFlagPreAuthorize | + kAuthorizationFlagExtendRights; + status = AuthorizationCopyRights(authRef, &authRights, kAuthorizationEmptyEnvironment, flags, NULL); + if (status != errAuthorizationSuccess) { + printf("Failed to authorize\n"); + return false; + } + + AuthorizationFree(authRef, kAuthorizationFlagDefaults); + return true; +} + extern "C" float BackingScaleFactor() { NSScreen* s = [NSScreen mainScreen]; if (s) return [s backingScaleFactor]; diff --git a/src/platform/macos.rs b/src/platform/macos.rs index b663b0f41..5c4c68e2c 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -34,6 +34,7 @@ extern "C" { static kAXTrustedCheckOptionPrompt: CFStringRef; fn AXIsProcessTrustedWithOptions(options: CFDictionaryRef) -> BOOL; fn InputMonitoringAuthStatus(_: BOOL) -> BOOL; + fn MacCheckAdminAuthorization() -> BOOL; fn MacGetModeNum(display: u32, numModes: *mut u32) -> BOOL; fn MacGetModes( display: u32, @@ -665,3 +666,10 @@ pub fn change_resolution(name: &str, width: usize, height: usize) -> ResultType< } Ok(()) } + + +pub fn check_super_user_permission() -> ResultType { + unsafe { + Ok(MacCheckAdminAuthorization() == YES) + } +} diff --git a/src/ui_interface.rs b/src/ui_interface.rs index 62eba25c1..471150f60 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -707,10 +707,10 @@ pub fn is_root() -> bool { pub fn check_super_user_permission() -> bool { #[cfg(feature = "flatpak")] return true; - #[cfg(any(windows, target_os = "linux"))] + #[cfg(any(windows, target_os = "linux", target_os = "macos"))] return crate::platform::check_super_user_permission().unwrap_or(false); - #[cfg(not(any(windows, target_os = "linux")))] - true + #[cfg(not(any(windows, target_os = "linux", target_os = "macos")))] + return true; } #[allow(dead_code)] From e3d704dfdee6712eca17964a74ac3bb1ebe97526 Mon Sep 17 00:00:00 2001 From: 21pages Date: Sat, 25 Feb 2023 21:26:09 +0800 Subject: [PATCH 16/65] ensure same bpp and framerate when get and set for mac --- src/platform/macos.mm | 83 +++++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 34 deletions(-) diff --git a/src/platform/macos.mm b/src/platform/macos.mm index ac9a69d04..3c90981c4 100644 --- a/src/platform/macos.mm +++ b/src/platform/macos.mm @@ -74,6 +74,33 @@ extern "C" float BackingScaleFactor() { // https://github.com/jhford/screenresolution/blob/master/cg_utils.c // https://github.com/jdoupe/screenres/blob/master/setgetscreen.m +size_t bitDepth(CGDisplayModeRef mode) { + size_t depth = 0; + // Deprecated, same display same bpp? + // https://stackoverflow.com/questions/8210824/how-to-avoid-cgdisplaymodecopypixelencoding-to-get-bpp + // https://github.com/libsdl-org/SDL/pull/6628 + CFStringRef pixelEncoding = CGDisplayModeCopyPixelEncoding(mode); + // my numerical representation for kIO16BitFloatPixels and kIO32bitFloatPixels + // are made up and possibly non-sensical + if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(kIO32BitFloatPixels), kCFCompareCaseInsensitive)) { + depth = 96; + } else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(kIO64BitDirectPixels), kCFCompareCaseInsensitive)) { + depth = 64; + } else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(kIO16BitFloatPixels), kCFCompareCaseInsensitive)) { + depth = 48; + } else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive)) { + depth = 32; + } else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(kIO30BitDirectPixels), kCFCompareCaseInsensitive)) { + depth = 30; + } else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive)) { + depth = 16; + } else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive)) { + depth = 8; + } + CFRelease(pixelEncoding); + return depth; +} + extern "C" bool MacGetModeNum(CGDirectDisplayID display, uint32_t *numModes) { CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL); if (allModes == NULL) { @@ -85,16 +112,28 @@ extern "C" bool MacGetModeNum(CGDirectDisplayID display, uint32_t *numModes) { } extern "C" bool MacGetModes(CGDirectDisplayID display, uint32_t *widths, uint32_t *heights, uint32_t max, uint32_t *numModes) { - CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL); - if (allModes == NULL) { + CGDisplayModeRef currentMode = CGDisplayCopyDisplayMode(display); + if (currentMode == NULL) { return false; } - *numModes = CFArrayGetCount(allModes); - for (uint32_t i = 0; i < *numModes && i < max; i++) { - CGDisplayModeRef mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i); - widths[i] = (uint32_t)CGDisplayModeGetWidth(mode); - heights[i] = (uint32_t)CGDisplayModeGetHeight(mode); + CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL); + if (allModes == NULL) { + CGDisplayModeRelease(currentMode); + return false; } + uint32_t allModeCount = CFArrayGetCount(allModes); + uint32_t realNum = 0; + for (uint32_t i = 0; i < allModeCount && realNum < max; i++) { + CGDisplayModeRef mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i); + if (CGDisplayModeGetRefreshRate(currentMode) == CGDisplayModeGetRefreshRate(mode) && + bitDepth(currentMode) == bitDepth(mode)) { + widths[realNum] = (uint32_t)CGDisplayModeGetWidth(mode); + heights[realNum] = (uint32_t)CGDisplayModeGetHeight(mode); + realNum++; + } + } + *numModes = realNum; + CGDisplayModeRelease(currentMode); CFRelease(allModes); return true; } @@ -110,31 +149,8 @@ extern "C" bool MacGetMode(CGDirectDisplayID display, uint32_t *width, uint32_t return true; } -size_t bitDepth(CGDisplayModeRef mode) { - size_t depth = 0; - CFStringRef pixelEncoding = CGDisplayModeCopyPixelEncoding(mode); - // my numerical representation for kIO16BitFloatPixels and kIO32bitFloatPixels - // are made up and possibly non-sensical - if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(kIO32BitFloatPixels), kCFCompareCaseInsensitive)) { - depth = 96; - } else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(kIO64BitDirectPixels), kCFCompareCaseInsensitive)) { - depth = 64; - } else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(kIO16BitFloatPixels), kCFCompareCaseInsensitive)) { - depth = 48; - } else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive)) { - depth = 32; - } else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(kIO30BitDirectPixels), kCFCompareCaseInsensitive)) { - depth = 30; - } else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive)) { - depth = 16; - } else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive)) { - depth = 8; - } - CFRelease(pixelEncoding); - return depth; -} -bool setDisplayToMode(CGDirectDisplayID display, CGDisplayModeRef mode) { +static bool setDisplayToMode(CGDirectDisplayID display, CGDisplayModeRef mode) { CGError rc; CGDisplayConfigRef config; rc = CGBeginDisplayConfiguration(&config); @@ -152,7 +168,6 @@ bool setDisplayToMode(CGDirectDisplayID display, CGDisplayModeRef mode) { return true; } - extern "C" bool MacSetMode(CGDirectDisplayID display, uint32_t width, uint32_t height) { bool ret = false; @@ -170,8 +185,8 @@ extern "C" bool MacSetMode(CGDirectDisplayID display, uint32_t width, uint32_t h CGDisplayModeRef mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i); if (width == CGDisplayModeGetWidth(mode) && height == CGDisplayModeGetHeight(mode) && - bitDepth(currentMode) == bitDepth(mode) && - CGDisplayModeGetRefreshRate(currentMode) == CGDisplayModeGetRefreshRate(mode)) { + CGDisplayModeGetRefreshRate(currentMode) == CGDisplayModeGetRefreshRate(mode) && + bitDepth(currentMode) == bitDepth(mode)) { ret = setDisplayToMode(display, mode); break; } From b6c3c74286e74b79e1eb688d4f44035f70dbf6a1 Mon Sep 17 00:00:00 2001 From: Kingtous Date: Mon, 27 Feb 2023 12:01:22 +0800 Subject: [PATCH 17/65] opt: move the resize area out of the flutter view --- flutter/lib/consts.dart | 7 +++++++ flutter/lib/desktop/pages/port_forward_tab_page.dart | 12 +++++++----- flutter/lib/desktop/pages/remote_tab_page.dart | 2 ++ .../lib/desktop/screen/desktop_remote_screen.dart | 5 +++++ flutter/lib/desktop/widgets/tabbar_widget.dart | 7 +++++++ flutter/lib/models/state_model.dart | 11 +++++++++++ flutter/pubspec.yaml | 4 ++-- 7 files changed, 41 insertions(+), 7 deletions(-) diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index 537784918..789517bf7 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_hbb/common.dart'; +import 'package:flutter_hbb/models/state_model.dart'; const double kDesktopRemoteTabBarHeight = 28.0; const int kMainWindowId = 0; @@ -58,6 +59,11 @@ const double kDesktopFileTransferMaximumWidth = 300; const double kDesktopFileTransferRowHeight = 30.0; const double kDesktopFileTransferHeaderHeight = 25.0; +EdgeInsets get kDragToResizeAreaPadding => Platform.isLinux + ? stateGlobal.fullscreen || stateGlobal.maximize + ? EdgeInsets.zero + : EdgeInsets.all(4.0) + : EdgeInsets.zero; // https://en.wikipedia.org/wiki/Non-breaking_space const int $nbsp = 0x00A0; @@ -79,6 +85,7 @@ const kDefaultScrollAmountMultiplier = 5.0; const kDefaultScrollDuration = Duration(milliseconds: 50); const kDefaultMouseWheelThrottleDuration = Duration(milliseconds: 50); const kFullScreenEdgeSize = 0.0; +const kMaximizeEdgeSize = 0.0; var kWindowEdgeSize = Platform.isWindows ? 1.0 : 5.0; const kWindowBorderWidth = 1.0; const kDesktopMenuPadding = EdgeInsets.only(left: 12.0, right: 3.0); diff --git a/flutter/lib/desktop/pages/port_forward_tab_page.dart b/flutter/lib/desktop/pages/port_forward_tab_page.dart index f2d75d00f..394d89e38 100644 --- a/flutter/lib/desktop/pages/port_forward_tab_page.dart +++ b/flutter/lib/desktop/pages/port_forward_tab_page.dart @@ -109,11 +109,13 @@ class _PortForwardTabPageState extends State { ); return Platform.isMacOS ? tabWidget - : SubWindowDragToResizeArea( - child: tabWidget, - resizeEdgeSize: stateGlobal.resizeEdgeSize.value, - windowId: stateGlobal.windowId, - ); + : Obx( + () => SubWindowDragToResizeArea( + child: tabWidget, + resizeEdgeSize: stateGlobal.resizeEdgeSize.value, + windowId: stateGlobal.windowId, + ), + ); } void onRemoveId(String id) { diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index 0deb646c0..e7aed0358 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -210,6 +210,8 @@ class _ConnectionTabPageState extends State { : Obx(() => SubWindowDragToResizeArea( key: contentKey, child: tabWidget, + // Specially configured for a better resize area and remote control. + childPadding: kDragToResizeAreaPadding, resizeEdgeSize: stateGlobal.resizeEdgeSize.value, windowId: stateGlobal.windowId, )); diff --git a/flutter/lib/desktop/screen/desktop_remote_screen.dart b/flutter/lib/desktop/screen/desktop_remote_screen.dart index bb6bc431b..64af41401 100644 --- a/flutter/lib/desktop/screen/desktop_remote_screen.dart +++ b/flutter/lib/desktop/screen/desktop_remote_screen.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/desktop/pages/remote_tab_page.dart'; @@ -26,6 +28,9 @@ class DesktopRemoteScreen extends StatelessWidget { ChangeNotifierProvider.value(value: gFFI.canvasModel), ], child: Scaffold( + // Set transparent background for padding the resize area out of the flutter view. + // This allows the wallpaper goes through our resize area. (Linux only now). + backgroundColor: Platform.isLinux ? Colors.transparent : null, body: ConnectionTabPage( params: params, ), diff --git a/flutter/lib/desktop/widgets/tabbar_widget.dart b/flutter/lib/desktop/widgets/tabbar_widget.dart index ee3aaaf2c..958c4c035 100644 --- a/flutter/lib/desktop/widgets/tabbar_widget.dart +++ b/flutter/lib/desktop/widgets/tabbar_widget.dart @@ -523,12 +523,18 @@ class WindowActionPanelState extends State super.dispose(); } + void _setMaximize(bool maximize) { + stateGlobal.setMaximize(maximize); + setState(() {}); + } + @override void onWindowMaximize() { // catch maximize from system if (!widget.isMaximized.value) { widget.isMaximized.value = true; } + _setMaximize(true); super.onWindowMaximize(); } @@ -538,6 +544,7 @@ class WindowActionPanelState extends State if (widget.isMaximized.value) { widget.isMaximized.value = false; } + _setMaximize(false); super.onWindowUnmaximize(); } diff --git a/flutter/lib/models/state_model.dart b/flutter/lib/models/state_model.dart index 761c95ded..7de258a39 100644 --- a/flutter/lib/models/state_model.dart +++ b/flutter/lib/models/state_model.dart @@ -9,8 +9,10 @@ import '../consts.dart'; class StateGlobal { int _windowId = -1; bool _fullscreen = false; + bool _maximize = false; bool grabKeyboard = false; final RxBool _showTabBar = true.obs; + final RxBool _showResizeEdge = true.obs; final RxDouble _resizeEdgeSize = RxDouble(kWindowEdgeSize); final RxDouble _windowBorderWidth = RxDouble(kWindowBorderWidth); final RxBool showRemoteMenuBar = false.obs; @@ -18,12 +20,21 @@ class StateGlobal { int get windowId => _windowId; bool get fullscreen => _fullscreen; + bool get maximize => _maximize; double get tabBarHeight => fullscreen ? 0 : kDesktopRemoteTabBarHeight; RxBool get showTabBar => _showTabBar; RxDouble get resizeEdgeSize => _resizeEdgeSize; RxDouble get windowBorderWidth => _windowBorderWidth; setWindowId(int id) => _windowId = id; + setMaximize(bool v) { + if (_maximize != v) { + print("set maximize"); + _maximize = v; + _resizeEdgeSize.value = + _maximize ? kMaximizeEdgeSize : kWindowEdgeSize; + } + } setFullscreen(bool v) { if (_fullscreen != v) { _fullscreen = v; diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index 572b3e20a..b10dd1ec0 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -59,7 +59,7 @@ dependencies: desktop_multi_window: git: url: https://github.com/Kingtous/rustdesk_desktop_multi_window - ref: f37357ed98a10717576eb9ed8413e92b2ec5d13a + ref: c717159ea8fc0b9c6b4ac50110efc1dfd3c1ba7a freezed_annotation: ^2.0.3 flutter_custom_cursor: ^0.0.4 window_size: @@ -76,7 +76,7 @@ dependencies: file_picker: ^5.1.0 flutter_svg: ^1.1.5 flutter_improved_scrolling: - # currently, we use flutter 3.0.5 for windows build, latest for other builds. + # currently, we use flutter 3.7.0+. # # for flutter 3.0.5, please use official version(just comment code below). # if build rustdesk by flutter >=3.3, please use our custom pub below (uncomment code below). From cb4b658e483c50c0028f0675eedff5bf40703a81 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 27 Feb 2023 14:24:15 +0800 Subject: [PATCH 18/65] Avoid dividing by 0 and setting scale to 0 Signed-off-by: fufesou --- flutter/lib/models/model.dart | 38 ++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 74cc7f14f..21949705f 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -617,13 +617,28 @@ class ViewStyle { final int displayWidth; final int displayHeight; ViewStyle({ - this.style = '', - this.width = 0.0, - this.height = 0.0, - this.displayWidth = 0, - this.displayHeight = 0, + required this.style, + required this.width, + required this.height, + required this.displayWidth, + required this.displayHeight, }); + static defaultViewStyle() { + final desktop = (isDesktop || isWebDesktop); + final w = + desktop ? kDesktopDefaultDisplayWidth : kMobileDefaultDisplayWidth; + final h = + desktop ? kDesktopDefaultDisplayHeight : kMobileDefaultDisplayHeight; + return ViewStyle( + style: '', + width: w.toDouble(), + height: h.toDouble(), + displayWidth: w, + displayHeight: h, + ); + } + static int _double2Int(double v) => (v * 100).round().toInt(); @override @@ -652,9 +667,14 @@ class ViewStyle { double get scale { double s = 1.0; if (style == kRemoteViewStyleAdaptive) { - final s1 = width / displayWidth; - final s2 = height / displayHeight; - s = s1 < s2 ? s1 : s2; + if (width != 0 && + height != 0 && + displayWidth != 0 && + displayHeight != 0) { + final s1 = width / displayWidth; + final s2 = height / displayHeight; + s = s1 < s2 ? s1 : s2; + } } return s; } @@ -680,7 +700,7 @@ class CanvasModel with ChangeNotifier { // scroll offset y percent double _scrollY = 0.0; ScrollStyle _scrollStyle = ScrollStyle.scrollauto; - ViewStyle _lastViewStyle = ViewStyle(); + ViewStyle _lastViewStyle = ViewStyle.defaultViewStyle(); final _imageOverflow = false.obs; From 6e6fc64f629c6b1a9067a7f16645451cd11f1073 Mon Sep 17 00:00:00 2001 From: Kingtous Date: Mon, 27 Feb 2023 15:56:09 +0800 Subject: [PATCH 19/65] opt: add resize area into the compatible ui mode --- flutter/lib/consts.dart | 2 +- flutter/lib/desktop/pages/desktop_tab_page.dart | 2 +- flutter/lib/desktop/pages/file_manager_tab_page.dart | 2 +- flutter/lib/desktop/pages/port_forward_tab_page.dart | 2 +- flutter/lib/desktop/pages/remote_tab_page.dart | 2 +- flutter/lib/models/state_model.dart | 1 - flutter/pubspec.yaml | 2 +- 7 files changed, 6 insertions(+), 7 deletions(-) diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index 789517bf7..b43f3e7da 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -59,7 +59,7 @@ const double kDesktopFileTransferMaximumWidth = 300; const double kDesktopFileTransferRowHeight = 30.0; const double kDesktopFileTransferHeaderHeight = 25.0; -EdgeInsets get kDragToResizeAreaPadding => Platform.isLinux +EdgeInsets get kDragToResizeAreaPadding => !kUseCompatibleUiMode && Platform.isLinux ? stateGlobal.fullscreen || stateGlobal.maximize ? EdgeInsets.zero : EdgeInsets.all(4.0) diff --git a/flutter/lib/desktop/pages/desktop_tab_page.dart b/flutter/lib/desktop/pages/desktop_tab_page.dart index 053a2d8a2..4a1a40242 100644 --- a/flutter/lib/desktop/pages/desktop_tab_page.dart +++ b/flutter/lib/desktop/pages/desktop_tab_page.dart @@ -75,7 +75,7 @@ class _DesktopTabPageState extends State { isClose: false, ), ))); - return Platform.isMacOS + return Platform.isMacOS || kUseCompatibleUiMode ? tabWidget : Obx( () => DragToResizeArea( diff --git a/flutter/lib/desktop/pages/file_manager_tab_page.dart b/flutter/lib/desktop/pages/file_manager_tab_page.dart index 148d928d9..39958e88e 100644 --- a/flutter/lib/desktop/pages/file_manager_tab_page.dart +++ b/flutter/lib/desktop/pages/file_manager_tab_page.dart @@ -98,7 +98,7 @@ class _FileManagerTabPageState extends State { labelGetter: DesktopTab.labelGetterAlias, )), ); - return Platform.isMacOS + return Platform.isMacOS || kUseCompatibleUiMode ? tabWidget : SubWindowDragToResizeArea( child: tabWidget, diff --git a/flutter/lib/desktop/pages/port_forward_tab_page.dart b/flutter/lib/desktop/pages/port_forward_tab_page.dart index 394d89e38..32f02c9b7 100644 --- a/flutter/lib/desktop/pages/port_forward_tab_page.dart +++ b/flutter/lib/desktop/pages/port_forward_tab_page.dart @@ -107,7 +107,7 @@ class _PortForwardTabPageState extends State { labelGetter: DesktopTab.labelGetterAlias, )), ); - return Platform.isMacOS + return Platform.isMacOS || kUseCompatibleUiMode ? tabWidget : Obx( () => SubWindowDragToResizeArea( diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index e7aed0358..d810650fd 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -205,7 +205,7 @@ class _ConnectionTabPageState extends State { ), ), ); - return Platform.isMacOS + return Platform.isMacOS || kUseCompatibleUiMode ? tabWidget : Obx(() => SubWindowDragToResizeArea( key: contentKey, diff --git a/flutter/lib/models/state_model.dart b/flutter/lib/models/state_model.dart index 7de258a39..aa4fab86e 100644 --- a/flutter/lib/models/state_model.dart +++ b/flutter/lib/models/state_model.dart @@ -29,7 +29,6 @@ class StateGlobal { setWindowId(int id) => _windowId = id; setMaximize(bool v) { if (_maximize != v) { - print("set maximize"); _maximize = v; _resizeEdgeSize.value = _maximize ? kMaximizeEdgeSize : kWindowEdgeSize; diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index b10dd1ec0..8d390d370 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -59,7 +59,7 @@ dependencies: desktop_multi_window: git: url: https://github.com/Kingtous/rustdesk_desktop_multi_window - ref: c717159ea8fc0b9c6b4ac50110efc1dfd3c1ba7a + ref: e383fffb5c4529c9e0a710f1025a0c590b99ee08 freezed_annotation: ^2.0.3 flutter_custom_cursor: ^0.0.4 window_size: From 920fa6dac7c2d9aa6b709398a3f7cb10c65fcd7f Mon Sep 17 00:00:00 2001 From: Kingtous Date: Mon, 27 Feb 2023 16:53:13 +0800 Subject: [PATCH 20/65] opt: resize padding set to 5.0 --- flutter/lib/consts.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index b43f3e7da..3c414cd85 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -62,7 +62,7 @@ const double kDesktopFileTransferHeaderHeight = 25.0; EdgeInsets get kDragToResizeAreaPadding => !kUseCompatibleUiMode && Platform.isLinux ? stateGlobal.fullscreen || stateGlobal.maximize ? EdgeInsets.zero - : EdgeInsets.all(4.0) + : EdgeInsets.all(5.0) : EdgeInsets.zero; // https://en.wikipedia.org/wiki/Non-breaking_space const int $nbsp = 0x00A0; From 2f7e758c751538e3caf025081b230ed2b49ee60a Mon Sep 17 00:00:00 2001 From: FastAct <93490087+FastAct@users.noreply.github.com> Date: Mon, 27 Feb 2023 09:56:56 +0100 Subject: [PATCH 21/65] Update nl.rs corrected error --- src/lang/nl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/nl.rs b/src/lang/nl.rs index eb7c214ab..f38c14791 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -444,7 +444,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Default View Style", "Standaard Weergave Stijl"), ("Default Scroll Style", "Standaard Scroll Stijl"), ("Default Image Quality", "Standaard Beeldkwaliteit"), - ("Default Codec", "tandaard Codec"), + ("Default Codec", "Standaard Codec"), ("Bitrate", "Bitrate"), ("FPS", "FPS"), ("Auto", "Auto"), From 6971f45fd0734b4e56d416d9ee0bba49eabb5334 Mon Sep 17 00:00:00 2001 From: 21pages Date: Mon, 27 Feb 2023 17:54:18 +0800 Subject: [PATCH 22/65] dark theme install page Signed-off-by: 21pages --- flutter/lib/desktop/pages/install_page.dart | 20 ++++++++++---------- flutter/lib/main.dart | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/flutter/lib/desktop/pages/install_page.dart b/flutter/lib/desktop/pages/install_page.dart index e7bb28813..d7202e300 100644 --- a/flutter/lib/desktop/pages/install_page.dart +++ b/flutter/lib/desktop/pages/install_page.dart @@ -46,15 +46,19 @@ class _InstallPageState extends State with WindowListener { final double em = 13; final btnFontSize = 0.9 * em; final double button_radius = 6; + final isDarkTheme = MyTheme.currentThemeMode() == ThemeMode.dark; final buttonStyle = OutlinedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(button_radius)), )); final inputBorder = OutlineInputBorder( borderRadius: BorderRadius.zero, - borderSide: BorderSide(color: Colors.black12)); + borderSide: + BorderSide(color: isDarkTheme ? Colors.white70 : Colors.black12)); + final textColor = isDarkTheme ? null : Colors.black87; + final dividerColor = isDarkTheme ? Colors.white70 : Colors.black87; return Scaffold( - backgroundColor: Colors.white, + backgroundColor: null, body: SingleChildScrollView( child: Column( children: [ @@ -91,8 +95,7 @@ class _InstallPageState extends State with WindowListener { style: buttonStyle, child: Text(translate('Change Path'), style: TextStyle( - color: Colors.black87, - fontSize: btnFontSize))) + color: textColor, fontSize: btnFontSize))) .marginOnly(left: em)) ], ).marginSymmetric(vertical: 2 * em), @@ -127,8 +130,7 @@ class _InstallPageState extends State with WindowListener { )).marginOnly(top: 2 * em), Row(children: [Text(translate('agreement_tip'))]) .marginOnly(top: em), - Divider(color: Colors.black87) - .marginSymmetric(vertical: 0.5 * em), + Divider(color: dividerColor).marginSymmetric(vertical: 0.5 * em), Row( children: [ Expanded( @@ -143,8 +145,7 @@ class _InstallPageState extends State with WindowListener { style: buttonStyle, child: Text(translate('Cancel'), style: TextStyle( - color: Colors.black87, - fontSize: btnFontSize))) + color: textColor, fontSize: btnFontSize))) .marginOnly(right: 2 * em)), Obx(() => ElevatedButton( onPressed: btnEnabled.value ? install : null, @@ -167,8 +168,7 @@ class _InstallPageState extends State with WindowListener { style: buttonStyle, child: Text(translate('Run without install'), style: TextStyle( - color: Colors.black87, - fontSize: btnFontSize))) + color: textColor, fontSize: btnFontSize))) .marginOnly(left: 2 * em)), ), ], diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index c61287d4f..baf7193b3 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -291,7 +291,7 @@ void _runApp( void runInstallPage() async { await windowManager.ensureInitialized(); await initEnv(kAppTypeMain); - _runApp('', const InstallPage(), ThemeMode.light); + _runApp('', const InstallPage(), MyTheme.currentThemeMode()); windowManager.waitUntilReadyToShow( WindowOptions(size: Size(800, 600), center: true), () async { windowManager.show(); From 2678c503a01aaac28936a6128019c72e77e578ca Mon Sep 17 00:00:00 2001 From: rustdesk Date: Mon, 27 Feb 2023 20:28:55 +0800 Subject: [PATCH 23/65] chore: fix recursive os.system on my m1 in build.py, and modify windows subsystem macro --- build.py | 184 ++++++++++++++++++++++++---------------------------- src/main.rs | 7 +- 2 files changed, 90 insertions(+), 101 deletions(-) diff --git a/build.py b/build.py index 727b53fe0..b30f76f95 100755 --- a/build.py +++ b/build.py @@ -18,14 +18,11 @@ exe_path = 'target/release/' + hbb_name flutter_win_target_dir = 'flutter/build/windows/runner/Release/' skip_cargo = False -def custom_os_system(cmd): - err = os._system(cmd) +def system2(cmd): + err = os.system(cmd) if err != 0: print(f"Error occurred when executing: {cmd}. Exiting.") sys.exit(-1) -# replace prebuilt os.system -os._system = os.system -os.system = custom_os_system def get_version(): with open("Cargo.toml", encoding="utf-8") as fh: @@ -144,8 +141,8 @@ def generate_build_script_for_docker(): # build rustdesk ./build.py --flutter --hwcodec ''') - os.system("chmod +x /tmp/build.sh") - os.system("bash /tmp/build.sh") + system2("chmod +x /tmp/build.sh") + system2("bash /tmp/build.sh") def download_extract_features(features, res_dir): @@ -250,7 +247,7 @@ def get_features(args): def generate_control_file(version): control_file_path = "../res/DEBIAN/control" - os.system('/bin/rm -rf %s' % control_file_path) + system2('/bin/rm -rf %s' % control_file_path) content = """Package: rustdesk Version: %s @@ -268,45 +265,45 @@ Description: A remote control software. def ffi_bindgen_function_refactor(): # workaround ffigen - os.system( + system2( 'sed -i "s/ffi.NativeFunction> tmpdeb/usr/share/rustdesk/files/polkit && chmod a+x tmpdeb/usr/share/rustdesk/files/polkit") - os.system('mkdir -p tmpdeb/DEBIAN') + system2('mkdir -p tmpdeb/DEBIAN') generate_control_file(version) - os.system('cp -a ../res/DEBIAN/* tmpdeb/DEBIAN/') + system2('cp -a ../res/DEBIAN/* tmpdeb/DEBIAN/') md5_file('usr/share/rustdesk/files/systemd/rustdesk.service') - os.system('dpkg-deb -b tmpdeb rustdesk.deb;') + system2('dpkg-deb -b tmpdeb rustdesk.deb;') - os.system('/bin/rm -rf tmpdeb/') - os.system('/bin/rm -rf ../res/DEBIAN/control') + system2('/bin/rm -rf tmpdeb/') + system2('/bin/rm -rf ../res/DEBIAN/control') os.rename('rustdesk.deb', '../rustdesk-%s.deb' % version) os.chdir("..") @@ -314,16 +311,16 @@ def build_flutter_deb(version, features): def build_flutter_dmg(version, features): if not skip_cargo: # set minimum osx build target, now is 10.14, which is the same as the flutter xcode project - os.system(f'MACOSX_DEPLOYMENT_TARGET=10.14 cargo build --features {features} --lib --release') + system2(f'MACOSX_DEPLOYMENT_TARGET=10.14 cargo build --features {features} --lib --release') # copy dylib - os.system( + system2( "cp target/release/liblibrustdesk.dylib target/release/librustdesk.dylib") # ffi_bindgen_function_refactor() # limitations from flutter rust bridge - os.system('sed -i "" "s/char \*\*rustdesk_core_main(int \*args_len);//" flutter/macos/Runner/bridge_generated.h') + system2('sed -i "" "s/char \*\*rustdesk_core_main(int \*args_len);//" flutter/macos/Runner/bridge_generated.h') os.chdir('flutter') - os.system('flutter build macos --release') - os.system( + system2('flutter build macos --release') + system2( "create-dmg rustdesk.dmg ./build/macos/Build/Products/Release/RustDesk.app") os.rename("rustdesk.dmg", f"../rustdesk-{version}.dmg") os.chdir("..") @@ -331,29 +328,29 @@ def build_flutter_dmg(version, features): def build_flutter_arch_manjaro(version, features): if not skip_cargo: - os.system(f'cargo build --features {features} --lib --release') + system2(f'cargo build --features {features} --lib --release') ffi_bindgen_function_refactor() os.chdir('flutter') - os.system('flutter build linux --release') - os.system('strip build/linux/x64/release/bundle/lib/librustdesk.so') + system2('flutter build linux --release') + system2('strip build/linux/x64/release/bundle/lib/librustdesk.so') os.chdir('../res') - os.system('HBB=`pwd`/.. FLUTTER=1 makepkg -f') + system2('HBB=`pwd`/.. FLUTTER=1 makepkg -f') def build_flutter_windows(version, features): if not skip_cargo: - os.system(f'cargo build --features {features} --lib --release') + system2(f'cargo build --features {features} --lib --release') if not os.path.exists("target/release/librustdesk.dll"): print("cargo build failed, please check rust source code.") exit(-1) os.chdir('flutter') - os.system('flutter build windows --release') + system2('flutter build windows --release') os.chdir('..') shutil.copy2('target/release/deps/dylib_virtual_display.dll', flutter_win_target_dir) os.chdir('libs/portable') - os.system('pip3 install -r requirements.txt') - os.system( + system2('pip3 install -r requirements.txt') + system2( f'python3 ./generate.py -f ../../{flutter_win_target_dir} -o . -e ../../{flutter_win_target_dir}/rustdesk.exe') os.chdir('../..') if os.path.exists('./rustdesk_portable.exe'): @@ -374,22 +371,15 @@ def main(): parser = make_parser() args = parser.parse_args() - shutil.copy2('Cargo.toml', 'Cargo.toml.bk') - shutil.copy2('src/main.rs', 'src/main.rs.bk') - if windows: - txt = open('src/main.rs', encoding='utf8').read() - with open('src/main.rs', 'wt', encoding='utf8') as fh: - fh.write(txt.replace( - '//#![windows_subsystem', '#![windows_subsystem')) if os.path.exists(exe_path): os.unlink(exe_path) if os.path.isfile('/usr/bin/pacman'): - os.system('git checkout src/ui/common.tis') + system2('git checkout src/ui/common.tis') version = get_version() features = ','.join(get_features(args)) flutter = args.flutter if not flutter: - os.system('python3 res/inline-sciter.py') + system2('python3 res/inline-sciter.py') print(args.skip_cargo) if args.skip_cargo: skip_cargo = True @@ -397,55 +387,55 @@ def main(): if windows: # build virtual display dynamic library os.chdir('libs/virtual_display/dylib') - os.system('cargo build --release') + system2('cargo build --release') os.chdir('../../..') if flutter: build_flutter_windows(version, features) return - os.system('cargo build --release --features ' + features) - # os.system('upx.exe target/release/rustdesk.exe') - os.system('mv target/release/rustdesk.exe target/release/RustDesk.exe') + system2('cargo build --release --features ' + features) + # system2('upx.exe target/release/rustdesk.exe') + system2('mv target/release/rustdesk.exe target/release/RustDesk.exe') pa = os.environ.get('P') if pa: - os.system( + system2( f'signtool sign /a /v /p {pa} /debug /f .\\cert.pfx /t http://timestamp.digicert.com ' 'target\\release\\rustdesk.exe') else: print('Not signed') - os.system( + system2( f'cp -rf target/release/RustDesk.exe rustdesk-{version}-win7-install.exe') elif os.path.isfile('/usr/bin/pacman'): # pacman -S -needed base-devel - os.system("sed -i 's/pkgver=.*/pkgver=%s/g' res/PKGBUILD" % version) + system2("sed -i 's/pkgver=.*/pkgver=%s/g' res/PKGBUILD" % version) if flutter: build_flutter_arch_manjaro(version, features) else: - os.system('cargo build --release --features ' + features) - os.system('git checkout src/ui/common.tis') - os.system('strip target/release/rustdesk') - os.system('ln -s res/pacman_install && ln -s res/PKGBUILD') - os.system('HBB=`pwd` makepkg -f') - os.system('mv rustdesk-%s-0-x86_64.pkg.tar.zst rustdesk-%s-manjaro-arch.pkg.tar.zst' % ( + system2('cargo build --release --features ' + features) + system2('git checkout src/ui/common.tis') + system2('strip target/release/rustdesk') + system2('ln -s res/pacman_install && ln -s res/PKGBUILD') + system2('HBB=`pwd` makepkg -f') + system2('mv rustdesk-%s-0-x86_64.pkg.tar.zst rustdesk-%s-manjaro-arch.pkg.tar.zst' % ( version, version)) # pacman -U ./rustdesk.pkg.tar.zst elif os.path.isfile('/usr/bin/yum'): - os.system('cargo build --release --features ' + features) - os.system('strip target/release/rustdesk') - os.system( + system2('cargo build --release --features ' + features) + system2('strip target/release/rustdesk') + system2( "sed -i 's/Version: .*/Version: %s/g' res/rpm.spec" % version) - os.system('HBB=`pwd` rpmbuild -ba res/rpm.spec') - os.system( + system2('HBB=`pwd` rpmbuild -ba res/rpm.spec') + system2( 'mv $HOME/rpmbuild/RPMS/x86_64/rustdesk-%s-0.x86_64.rpm ./rustdesk-%s-fedora28-centos8.rpm' % ( version, version)) # yum localinstall rustdesk.rpm elif os.path.isfile('/usr/bin/zypper'): - os.system('cargo build --release --features ' + features) - os.system('strip target/release/rustdesk') - os.system( + system2('cargo build --release --features ' + features) + system2('strip target/release/rustdesk') + system2( "sed -i 's/Version: .*/Version: %s/g' res/rpm-suse.spec" % version) - os.system('HBB=`pwd` rpmbuild -ba res/rpm-suse.spec') - os.system( + system2('HBB=`pwd` rpmbuild -ba res/rpm-suse.spec') + system2( 'mv $HOME/rpmbuild/RPMS/x86_64/rustdesk-%s-0.x86_64.rpm ./rustdesk-%s-suse.rpm' % ( version, version)) # yum localinstall rustdesk.rpm @@ -455,18 +445,18 @@ def main(): build_flutter_dmg(version, features) pass else: - # os.system( + # system2( # 'mv target/release/bundle/deb/rustdesk*.deb ./flutter/rustdesk.deb') build_flutter_deb(version, features) else: - os.system('cargo bundle --release --features ' + features) + system2('cargo bundle --release --features ' + features) if osx: - os.system( + system2( 'strip target/release/bundle/osx/RustDesk.app/Contents/MacOS/rustdesk') - os.system( + system2( 'cp libsciter.dylib target/release/bundle/osx/RustDesk.app/Contents/MacOS/') # https://github.com/sindresorhus/create-dmg - os.system('/bin/rm -rf *.dmg') + system2('/bin/rm -rf *.dmg') plist = "target/release/bundle/osx/RustDesk.app/Contents/Info.plist" txt = open(plist).read() with open(plist, "wt") as fh: @@ -476,7 +466,7 @@ def main(): """)) pa = os.environ.get('P') if pa: - os.system(''' + system2(''' # buggy: rcodesign sign ... path/*, have to sign one by one # install rcodesign via cargo install apple-codesign #rcodesign sign --p12-file ~/.p12/rustdesk-developer-id.p12 --p12-password-file ~/.p12/.cert-pass --code-signature-flags runtime ./target/release/bundle/osx/RustDesk.app/Contents/MacOS/rustdesk @@ -486,11 +476,11 @@ def main(): codesign -s "Developer ID Application: {0}" --force --options runtime ./target/release/bundle/osx/RustDesk.app/Contents/MacOS/* codesign -s "Developer ID Application: {0}" --force --options runtime ./target/release/bundle/osx/RustDesk.app '''.format(pa)) - os.system('create-dmg target/release/bundle/osx/RustDesk.app') + system2('create-dmg target/release/bundle/osx/RustDesk.app') os.rename('RustDesk %s.dmg' % version, 'rustdesk-%s.dmg' % version) if pa: - os.system(''' + system2(''' # https://pyoxidizer.readthedocs.io/en/apple-codesign-0.14.0/apple_codesign.html # https://pyoxidizer.readthedocs.io/en/stable/tugger_code_signing.html # https://developer.apple.com/developer-id/ @@ -507,34 +497,32 @@ def main(): print('Not signed') else: # buid deb package - os.system( + system2( 'mv target/release/bundle/deb/rustdesk*.deb ./rustdesk.deb') - os.system('dpkg-deb -R rustdesk.deb tmpdeb') - os.system('mkdir -p tmpdeb/usr/share/rustdesk/files/systemd/') - os.system( + system2('dpkg-deb -R rustdesk.deb tmpdeb') + system2('mkdir -p tmpdeb/usr/share/rustdesk/files/systemd/') + system2( 'cp res/rustdesk.service tmpdeb/usr/share/rustdesk/files/systemd/') - os.system( + system2( 'cp res/128x128@2x.png tmpdeb/usr/share/rustdesk/files/rustdesk.png') - os.system( + system2( 'cp res/rustdesk.desktop tmpdeb/usr/share/applications/rustdesk.desktop') - os.system( + system2( 'cp res/rustdesk-link.desktop tmpdeb/usr/share/applications/rustdesk-link.desktop') - os.system('cp -a res/DEBIAN/* tmpdeb/DEBIAN/') - os.system('strip tmpdeb/usr/bin/rustdesk') - os.system('mkdir -p tmpdeb/usr/lib/rustdesk') - os.system('mv tmpdeb/usr/bin/rustdesk tmpdeb/usr/lib/rustdesk/') - os.system('cp libsciter-gtk.so tmpdeb/usr/lib/rustdesk/') + system2('cp -a res/DEBIAN/* tmpdeb/DEBIAN/') + system2('strip tmpdeb/usr/bin/rustdesk') + system2('mkdir -p tmpdeb/usr/lib/rustdesk') + system2('mv tmpdeb/usr/bin/rustdesk tmpdeb/usr/lib/rustdesk/') + system2('cp libsciter-gtk.so tmpdeb/usr/lib/rustdesk/') md5_file('usr/share/rustdesk/files/systemd/rustdesk.service') md5_file('usr/lib/rustdesk/libsciter-gtk.so') - os.system('dpkg-deb -b tmpdeb rustdesk.deb; /bin/rm -rf tmpdeb/') + system2('dpkg-deb -b tmpdeb rustdesk.deb; /bin/rm -rf tmpdeb/') os.rename('rustdesk.deb', 'rustdesk-%s.deb' % version) - os.system("mv Cargo.toml.bk Cargo.toml") - os.system("mv src/main.rs.bk src/main.rs") def md5_file(fn): md5 = hashlib.md5(open('tmpdeb/' + fn, 'rb').read()).hexdigest() - os.system('echo "%s %s" >> tmpdeb/DEBIAN/md5sums' % (md5, fn)) + system2('echo "%s %s" >> tmpdeb/DEBIAN/md5sums' % (md5, fn)) if __name__ == "__main__": diff --git a/src/main.rs b/src/main.rs index 169515425..3759f6056 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ -// Specify the Windows subsystem to eliminate console window. -// Requires Rust 1.18. -//#![windows_subsystem = "windows"] + #![cfg_attr( + all(not(debug_assertions), target_os = "windows"), + windows_subsystem = "windows" + )] use librustdesk::*; From f94791793bdec5d83b011709261857a6d6a8f653 Mon Sep 17 00:00:00 2001 From: 21pages Date: Mon, 27 Feb 2023 19:22:52 +0800 Subject: [PATCH 24/65] fix can't install when username contains &, @, ^ Signed-off-by: 21pages --- src/platform/windows.rs | 25 +++++++++++++++++++++++++ src/server/portable_service.rs | 12 +----------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 6b3f8013c..0bba649f4 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -1236,6 +1236,15 @@ pub fn uninstall_me() -> ResultType<()> { fn write_cmds(cmds: String, ext: &str, tip: &str) -> ResultType { let mut tmp = std::env::temp_dir(); + // When dir contains these characters, the bat file will not execute in elevated mode. + if vec!["&", "@", "^"] + .drain(..) + .any(|s| tmp.to_string_lossy().to_string().contains(s)) + { + if let Ok(dir) = user_accessible_folder() { + tmp = dir; + } + } tmp.push(format!("{}_{}.{}", crate::get_app_name(), tip, ext)); let mut file = std::fs::File::create(&tmp)?; // in case cmds mixed with \r\n and \n, make sure all ending with \r\n @@ -1872,3 +1881,19 @@ pub fn change_resolution(name: &str, width: usize, height: usize) -> ResultType< Ok(()) } } + +pub fn user_accessible_folder() -> ResultType { + let disk = std::env::var("SystemDrive").unwrap_or("C:".to_string()); + let dir1 = PathBuf::from(format!("{}\\ProgramData", disk)); + // NOTICE: "C:\Windows\Temp" requires permanent authorization. + let dir2 = PathBuf::from(format!("{}\\Windows\\Temp", disk)); + let dir; + if dir1.exists() { + dir = dir1; + } else if dir2.exists() { + dir = dir2; + } else { + bail!("no vaild user accessible folder"); + } + Ok(dir) +} diff --git a/src/server/portable_service.rs b/src/server/portable_service.rs index 7514ead38..c49f974a7 100644 --- a/src/server/portable_service.rs +++ b/src/server/portable_service.rs @@ -117,17 +117,7 @@ impl SharedMemory { } fn flink(name: String) -> ResultType { - let disk = std::env::var("SystemDrive").unwrap_or("C:".to_string()); - let dir1 = PathBuf::from(format!("{}\\ProgramData", disk)); - let dir2 = PathBuf::from(format!("{}\\Windows\\Temp", disk)); - let mut dir; - if dir1.exists() { - dir = dir1; - } else if dir2.exists() { - dir = dir2; - } else { - bail!("no vaild flink directory"); - } + let mut dir = crate::platform::user_accessible_folder()?; dir = dir.join(hbb_common::config::APP_NAME.read().unwrap().clone()); if !dir.exists() { std::fs::create_dir(&dir)?; From c7e8037a79f3446591e585bbdfe52ed696c26873 Mon Sep 17 00:00:00 2001 From: solokot Date: Mon, 27 Feb 2023 15:57:46 +0300 Subject: [PATCH 25/65] Update ru.rs --- src/lang/ru.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 07b8af998..3bfb5357d 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -454,8 +454,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Stop voice call", "Завершить голосовой вызов"), ("relay_hint_tip", "Прямое подключение может оказаться невозможным. В этом случае можно попытаться подключиться через сервер ретрансляции. \nКроме того, если вы хотите сразу использовать сервер ретрансляции, можно добавить к ID суффикс \"/r\" или включить \"Всегда подключаться через ретранслятор\" в настройках удалённого узла."), ("Reconnect", "Переподключить"), - ("Codec", ""), - ("Resolution", ""), - ("No transfers in progress", ""), + ("Codec", "Кодек"), + ("Resolution", "Разрешение"), + ("No transfers in progress", "Передача не осуществляется"), ].iter().cloned().collect(); } From 63185a5bcb6272ad42b3f5abbaa54a9724fc03e7 Mon Sep 17 00:00:00 2001 From: csf Date: Mon, 27 Feb 2023 23:07:52 +0900 Subject: [PATCH 26/65] 1. enable BootReceiver. 2. add PermissionRequestTransparentActivity. 3. opt const. --- .../android/app/src/main/AndroidManifest.xml | 21 +++++--- .../com/carriez/flutter_hbb/BootReceiver.kt | 17 ++++-- .../com/carriez/flutter_hbb/MainActivity.kt | 51 ++++-------------- .../com/carriez/flutter_hbb/MainService.kt | 37 ++++++++----- .../PermissionRequestTransparentActivity.kt | 54 +++++++++++++++++++ .../kotlin/com/carriez/flutter_hbb/common.kt | 21 ++++++-- .../app/src/main/res/values/styles.xml | 8 +++ 7 files changed, 137 insertions(+), 72 deletions(-) create mode 100644 flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/PermissionRequestTransparentActivity.kt diff --git a/flutter/android/app/src/main/AndroidManifest.xml b/flutter/android/app/src/main/AndroidManifest.xml index ede6353ef..6f646b913 100644 --- a/flutter/android/app/src/main/AndroidManifest.xml +++ b/flutter/android/app/src/main/AndroidManifest.xml @@ -11,22 +11,24 @@ - + + android:supportsRtl="true"> + android:enabled="true" + android:exported="true"> + + @@ -53,8 +55,6 @@ android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:windowSoftInputMode="adjustResize"> - - @@ -62,6 +62,11 @@ + + - + \ No newline at end of file diff --git a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/BootReceiver.kt b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/BootReceiver.kt index 328701567..a49dcc326 100644 --- a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/BootReceiver.kt +++ b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/BootReceiver.kt @@ -4,18 +4,25 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.os.Build +import android.util.Log import android.widget.Toast +const val DEBUG_BOOT_COMPLETED = "com.carriez.flutter_hbb.DEBUG_BOOT_COMPLETED" + class BootReceiver : BroadcastReceiver() { + private val logTag = "tagBootReceiver" + override fun onReceive(context: Context, intent: Intent) { - if ("android.intent.action.BOOT_COMPLETED" == intent.action){ - val it = Intent(context,MainService::class.java).apply { - addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + Log.d(logTag, "onReceive ${intent.action}") + + if (Intent.ACTION_BOOT_COMPLETED == intent.action || DEBUG_BOOT_COMPLETED == intent.action) { + val it = Intent(context, MainService::class.java).apply { + action = ACT_INIT_MEDIA_PROJECTION_AND_SERVICE } - Toast.makeText(context, "RustDesk is Open", Toast.LENGTH_LONG).show(); + Toast.makeText(context, "RustDesk is Open", Toast.LENGTH_LONG).show() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(it) - }else{ + } else { context.startService(it) } } diff --git a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt index fd340f7ed..73dbd2dad 100644 --- a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt +++ b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt @@ -7,12 +7,10 @@ package com.carriez.flutter_hbb * Inspired by [droidVNC-NG] https://github.com/bk138/droidVNC-NG */ -import android.app.Activity import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.ServiceConnection -import android.media.projection.MediaProjectionManager import android.os.Build import android.os.IBinder import android.provider.Settings @@ -23,7 +21,6 @@ import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel -const val MEDIA_REQUEST_CODE = 42 class MainActivity : FlutterActivity() { companion object { @@ -32,7 +29,6 @@ class MainActivity : FlutterActivity() { private val channelTag = "mChannel" private val logTag = "mMainActivity" - private var mediaProjectionResultIntent: Intent? = null private var mainService: MainService? = null @RequiresApi(Build.VERSION_CODES.M) @@ -58,7 +54,7 @@ class MainActivity : FlutterActivity() { result.success(false) return@setMethodCallHandler } - getMediaProjection() + requestMediaProjection() result.success(true) } "start_capture" -> { @@ -153,35 +149,6 @@ class MainActivity : FlutterActivity() { } } - private fun getMediaProjection() { - val mMediaProjectionManager = - getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager - val mIntent = mMediaProjectionManager.createScreenCaptureIntent() - startActivityForResult(mIntent, MEDIA_REQUEST_CODE) - } - - private fun initService() { - if (mediaProjectionResultIntent == null) { - Log.w(logTag, "initService fail,mediaProjectionResultIntent is null") - return - } - Log.d(logTag, "Init service") - val serviceIntent = Intent(this, MainService::class.java) - serviceIntent.action = INIT_SERVICE - serviceIntent.putExtra(EXTRA_MP_DATA, mediaProjectionResultIntent) - - launchMainService(serviceIntent) - } - - private fun launchMainService(intent: Intent) { - // TEST api < O - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - startForegroundService(intent) - } else { - startService(intent) - } - } - private fun initInput() { val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS) if (intent.resolveActivity(packageManager) != null) { @@ -200,15 +167,17 @@ class MainActivity : FlutterActivity() { } } + private fun requestMediaProjection() { + val intent = Intent(this, PermissionRequestTransparentActivity::class.java).apply { + action = ACT_REQUEST_MEDIA_PROJECTION + } + startActivityForResult(intent, REQ_INVOKE_PERMISSION_ACTIVITY_MEDIA_PROJECTION) + } + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) - if (requestCode == MEDIA_REQUEST_CODE) { - if (resultCode == Activity.RESULT_OK && data != null) { - mediaProjectionResultIntent = data - initService() - } else { - flutterMethodChannel.invokeMethod("on_media_projection_canceled", null) - } + if (requestCode == REQ_INVOKE_PERMISSION_ACTIVITY_MEDIA_PROJECTION && resultCode == RES_FAILED) { + flutterMethodChannel.invokeMethod("on_media_projection_canceled", null) } } diff --git a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt index cf8e12e92..e28311964 100644 --- a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt +++ b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt @@ -43,10 +43,6 @@ import java.nio.ByteBuffer import kotlin.math.max import kotlin.math.min -const val EXTRA_MP_DATA = "mp_intent" -const val INIT_SERVICE = "init_service" -const val ACTION_LOGIN_REQ_NOTIFY = "ACTION_LOGIN_REQ_NOTIFY" -const val EXTRA_LOGIN_REQ_NOTIFY = "EXTRA_LOGIN_REQ_NOTIFY" const val DEFAULT_NOTIFY_TITLE = "RustDesk" const val DEFAULT_NOTIFY_TEXT = "Service is running" @@ -195,6 +191,7 @@ class MainService : Service() { override fun onCreate() { super.onCreate() + Log.d(logTag,"MainService onCreate") HandlerThread("Service", Process.THREAD_PRIORITY_BACKGROUND).apply { start() serviceLooper = looper @@ -203,6 +200,7 @@ class MainService : Service() { updateScreenInfo(resources.configuration.orientation) initNotification() startServer() + createForegroundNotification() } override fun onDestroy() { @@ -277,22 +275,25 @@ class MainService : Service() { } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - Log.d("whichService", "this service:${Thread.currentThread()}") + Log.d("whichService", "this service: ${Thread.currentThread()}") super.onStartCommand(intent, flags, startId) - if (intent?.action == INIT_SERVICE) { - Log.d(logTag, "service starting:${startId}:${Thread.currentThread()}") - createForegroundNotification() - val mMediaProjectionManager = + if (intent?.action == ACT_INIT_MEDIA_PROJECTION_AND_SERVICE) { + Log.d(logTag, "service starting: ${startId}:${Thread.currentThread()}") + val mediaProjectionManager = getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager - intent.getParcelableExtra(EXTRA_MP_DATA)?.let { + + intent.getParcelableExtra(EXT_MEDIA_PROJECTION_RES_INTENT)?.let { mediaProjection = - mMediaProjectionManager.getMediaProjection(Activity.RESULT_OK, it) + mediaProjectionManager.getMediaProjection(Activity.RESULT_OK, it) checkMediaPermission() init(this) _isReady = true + } ?: let { + Log.d(logTag, "getParcelableExtra intent null, invoke requestMediaProjection") + requestMediaProjection() } } - return START_NOT_STICKY // don't use sticky (auto restart),the new service (from auto restart) will lose control + return START_NOT_STICKY // don't use sticky (auto restart), the new service (from auto restart) will lose control } override fun onConfigurationChanged(newConfig: Configuration) { @@ -300,6 +301,14 @@ class MainService : Service() { updateScreenInfo(newConfig.orientation) } + private fun requestMediaProjection() { + val intent = Intent(this, PermissionRequestTransparentActivity::class.java).apply { + action = ACT_REQUEST_MEDIA_PROJECTION + flags = Intent.FLAG_ACTIVITY_NEW_TASK + } + startActivity(intent) + } + @SuppressLint("WrongConstant") private fun createSurface(): Surface? { return if (useVP9) { @@ -653,8 +662,8 @@ class MainService : Service() { @SuppressLint("UnspecifiedImmutableFlag") private fun genLoginRequestPendingIntent(res: Boolean): PendingIntent { val intent = Intent(this, MainService::class.java).apply { - action = ACTION_LOGIN_REQ_NOTIFY - putExtra(EXTRA_LOGIN_REQ_NOTIFY, res) + action = ACT_LOGIN_REQ_NOTIFY + putExtra(EXT_LOGIN_REQ_NOTIFY, res) } return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { PendingIntent.getService(this, 111, intent, FLAG_IMMUTABLE) diff --git a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/PermissionRequestTransparentActivity.kt b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/PermissionRequestTransparentActivity.kt new file mode 100644 index 000000000..3beb7ec6b --- /dev/null +++ b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/PermissionRequestTransparentActivity.kt @@ -0,0 +1,54 @@ +package com.carriez.flutter_hbb + +import android.app.Activity +import android.content.Intent +import android.media.projection.MediaProjectionManager +import android.os.Build +import android.os.Bundle +import android.util.Log + +class PermissionRequestTransparentActivity: Activity() { + private val logTag = "permissionRequest" + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + Log.d(logTag, "onCreate PermissionRequestTransparentActivity: intent.action: ${intent.action}") + + when (intent.action) { + ACT_REQUEST_MEDIA_PROJECTION -> { + val mediaProjectionManager = + getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager + val intent = mediaProjectionManager.createScreenCaptureIntent() + startActivityForResult(intent, REQ_REQUEST_MEDIA_PROJECTION) + } + else -> finish() + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (requestCode == REQ_REQUEST_MEDIA_PROJECTION) { + if (resultCode == RESULT_OK && data != null) { + launchService(data) + } else { + setResult(RES_FAILED) + } + } + + finish() + } + + private fun launchService(mediaProjectionResultIntent: Intent) { + Log.d(logTag, "Launch MainService") + val serviceIntent = Intent(this, MainService::class.java) + serviceIntent.action = ACT_INIT_MEDIA_PROJECTION_AND_SERVICE + serviceIntent.putExtra(EXT_MEDIA_PROJECTION_RES_INTENT, mediaProjectionResultIntent) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + startForegroundService(serviceIntent) + } else { + startService(serviceIntent) + } + } + +} \ No newline at end of file diff --git a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt index 4bf244a06..a812686ec 100644 --- a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt +++ b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt @@ -12,8 +12,7 @@ import android.os.Build import android.os.Handler import android.os.Looper import android.os.PowerManager -import android.provider.Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS -import android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS +import android.provider.Settings.* import androidx.annotation.RequiresApi import androidx.core.content.ContextCompat.getSystemService import com.hjq.permissions.Permission @@ -22,6 +21,21 @@ import java.nio.ByteBuffer import java.util.* +// intent action, extra +const val ACT_REQUEST_MEDIA_PROJECTION = "REQUEST_MEDIA_PROJECTION" +const val ACT_INIT_MEDIA_PROJECTION_AND_SERVICE = "INIT_MEDIA_PROJECTION_AND_SERVICE" +const val ACT_LOGIN_REQ_NOTIFY = "LOGIN_REQ_NOTIFY" +const val EXT_MEDIA_PROJECTION_RES_INTENT = "MEDIA_PROJECTION_RES_INTENT" +const val EXT_LOGIN_REQ_NOTIFY = "LOGIN_REQ_NOTIFY" + +// Activity requestCode +const val REQ_INVOKE_PERMISSION_ACTIVITY_MEDIA_PROJECTION = 101 +const val REQ_REQUEST_MEDIA_PROJECTION = 201 + +// Activity responseCode +const val RES_FAILED = -100 + + @SuppressLint("ConstantLocale") val LOCAL_NAME = Locale.getDefault().toString() val SCREEN_INFO = Info(0, 0, 1, 200) @@ -59,9 +73,8 @@ fun requestPermission(context: Context, type: String) { } "application_details_settings" -> { try { - context.startActivity(Intent().apply { + context.startActivity(Intent(ACTION_APPLICATION_DETAILS_SETTINGS).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - action = "android.settings.APPLICATION_DETAILS_SETTINGS" data = Uri.parse("package:" + context.packageName) }) } catch (e:Exception) { diff --git a/flutter/android/app/src/main/res/values/styles.xml b/flutter/android/app/src/main/res/values/styles.xml index d74aa35c2..146267c91 100644 --- a/flutter/android/app/src/main/res/values/styles.xml +++ b/flutter/android/app/src/main/res/values/styles.xml @@ -15,4 +15,12 @@ + From 658c45d1c233a7be5997e38db701ea2af9c81c45 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 27 Feb 2023 21:46:26 +0800 Subject: [PATCH 27/65] Do not use flutter texture for render. Signed-off-by: fufesou --- .github/workflows/flutter-nightly.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/flutter-nightly.yml b/.github/workflows/flutter-nightly.yml index b08193971..ffcadd18b 100644 --- a/.github/workflows/flutter-nightly.yml +++ b/.github/workflows/flutter-nightly.yml @@ -732,7 +732,7 @@ jobs: x86_64) # no need mock on x86_64 export VCPKG_ROOT=/opt/artifacts/vcpkg - cargo build --lib --features hwcodec,flutter,flutter_texture_render,${{ matrix.job.extra-build-features }} --release + cargo build --lib --features hwcodec,flutter,${{ matrix.job.extra-build-features }} --release ;; esac @@ -900,7 +900,7 @@ jobs: ln -s /usr/include /vcpkg/installed/arm64-linux/include export VCPKG_ROOT=/vcpkg # disable hwcodec for compilation - cargo build --lib --features flutter,flutter_texture_render,${{ matrix.job.extra-build-features }} --release + cargo build --lib --features flutter,${{ matrix.job.extra-build-features }} --release ;; armv7) cp -r /opt/artifacts/vcpkg/installed/lib/* /usr/lib/arm-linux-gnueabihf/ @@ -910,7 +910,7 @@ jobs: ln -s /usr/include /vcpkg/installed/arm-linux/include export VCPKG_ROOT=/vcpkg # disable hwcodec for compilation - cargo build --lib --features flutter,flutter_texture_render,${{ matrix.job.extra-build-features }} --release + cargo build --lib --features flutter,${{ matrix.job.extra-build-features }} --release ;; esac From fb21f9df440101739875eece1c45383272394cd1 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 27 Feb 2023 22:24:00 +0800 Subject: [PATCH 28/65] check divide by 0 Signed-off-by: fufesou --- flutter/lib/models/model.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 21949705f..fd97b1e5c 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -810,6 +810,10 @@ class CanvasModel with ChangeNotifier { double get tabBarHeight => stateGlobal.tabBarHeight; moveDesktopMouse(double x, double y) { + if (size.width == 0 || size.height == 0) { + return; + } + // On mobile platforms, move the canvas with the cursor. final dw = getDisplayWidth() * _scale; final dh = getDisplayHeight() * _scale; From 8cd9f8745d99686598347d1f0cd0d0192d1ec288 Mon Sep 17 00:00:00 2001 From: csf Date: Tue, 28 Feb 2023 00:41:09 +0900 Subject: [PATCH 29/65] opt AndroidPermissionManager --- .../com/carriez/flutter_hbb/MainActivity.kt | 8 ++ .../kotlin/com/carriez/flutter_hbb/common.kt | 84 +++++-------------- flutter/lib/common.dart | 27 ++---- flutter/lib/consts.dart | 26 ++++-- flutter/lib/mobile/pages/server_page.dart | 12 +-- flutter/lib/mobile/pages/settings_page.dart | 10 ++- flutter/lib/models/server_model.dart | 19 +++-- 7 files changed, 85 insertions(+), 101 deletions(-) diff --git a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt index 73dbd2dad..7050e7a46 100644 --- a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt +++ b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt @@ -88,6 +88,14 @@ class MainActivity : FlutterActivity() { result.success(false) } } + START_ACTION -> { + if (call.arguments is String) { + startAction(context, call.arguments as String) + result.success(true) + } else { + result.success(false) + } + } "check_video_permission" -> { mainService?.let { result.success(it.checkMediaPermission()) diff --git a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt index a812686ec..0bc6c1c28 100644 --- a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt +++ b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt @@ -1,5 +1,6 @@ package com.carriez.flutter_hbb +import android.Manifest.permission.* import android.annotation.SuppressLint import android.content.Context import android.content.Intent @@ -35,6 +36,10 @@ const val REQ_REQUEST_MEDIA_PROJECTION = 201 // Activity responseCode const val RES_FAILED = -100 +// Flutter channel +const val START_ACTION = "start_action"; +const val IGNORE_BATTERY_OPTIMIZATIONS = "ignore_battery_optimizations"; + @SuppressLint("ConstantLocale") val LOCAL_NAME = Locale.getDefault().toString() @@ -44,56 +49,10 @@ data class Info( var width: Int, var height: Int, var scale: Int, var dpi: Int ) -@RequiresApi(Build.VERSION_CODES.LOLLIPOP) -fun testVP9Support(): Boolean { - return true - val res = MediaCodecList(MediaCodecList.ALL_CODECS) - .findEncoderForFormat( - MediaFormat.createVideoFormat( - MediaFormat.MIMETYPE_VIDEO_VP9, - SCREEN_INFO.width, - SCREEN_INFO.width - ) - ) - return res != null -} - @RequiresApi(Build.VERSION_CODES.M) fun requestPermission(context: Context, type: String) { - val permission = when (type) { - "ignore_battery_optimizations" -> { - try { - context.startActivity(Intent(ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).apply { - data = Uri.parse("package:" + context.packageName) - }) - } catch (e:Exception) { - e.printStackTrace() - } - return - } - "application_details_settings" -> { - try { - context.startActivity(Intent(ACTION_APPLICATION_DETAILS_SETTINGS).apply { - addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - data = Uri.parse("package:" + context.packageName) - }) - } catch (e:Exception) { - e.printStackTrace() - } - return - } - "audio" -> { - Permission.RECORD_AUDIO - } - "file" -> { - Permission.MANAGE_EXTERNAL_STORAGE - } - else -> { - return - } - } XXPermissions.with(context) - .permission(permission) + .permission(type) .request { _, all -> if (all) { Handler(Looper.getMainLooper()).post { @@ -108,22 +67,23 @@ fun requestPermission(context: Context, type: String) { @RequiresApi(Build.VERSION_CODES.M) fun checkPermission(context: Context, type: String): Boolean { - val permission = when (type) { - "ignore_battery_optimizations" -> { - val pw = context.getSystemService(Context.POWER_SERVICE) as PowerManager - return pw.isIgnoringBatteryOptimizations(context.packageName) - } - "audio" -> { - Permission.RECORD_AUDIO - } - "file" -> { - Permission.MANAGE_EXTERNAL_STORAGE - } - else -> { - return false - } + if (IGNORE_BATTERY_OPTIMIZATIONS == type) { + val pw = context.getSystemService(Context.POWER_SERVICE) as PowerManager + return pw.isIgnoringBatteryOptimizations(context.packageName) + } + return XXPermissions.isGranted(context, type) +} + +@RequiresApi(Build.VERSION_CODES.M) +fun startAction(context: Context, action: String) { + try { + context.startActivity(Intent(action).apply { + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + data = Uri.parse("package:" + context.packageName) + }) + } catch (e: Exception) { + e.printStackTrace() } - return XXPermissions.isGranted(context, permission) } class AudioReader(val bufSize: Int, private val maxFrames: Int) { diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 53a401230..41ac595f2 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -907,21 +907,14 @@ class AccessibilityListener extends StatelessWidget { } } -class PermissionManager { +class AndroidPermissionManager { static Completer? _completer; static Timer? _timer; static var _current = ""; - static final permissions = [ - "audio", - "file", - "ignore_battery_optimizations", - "application_details_settings" - ]; - static bool isWaitingFile() { if (_completer != null) { - return !_completer!.isCompleted && _current == "file"; + return !_completer!.isCompleted && _current == kManageExternalStorage; } return false; } @@ -930,9 +923,6 @@ class PermissionManager { if (isDesktop) { return Future.value(true); } - if (!permissions.contains(type)) { - return Future.error("Wrong permission!$type"); - } return gFFI.invokeMethod("check_permission", type); } @@ -940,17 +930,16 @@ class PermissionManager { if (isDesktop) { return Future.value(true); } - if (!permissions.contains(type)) { - return Future.error("Wrong permission!$type"); - } gFFI.invokeMethod("request_permission", type); - if (type == "ignore_battery_optimizations") { + + // kIgnoreBatteryOptimizations permission doesn't depend on callback result, the result will be checked and updated on page resume + if (type == kIgnoreBatteryOptimizations) { return Future.value(false); } + _current = type; _completer = Completer(); - gFFI.invokeMethod("request_permission", type); // timeout _timer?.cancel(); @@ -1484,8 +1473,8 @@ connect(BuildContext context, String id, } } else { if (isFileTransfer) { - if (!await PermissionManager.check("file")) { - if (!await PermissionManager.request("file")) { + if (!await AndroidPermissionManager.check(kManageExternalStorage)) { + if (!await AndroidPermissionManager.request(kManageExternalStorage)) { return; } } diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index 3c414cd85..a0766a874 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -59,11 +59,12 @@ const double kDesktopFileTransferMaximumWidth = 300; const double kDesktopFileTransferRowHeight = 30.0; const double kDesktopFileTransferHeaderHeight = 25.0; -EdgeInsets get kDragToResizeAreaPadding => !kUseCompatibleUiMode && Platform.isLinux - ? stateGlobal.fullscreen || stateGlobal.maximize - ? EdgeInsets.zero - : EdgeInsets.all(5.0) - : EdgeInsets.zero; +EdgeInsets get kDragToResizeAreaPadding => + !kUseCompatibleUiMode && Platform.isLinux + ? stateGlobal.fullscreen || stateGlobal.maximize + ? EdgeInsets.zero + : EdgeInsets.all(5.0) + : EdgeInsets.zero; // https://en.wikipedia.org/wiki/Non-breaking_space const int $nbsp = 0x00A0; @@ -136,6 +137,21 @@ const kRemoteAudioDualWay = 'dual-way'; const kIgnoreDpi = true; +/// Android constants +const kActionApplicationDetailsSettings = + "android.settings.APPLICATION_DETAILS_SETTINGS"; +const kActionRequestIgnoreBatteryOptimizations = + "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"; +const kRecordAudio = "android.permission.RECORD_AUDIO"; +const kManageExternalStorage = "android.permission.MANAGE_EXTERNAL_STORAGE"; +const kSystemAlertWindow = "android.permission.SYSTEM_ALERT_WINDOW"; + +/// [kIgnoreBatteryOptimizations] not a Android Permission, it is a custom key, used in `ignore battery optimizations` check +const kIgnoreBatteryOptimizations = "ignore_battery_optimizations"; + +/// Android channel invoke type key +const kStartAction = "start_action"; + /// flutter/packages/flutter/lib/src/services/keyboard_key.dart -> _keyLabels /// see [LogicalKeyboardKey.keyLabel] const Map logicalKeyMap = { diff --git a/flutter/lib/mobile/pages/server_page.dart b/flutter/lib/mobile/pages/server_page.dart index abccdf683..648448f41 100644 --- a/flutter/lib/mobile/pages/server_page.dart +++ b/flutter/lib/mobile/pages/server_page.dart @@ -6,6 +6,7 @@ import 'package:provider/provider.dart'; import '../../common.dart'; import '../../common/widgets/dialog.dart'; +import '../../consts.dart'; import '../../models/platform_model.dart'; import '../../models/server_model.dart'; import 'home_page.dart'; @@ -150,10 +151,11 @@ class _ServerPageState extends State { } void checkService() async { - gFFI.invokeMethod("check_service"); // jvm - // for Android 10/11,MANAGE_EXTERNAL_STORAGE permission from a system setting page - if (PermissionManager.isWaitingFile() && !gFFI.serverModel.fileOk) { - PermissionManager.complete("file", await PermissionManager.check("file")); + gFFI.invokeMethod("check_service"); + // for Android 10/11, request MANAGE_EXTERNAL_STORAGE permission from system setting page + if (AndroidPermissionManager.isWaitingFile() && !gFFI.serverModel.fileOk) { + AndroidPermissionManager.complete(kManageExternalStorage, + await AndroidPermissionManager.check(kManageExternalStorage)); debugPrint("file permission finished"); } } @@ -567,7 +569,7 @@ void androidChannelInit() { { var type = arguments["type"] as String; var result = arguments["result"] as bool; - PermissionManager.complete(type, result); + AndroidPermissionManager.complete(type, result); break; } case "on_media_projection_canceled": diff --git a/flutter/lib/mobile/pages/settings_page.dart b/flutter/lib/mobile/pages/settings_page.dart index c5f3b6935..6bdb7e813 100644 --- a/flutter/lib/mobile/pages/settings_page.dart +++ b/flutter/lib/mobile/pages/settings_page.dart @@ -10,6 +10,7 @@ import 'package:url_launcher/url_launcher.dart'; import '../../common.dart'; import '../../common/widgets/dialog.dart'; import '../../common/widgets/login.dart'; +import '../../consts.dart'; import '../../models/model.dart'; import '../../models/platform_model.dart'; import '../widgets/dialog.dart'; @@ -133,7 +134,8 @@ class _SettingsState extends State with WidgetsBindingObserver { } Future updateIgnoreBatteryStatus() async { - final res = await PermissionManager.check("ignore_battery_optimizations"); + final res = + await AndroidPermissionManager.check(kIgnoreBatteryOptimizations); if (_ignoreBatteryOpt != res) { _ignoreBatteryOpt = res; return true; @@ -265,7 +267,8 @@ class _SettingsState extends State with WidgetsBindingObserver { ]), onToggle: (v) async { if (v) { - PermissionManager.request("ignore_battery_optimizations"); + gFFI.invokeMethod( + kStartAction, kActionRequestIgnoreBatteryOptimizations); } else { final res = await gFFI.dialogManager .show((setState, close) => CustomAlertDialog( @@ -282,7 +285,8 @@ class _SettingsState extends State with WidgetsBindingObserver { ], )); if (res == true) { - PermissionManager.request("application_details_settings"); + gFFI.invokeMethod( + kStartAction, kActionApplicationDetailsSettings); } } })); diff --git a/flutter/lib/models/server_model.dart b/flutter/lib/models/server_model.dart index b2043f3c2..433990a2a 100644 --- a/flutter/lib/models/server_model.dart +++ b/flutter/lib/models/server_model.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/main.dart'; import 'package:flutter_hbb/models/platform_model.dart'; import 'package:get/get.dart'; @@ -154,7 +155,8 @@ class ServerModel with ChangeNotifier { /// file true by default (if permission on) checkAndroidPermission() async { // audio - if (androidVersion < 30 || !await PermissionManager.check("audio")) { + if (androidVersion < 30 || + !await AndroidPermissionManager.check(kRecordAudio)) { _audioOk = false; bind.mainSetOption(key: "enable-audio", value: "N"); } else { @@ -163,7 +165,7 @@ class ServerModel with ChangeNotifier { } // file - if (!await PermissionManager.check("file")) { + if (!await AndroidPermissionManager.check(kManageExternalStorage)) { _fileOk = false; bind.mainSetOption(key: "enable-file-transfer", value: "N"); } else { @@ -229,8 +231,8 @@ class ServerModel with ChangeNotifier { } toggleAudio() async { - if (!_audioOk && !await PermissionManager.check("audio")) { - final res = await PermissionManager.request("audio"); + if (!_audioOk && !await AndroidPermissionManager.check(kRecordAudio)) { + final res = await AndroidPermissionManager.request(kRecordAudio); if (!res) { // TODO handle fail return; @@ -243,8 +245,10 @@ class ServerModel with ChangeNotifier { } toggleFile() async { - if (!_fileOk && !await PermissionManager.check("file")) { - final res = await PermissionManager.request("file"); + if (!_fileOk && + !await AndroidPermissionManager.check(kManageExternalStorage)) { + final res = + await AndroidPermissionManager.request(kManageExternalStorage); if (!res) { // TODO handle fail return; @@ -561,7 +565,8 @@ class ServerModel with ChangeNotifier { } Future closeAll() async { - await Future.wait(_clients.map((client) => bind.cmCloseConnection(connId: client.id))); + await Future.wait( + _clients.map((client) => bind.cmCloseConnection(connId: client.id))); _clients.clear(); tabController.state.value.tabs.clear(); } From 7bbeb351ce4eb6c582a7b162b4e415270b86b1be Mon Sep 17 00:00:00 2001 From: Michal Witek Date: Mon, 27 Feb 2023 20:40:39 +0100 Subject: [PATCH 30/65] Updated Flutter Version to `3.7.5` Updated agents OS to `Ubuntu 20.04` where possible --- .github/workflows/flutter-ci.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/flutter-ci.yml b/.github/workflows/flutter-ci.yml index 74e4efa99..cae5b82c7 100644 --- a/.github/workflows/flutter-ci.yml +++ b/.github/workflows/flutter-ci.yml @@ -18,7 +18,7 @@ on: env: LLVM_VERSION: "15.0.6" - FLUTTER_VERSION: "3.7.0" + FLUTTER_VERSION: "3.7.5" # vcpkg version: 2022.05.10 # for multiarch gcc compatibility VCPKG_COMMIT_ID: "14e7bb4ae24616ec54ff6b2f6ef4e8659434ea44" @@ -260,7 +260,7 @@ jobs: job: - { target: x86_64-unknown-linux-gnu, - os: ubuntu-18.04, + os: ubuntu-20.04, extra-build-args: "", } steps: @@ -330,13 +330,13 @@ jobs: - { arch: x86_64, target: aarch64-linux-android, - os: ubuntu-18.04, + os: ubuntu-20.04, extra-build-features: "", } # - { # arch: x86_64, # target: armv7-linux-androideabi, - # os: ubuntu-18.04, + # os: ubuntu-20.04, # extra-build-features: "", # } steps: @@ -907,19 +907,19 @@ jobs: - { arch: x86_64, target: x86_64-unknown-linux-gnu, - os: ubuntu-18.04, + os: ubuntu-20.04, extra-build-features: "", } - { arch: x86_64, target: x86_64-unknown-linux-gnu, - os: ubuntu-18.04, + os: ubuntu-20.04, extra-build-features: "flatpak", } - { arch: x86_64, target: x86_64-unknown-linux-gnu, - os: ubuntu-18.04, + os: ubuntu-20.04, extra-build-features: "appimage", } # - { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true } From 0380fc0c9e6235b86af42d99041a55401ea63e13 Mon Sep 17 00:00:00 2001 From: "Miguel F. G" <116861809+flusheDData@users.noreply.github.com> Date: Tue, 28 Feb 2023 00:50:07 +0100 Subject: [PATCH 31/65] Update es.rs New term added --- src/lang/es.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/es.rs b/src/lang/es.rs index af0da0479..a95d39776 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -456,6 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Reconnect", "Reconectar"), ("Codec", "Códec"), ("Resolution", "Resolución"), - ("No transfers in progress", ""), + ("No transfers in progress", "No hay transferencias en curso"), ].iter().cloned().collect(); } From 48100c9e91ed7ac725e8651f5fbc458c4a71613c Mon Sep 17 00:00:00 2001 From: csf Date: Tue, 28 Feb 2023 11:31:30 +0900 Subject: [PATCH 32/65] 1. add _systemAlertWindow and _enableStartOnBoot options. 2. opt settings_page.dart state variables --- .../android/app/src/main/AndroidManifest.xml | 1 + .../com/carriez/flutter_hbb/MainActivity.kt | 20 ++++ .../kotlin/com/carriez/flutter_hbb/common.kt | 9 +- flutter/lib/consts.dart | 6 +- flutter/lib/mobile/pages/settings_page.dart | 101 ++++++++++++++---- 5 files changed, 116 insertions(+), 21 deletions(-) diff --git a/flutter/android/app/src/main/AndroidManifest.xml b/flutter/android/app/src/main/AndroidManifest.xml index 6f646b913..b3c655917 100644 --- a/flutter/android/app/src/main/AndroidManifest.xml +++ b/flutter/android/app/src/main/AndroidManifest.xml @@ -12,6 +12,7 @@ + { + val prefs = getSharedPreferences(KEY_SHARED_PREFERENCES, MODE_PRIVATE) + result.success(prefs.getBoolean(KEY_START_ON_BOOT_OPT, false)) + } + SET_START_ON_BOOT_OPT -> { + try { + if (call.arguments is Boolean) { + val prefs = getSharedPreferences(KEY_SHARED_PREFERENCES, MODE_PRIVATE) + val edit = prefs.edit() + edit.putBoolean(KEY_START_ON_BOOT_OPT, call.arguments as Boolean) + edit.apply() + result.success(true) + } else { + result.success(false) + } + } finally { + result.success(false) + } + } else -> { result.error("-1", "No such method", null) } diff --git a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt index 0bc6c1c28..2d53ea010 100644 --- a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt +++ b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt @@ -37,9 +37,14 @@ const val REQ_REQUEST_MEDIA_PROJECTION = 201 const val RES_FAILED = -100 // Flutter channel -const val START_ACTION = "start_action"; -const val IGNORE_BATTERY_OPTIMIZATIONS = "ignore_battery_optimizations"; +const val START_ACTION = "start_action" +const val GET_START_ON_BOOT_OPT = "get_start_on_boot_opt" +const val SET_START_ON_BOOT_OPT = "set_start_on_boot_opt" +const val IGNORE_BATTERY_OPTIMIZATIONS = "ignore_battery_optimizations" + +const val KEY_SHARED_PREFERENCES = "KEY_SHARED_PREFERENCES" +const val KEY_START_ON_BOOT_OPT = "KEY_START_ON_BOOT_OPT" @SuppressLint("ConstantLocale") val LOCAL_NAME = Locale.getDefault().toString() diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index a0766a874..1dc1c0b5a 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -150,7 +150,11 @@ const kSystemAlertWindow = "android.permission.SYSTEM_ALERT_WINDOW"; const kIgnoreBatteryOptimizations = "ignore_battery_optimizations"; /// Android channel invoke type key -const kStartAction = "start_action"; +class AndroidChannel { + static final kStartAction = "start_action"; + static final kGetStartOnBootOpt = "get_start_on_boot_opt"; + static final kSetStartOnBootOpt = "set_start_on_boot_opt"; +} /// flutter/packages/flutter/lib/src/services/keyboard_key.dart -> _keyLabels /// see [LogicalKeyboardKey.keyLabel] diff --git a/flutter/lib/mobile/pages/settings_page.dart b/flutter/lib/mobile/pages/settings_page.dart index 6bdb7e813..0e160396b 100644 --- a/flutter/lib/mobile/pages/settings_page.dart +++ b/flutter/lib/mobile/pages/settings_page.dart @@ -32,18 +32,21 @@ class SettingsPage extends StatefulWidget implements PageShape { } const url = 'https://rustdesk.com/'; -final _hasIgnoreBattery = androidVersion >= 26; -var _ignoreBatteryOpt = false; -var _enableAbr = false; -var _denyLANDiscovery = false; -var _onlyWhiteList = false; -var _enableDirectIPAccess = false; -var _enableRecordSession = false; -var _autoRecordIncomingSession = false; -var _localIP = ""; -var _directAccessPort = ""; class _SettingsState extends State with WidgetsBindingObserver { + final _hasIgnoreBattery = androidVersion >= 26; + var _ignoreBatteryOpt = false; + var _systemAlertWindow = false; + var _enableStartOnBoot = false; + var _enableAbr = false; + var _denyLANDiscovery = false; + var _onlyWhiteList = false; + var _enableDirectIPAccess = false; + var _enableRecordSession = false; + var _autoRecordIncomingSession = false; + var _localIP = ""; + var _directAccessPort = ""; + @override void initState() { super.initState(); @@ -51,11 +54,35 @@ class _SettingsState extends State with WidgetsBindingObserver { () async { var update = false; + if (_hasIgnoreBattery) { - update = await updateIgnoreBatteryStatus(); + if (await checkAndUpdateIgnoreBatteryStatus()) { + update = true; + } } - final enableAbrRes = await bind.mainGetOption(key: "enable-abr") != "N"; + if (await checkAndUpdateSystemAlertWindow()) { + update = true; + } + + // TODO need input + // start on boot depends on ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS and SYSTEM_ALERT_WINDOW + var enableStartOnBoot = + await gFFI.invokeMethod(AndroidChannel.kGetStartOnBootOpt); + if (enableStartOnBoot) { + if (!canStartOnBoot()) { + enableStartOnBoot = false; + gFFI.invokeMethod(AndroidChannel.kSetStartOnBootOpt, false); + } + } + + if (enableStartOnBoot != _enableStartOnBoot) { + update = true; + _enableStartOnBoot = enableStartOnBoot; + } + + final enableAbrRes = option2bool( + "enable-abr", await bind.mainGetOption(key: "enable-abr")); if (enableAbrRes != _enableAbr) { update = true; _enableAbr = enableAbrRes; @@ -126,14 +153,15 @@ class _SettingsState extends State with WidgetsBindingObserver { void didChangeAppLifecycleState(AppLifecycleState state) { if (state == AppLifecycleState.resumed) { () async { - if (await updateIgnoreBatteryStatus()) { + if (await checkAndUpdateIgnoreBatteryStatus() || + await checkAndUpdateSystemAlertWindow()) { setState(() {}); } }(); } } - Future updateIgnoreBatteryStatus() async { + Future checkAndUpdateIgnoreBatteryStatus() async { final res = await AndroidPermissionManager.check(kIgnoreBatteryOptimizations); if (_ignoreBatteryOpt != res) { @@ -144,6 +172,16 @@ class _SettingsState extends State with WidgetsBindingObserver { } } + Future checkAndUpdateSystemAlertWindow() async { + final res = await AndroidPermissionManager.check(kSystemAlertWindow); + if (_systemAlertWindow != res) { + _systemAlertWindow = res; + return true; + } else { + return false; + } + } + @override Widget build(BuildContext context) { Provider.of(context); @@ -267,8 +305,8 @@ class _SettingsState extends State with WidgetsBindingObserver { ]), onToggle: (v) async { if (v) { - gFFI.invokeMethod( - kStartAction, kActionRequestIgnoreBatteryOptimizations); + gFFI.invokeMethod(AndroidChannel.kStartAction, + kActionRequestIgnoreBatteryOptimizations); } else { final res = await gFFI.dialogManager .show((setState, close) => CustomAlertDialog( @@ -285,12 +323,27 @@ class _SettingsState extends State with WidgetsBindingObserver { ], )); if (res == true) { - gFFI.invokeMethod( - kStartAction, kActionApplicationDetailsSettings); + gFFI.invokeMethod(AndroidChannel.kStartAction, + kActionApplicationDetailsSettings); } } })); } + enhancementsTiles.add(SettingsTile.switchTile( + initialValue: _enableStartOnBoot, + title: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text("$translate('Start on Boot') (beta)"), + Text( + '* ${translate('Start the screen recording service on boot, which requires special permissions')}', + style: Theme.of(context).textTheme.bodySmall), + ]), + onToggle: (v) async { + if (v) { + // TODO + } else { + gFFI.invokeMethod(AndroidChannel.kSetStartOnBootOpt, false); + } + })); return SettingsList( sections: [ @@ -391,6 +444,18 @@ class _SettingsState extends State with WidgetsBindingObserver { ], ); } + + bool canStartOnBoot() { + // TODO need input + // start on boot depends on ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS and SYSTEM_ALERT_WINDOW + if (_hasIgnoreBattery && !_ignoreBatteryOpt) { + return false; + } + if (!_systemAlertWindow) { + return false; + } + return true; + } } void showServerSettings(OverlayDialogManager dialogManager) async { From eebe3448786b1704d9be4c2b08e9d7de619511da Mon Sep 17 00:00:00 2001 From: Andi Ariffin Date: Tue, 28 Feb 2023 11:57:39 +0700 Subject: [PATCH 33/65] Fix typos causing gen_js_from_hbb.py to fail --- src/lang/en.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lang/en.rs b/src/lang/en.rs index 3e87cd661..250530013 100644 --- a/src/lang/en.rs +++ b/src/lang/en.rs @@ -39,8 +39,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("verification_tip", "A new device has been detected, and a verification code has been sent to the registered email address, enter the verification code to continue logging in."), ("software_render_tip", "If you have an Nvidia graphics card and the remote window closes immediately after connecting, installing the nouveau driver and choosing to use software rendering may help. A software restart is required."), ("config_input", "In order to control remote desktop with keyboard, you need to grant RustDesk \"Input Monitoring\" permissions."), - ("request_elevation_tip","You can also request elevation if there is someone on the remote side."), - ("wait_accept_uac_tip","Please wait for the remote user to accept the UAC dialog."), + ("request_elevation_tip", "You can also request elevation if there is someone on the remote side."), + ("wait_accept_uac_tip", "Please wait for the remote user to accept the UAC dialog."), ("still_click_uac_tip", "Still requires the remote user to click OK on the UAC window of running RustDesk."), ("config_microphone", "In order to speak remotely, you need to grant RustDesk \"Record Audio\" permissions."), ("relay_hint_tip", "It may not be possible to connect directly, you can try to connect via relay. \nIn addition, if you want to use relay on your first try, you can add the \"/r\" suffix to the ID, or select the option \"Always connect via relay\" in the peer card."), From 6bd26ef3987db43cadfecb19267262c8d5cf50f1 Mon Sep 17 00:00:00 2001 From: Kingtous Date: Tue, 28 Feb 2023 13:23:27 +0800 Subject: [PATCH 34/65] fix: linux canvas offset --- flutter/lib/models/model.dart | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index fd97b1e5c..cea6785fc 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -731,8 +731,15 @@ class CanvasModel with ChangeNotifier { Size getSize() { final size = MediaQueryData.fromWindow(ui.window).size; // If minimized, w or h may be negative here. - double w = size.width - windowBorderWidth * 2; - double h = size.height - tabBarHeight - windowBorderWidth * 2; + double w = size.width - + windowBorderWidth * 2 - + kDragToResizeAreaPadding.left - + kDragToResizeAreaPadding.right; + double h = size.height - + tabBarHeight - + windowBorderWidth * 2 - + kDragToResizeAreaPadding.top - + kDragToResizeAreaPadding.bottom; return Size(w < 0 ? 0 : w, h < 0 ? 0 : h); } From e26707e55277cfb82644e8b471466ab0fde65994 Mon Sep 17 00:00:00 2001 From: sjpark Date: Tue, 28 Feb 2023 15:47:44 +0900 Subject: [PATCH 35/65] delete unused patch --- Cargo.toml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d768005fe..f93f776a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -166,8 +166,3 @@ panic = 'abort' strip = true #opt-level = 'z' # only have smaller size after strip rpath = true - -[patch."https://github.com/fufesou/rdev"] -#rdev = { path = "../rdev" } -rdev = { git = "https://github.com/sj6219/rdev", branch = "sigma" } - From 8703d23277e66b970d52bb43d7e7d360051e47e4 Mon Sep 17 00:00:00 2001 From: fufesou Date: Tue, 28 Feb 2023 14:50:51 +0800 Subject: [PATCH 36/65] refact canvas position and size Signed-off-by: fufesou --- .../lib/desktop/widgets/remote_menubar.dart | 15 ++++++------ flutter/lib/models/input_model.dart | 4 ++-- flutter/lib/models/model.dart | 24 ++++++++++--------- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/flutter/lib/desktop/widgets/remote_menubar.dart b/flutter/lib/desktop/widgets/remote_menubar.dart index c27546d9f..4b0215703 100644 --- a/flutter/lib/desktop/widgets/remote_menubar.dart +++ b/flutter/lib/desktop/widgets/remote_menubar.dart @@ -953,12 +953,13 @@ class _DisplayMenuState extends State<_DisplayMenu> { final canvasModel = widget.ffi.canvasModel; final width = (canvasModel.getDisplayWidth() * canvasModel.scale + - canvasModel.windowBorderWidth * 2) * + CanvasModel.leftToEdge + + CanvasModel.rightToEdge) * scale + magicWidth; final height = (canvasModel.getDisplayHeight() * canvasModel.scale + - canvasModel.tabBarHeight + - canvasModel.windowBorderWidth * 2) * + CanvasModel.topToEdge + + CanvasModel.bottomToEdge) * scale + magicHeight; double left = wndRect.left + (wndRect.width - width) / 2; @@ -1027,10 +1028,10 @@ class _DisplayMenuState extends State<_DisplayMenu> { final canvasModel = widget.ffi.canvasModel; final displayWidth = canvasModel.getDisplayWidth(); final displayHeight = canvasModel.getDisplayHeight(); - final requiredWidth = displayWidth + - (canvasModel.tabBarHeight + canvasModel.windowBorderWidth * 2); - final requiredHeight = displayHeight + - (canvasModel.tabBarHeight + canvasModel.windowBorderWidth * 2); + final requiredWidth = + CanvasModel.leftToEdge + displayWidth + CanvasModel.rightToEdge; + final requiredHeight = + CanvasModel.topToEdge + displayHeight + CanvasModel.bottomToEdge; return selfWidth > (requiredWidth * scale) && selfHeight > (requiredHeight * scale); } diff --git a/flutter/lib/models/input_model.dart b/flutter/lib/models/input_model.dart index b91453138..8c6a89377 100644 --- a/flutter/lib/models/input_model.dart +++ b/flutter/lib/models/input_model.dart @@ -459,8 +459,8 @@ class InputModel { } evt['type'] = type; if (isDesktop) { - y = y - stateGlobal.tabBarHeight - stateGlobal.windowBorderWidth.value; - x -= stateGlobal.windowBorderWidth.value; + y -= CanvasModel.topToEdge; + x -= CanvasModel.leftToEdge; } final canvasModel = parent.target!.canvasModel; final nearThr = 3; diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index cea6785fc..6def57462 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -727,19 +727,21 @@ class CanvasModel with ChangeNotifier { double get scrollX => _scrollX; double get scrollY => _scrollY; + static double get leftToEdge => + windowBorderWidth + kDragToResizeAreaPadding.left; + static double get rightToEdge => + windowBorderWidth + kDragToResizeAreaPadding.right; + static double get topToEdge => + tabBarHeight + windowBorderWidth + kDragToResizeAreaPadding.top; + static double get bottomToEdge => + windowBorderWidth + kDragToResizeAreaPadding.bottom; + updateViewStyle() async { Size getSize() { final size = MediaQueryData.fromWindow(ui.window).size; // If minimized, w or h may be negative here. - double w = size.width - - windowBorderWidth * 2 - - kDragToResizeAreaPadding.left - - kDragToResizeAreaPadding.right; - double h = size.height - - tabBarHeight - - windowBorderWidth * 2 - - kDragToResizeAreaPadding.top - - kDragToResizeAreaPadding.bottom; + double w = size.width - leftToEdge - rightToEdge; + double h = size.height - topToEdge - bottomToEdge; return Size(w < 0 ? 0 : w, h < 0 ? 0 : h); } @@ -813,8 +815,8 @@ class CanvasModel with ChangeNotifier { return parent.target?.ffiModel.display.height ?? defaultHeight; } - double get windowBorderWidth => stateGlobal.windowBorderWidth.value; - double get tabBarHeight => stateGlobal.tabBarHeight; + static double get windowBorderWidth => stateGlobal.windowBorderWidth.value; + static double get tabBarHeight => stateGlobal.tabBarHeight; moveDesktopMouse(double x, double y) { if (size.width == 0 || size.height == 0) { From 409da145c3138ff30c8372d9a88ac2842f467a4b Mon Sep 17 00:00:00 2001 From: rustdesk Date: Tue, 28 Feb 2023 15:23:25 +0800 Subject: [PATCH 37/65] add settings page left side to 200 to conform to main page --- flutter/lib/desktop/pages/desktop_setting_page.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index e041b591d..52f64c0e3 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -19,7 +19,7 @@ import 'package:flutter_hbb/desktop/widgets/scroll_wrapper.dart'; import '../../common/widgets/dialog.dart'; import '../../common/widgets/login.dart'; -const double _kTabWidth = 235; +const double _kTabWidth = 200; const double _kTabHeight = 42; const double _kCardFixedWidth = 540; const double _kCardLeftMargin = 15; From 45de6e3f66a7930097f1914aa818eff4091f0db9 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Tue, 28 Feb 2023 15:28:11 +0800 Subject: [PATCH 38/65] update Cargo.lock for new merge --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index a2cdf91a4..8f8895bd5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4656,7 +4656,7 @@ dependencies = [ [[package]] name = "rdev" version = "0.5.0-2" -source = "git+https://github.com/fufesou/rdev#5b9fb5e42117f44e0ce0fe7cf2bddf270c75f1dc" +source = "git+https://github.com/fufesou/rdev#25a99ce71ab42843ad253dd51e6a35e83e87a8a4" dependencies = [ "cocoa", "core-foundation 0.9.3", From f65a40f914225052184d1b1b039a7e1b80aff947 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Tue, 28 Feb 2023 16:21:14 +0800 Subject: [PATCH 39/65] chore: try to enable keyboard for scroll, but behavior is strange on mac, #3428 issue --- flutter/lib/desktop/widgets/scroll_wrapper.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/flutter/lib/desktop/widgets/scroll_wrapper.dart b/flutter/lib/desktop/widgets/scroll_wrapper.dart index 32ed149e5..c5bc3394b 100644 --- a/flutter/lib/desktop/widgets/scroll_wrapper.dart +++ b/flutter/lib/desktop/widgets/scroll_wrapper.dart @@ -14,6 +14,7 @@ class DesktopScrollWrapper extends StatelessWidget { return ImprovedScrolling( scrollController: scrollController, enableCustomMouseWheelScrolling: true, + // enableKeyboardScrolling: true, // strange behavior on mac customMouseWheelScrollConfig: CustomMouseWheelScrollConfig( scrollDuration: kDefaultScrollDuration, scrollCurve: Curves.linearToEaseOut, From 1b396d22879f1143f55080e5f19e5888fd355819 Mon Sep 17 00:00:00 2001 From: Kingtous Date: Tue, 28 Feb 2023 17:25:59 +0800 Subject: [PATCH 40/65] opt: scrollbar in night mode --- flutter/lib/common.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 53a401230..023fe7511 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -217,6 +217,9 @@ class MyTheme { tabBarTheme: const TabBarTheme( labelColor: Colors.white70, ), + scrollbarTheme: ScrollbarThemeData( + thumbColor: MaterialStateProperty.all(Colors.grey[500]) + ), splashColor: Colors.transparent, highlightColor: Colors.transparent, splashFactory: isDesktop ? NoSplash.splashFactory : null, From a974fef1e50e456a592a7ea37a6271829d03567e Mon Sep 17 00:00:00 2001 From: mehdi-song Date: Tue, 28 Feb 2023 13:19:02 +0330 Subject: [PATCH 41/65] Update fa.rs --- src/lang/fa.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lang/fa.rs b/src/lang/fa.rs index 0c31e1531..f76567ee5 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -454,8 +454,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Stop voice call", "توقف تماس صوتی"), ("relay_hint_tip", " را به شناسه اضافه کنید یا گزینه \"همیشه از طریق رله متصل شوید\" را در کارت همتا انتخاب کنید. همچنین، اگر می‌خواهید فوراً از سرور رله استفاده کنید، می‌توانید پسوند \"/r\".\n اتصال مستقیم ممکن است امکان پذیر نباشد. در این صورت می توانید سعی کنید از طریق سرور رله متصل شوید"), ("Reconnect", "اتصال مجدد"), - ("No transfers in progress", ""), - ("Codec", ""), - ("Resolution", ""), + ("No transfers in progress", "هیچ انتقالی در حال انجام نیست"), + ("Codec", "کدک"), + ("Resolution", "وضوح"), ].iter().cloned().collect(); } From 73bc963311475f8433dfede2f292cd6d05d9e9fc Mon Sep 17 00:00:00 2001 From: csf Date: Tue, 28 Feb 2023 19:46:41 +0900 Subject: [PATCH 42/65] add kActionAccessibilitySettings to manage Input Permission --- flutter/lib/common.dart | 5 +++++ flutter/lib/consts.dart | 2 ++ flutter/lib/mobile/pages/settings_page.dart | 4 ++-- flutter/lib/models/server_model.dart | 10 +++------- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 41ac595f2..89b2c1b28 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -926,6 +926,11 @@ class AndroidPermissionManager { return gFFI.invokeMethod("check_permission", type); } + // startActivity goto Android Setting's page to request permission manually by user + static void startAction(String action) { + gFFI.invokeMethod(AndroidChannel.kStartAction, action); + } + static Future request(String type) { if (isDesktop) { return Future.value(true); diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index 1dc1c0b5a..3edafbf62 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -142,6 +142,8 @@ const kActionApplicationDetailsSettings = "android.settings.APPLICATION_DETAILS_SETTINGS"; const kActionRequestIgnoreBatteryOptimizations = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"; +const kActionAccessibilitySettings = "android.settings.ACCESSIBILITY_SETTINGS"; + const kRecordAudio = "android.permission.RECORD_AUDIO"; const kManageExternalStorage = "android.permission.MANAGE_EXTERNAL_STORAGE"; const kSystemAlertWindow = "android.permission.SYSTEM_ALERT_WINDOW"; diff --git a/flutter/lib/mobile/pages/settings_page.dart b/flutter/lib/mobile/pages/settings_page.dart index 0e160396b..397c117f7 100644 --- a/flutter/lib/mobile/pages/settings_page.dart +++ b/flutter/lib/mobile/pages/settings_page.dart @@ -305,7 +305,7 @@ class _SettingsState extends State with WidgetsBindingObserver { ]), onToggle: (v) async { if (v) { - gFFI.invokeMethod(AndroidChannel.kStartAction, + AndroidPermissionManager.startAction( kActionRequestIgnoreBatteryOptimizations); } else { final res = await gFFI.dialogManager @@ -323,7 +323,7 @@ class _SettingsState extends State with WidgetsBindingObserver { ], )); if (res == true) { - gFFI.invokeMethod(AndroidChannel.kStartAction, + AndroidPermissionManager.startAction( kActionApplicationDetailsSettings); } } diff --git a/flutter/lib/models/server_model.dart b/flutter/lib/models/server_model.dart index 433990a2a..7ee23ec40 100644 --- a/flutter/lib/models/server_model.dart +++ b/flutter/lib/models/server_model.dart @@ -234,7 +234,7 @@ class ServerModel with ChangeNotifier { if (!_audioOk && !await AndroidPermissionManager.check(kRecordAudio)) { final res = await AndroidPermissionManager.request(kRecordAudio); if (!res) { - // TODO handle fail + showToast(translate('Failed')); return; } } @@ -250,7 +250,7 @@ class ServerModel with ChangeNotifier { final res = await AndroidPermissionManager.request(kManageExternalStorage); if (!res) { - // TODO handle fail + showToast(translate('Failed')); return; } } @@ -348,10 +348,6 @@ class ServerModel with ChangeNotifier { } } - Future initInput() async { - await parent.target?.invokeMethod("init_input"); - } - Future setPermanentPassword(String newPW) async { await bind.mainSetPermanentPassword(password: newPW); await Future.delayed(Duration(milliseconds: 500)); @@ -689,7 +685,7 @@ String getLoginDialogTag(int id) { showInputWarnAlert(FFI ffi) { ffi.dialogManager.show((setState, close) { submit() { - ffi.serverModel.initInput(); + AndroidPermissionManager.startAction(kActionAccessibilitySettings); close(); } From a071700cc7c77e9fa50bf44341a4e8eb3796d6a9 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Tue, 28 Feb 2023 19:25:14 +0800 Subject: [PATCH 43/65] fix build.py for mac --- build.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.py b/build.py index b30f76f95..8d64553c2 100755 --- a/build.py +++ b/build.py @@ -317,11 +317,11 @@ def build_flutter_dmg(version, features): "cp target/release/liblibrustdesk.dylib target/release/librustdesk.dylib") # ffi_bindgen_function_refactor() # limitations from flutter rust bridge - system2('sed -i "" "s/char \*\*rustdesk_core_main(int \*args_len);//" flutter/macos/Runner/bridge_generated.h') + system2('sed -i "s/char \*\*rustdesk_core_main(int \*args_len);//" flutter/macos/Runner/bridge_generated.h') os.chdir('flutter') system2('flutter build macos --release') system2( - "create-dmg rustdesk.dmg ./build/macos/Build/Products/Release/RustDesk.app") + "create-dmg --volname \"RustDesk Installer\" --window-pos 200 120 --window-size 800 400 --icon-size 100 --app-drop-link 600 185 --icon RustDesk.app 200 190 --hide-extension RustDesk.app rustdesk.dmg ./build/macos/Build/Products/Release/RustDesk.app") os.rename("rustdesk.dmg", f"../rustdesk-{version}.dmg") os.chdir("..") From 60ab29ad6e9ec80b9ce50abb073ac6bc384f8230 Mon Sep 17 00:00:00 2001 From: csf Date: Tue, 28 Feb 2023 21:02:42 +0900 Subject: [PATCH 44/65] 1. use XXPermissions to manage REQUEST_IGNORE_BATTERY_OPTIMIZATIONS. 2. pre-request permission on Start on Boot enabled. --- .../com/carriez/flutter_hbb/MainActivity.kt | 14 +------ .../kotlin/com/carriez/flutter_hbb/common.kt | 17 +++----- flutter/lib/common.dart | 13 ++++--- flutter/lib/consts.dart | 7 +--- flutter/lib/mobile/pages/settings_page.dart | 39 +++++++++++++------ 5 files changed, 43 insertions(+), 47 deletions(-) diff --git a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt index 126e169da..e4b42cf08 100644 --- a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt +++ b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt @@ -18,6 +18,7 @@ import android.provider.Settings import android.util.Log import android.view.WindowManager import androidx.annotation.RequiresApi +import com.hjq.permissions.XXPermissions import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel @@ -76,7 +77,7 @@ class MainActivity : FlutterActivity() { } "check_permission" -> { if (call.arguments is String) { - result.success(checkPermission(context, call.arguments as String)) + result.success(XXPermissions.isGranted(context, call.arguments as String)) } else { result.success(false) } @@ -115,10 +116,6 @@ class MainActivity : FlutterActivity() { ) result.success(true) } - "init_input" -> { - initInput() - result.success(true) - } "stop_input" -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { InputService.ctx?.disableSelf() @@ -177,13 +174,6 @@ class MainActivity : FlutterActivity() { } } - private fun initInput() { - val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS) - if (intent.resolveActivity(packageManager) != null) { - startActivity(intent) - } - } - override fun onResume() { super.onResume() val inputPer = InputService.isOpen diff --git a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt index 2d53ea010..0c34c2223 100644 --- a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt +++ b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt @@ -13,6 +13,7 @@ import android.os.Build import android.os.Handler import android.os.Looper import android.os.PowerManager +import android.provider.Settings import android.provider.Settings.* import androidx.annotation.RequiresApi import androidx.core.content.ContextCompat.getSystemService @@ -41,8 +42,6 @@ const val START_ACTION = "start_action" const val GET_START_ON_BOOT_OPT = "get_start_on_boot_opt" const val SET_START_ON_BOOT_OPT = "set_start_on_boot_opt" -const val IGNORE_BATTERY_OPTIMIZATIONS = "ignore_battery_optimizations" - const val KEY_SHARED_PREFERENCES = "KEY_SHARED_PREFERENCES" const val KEY_START_ON_BOOT_OPT = "KEY_START_ON_BOOT_OPT" @@ -70,21 +69,15 @@ fun requestPermission(context: Context, type: String) { } } -@RequiresApi(Build.VERSION_CODES.M) -fun checkPermission(context: Context, type: String): Boolean { - if (IGNORE_BATTERY_OPTIMIZATIONS == type) { - val pw = context.getSystemService(Context.POWER_SERVICE) as PowerManager - return pw.isIgnoringBatteryOptimizations(context.packageName) - } - return XXPermissions.isGranted(context, type) -} - @RequiresApi(Build.VERSION_CODES.M) fun startAction(context: Context, action: String) { try { context.startActivity(Intent(action).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - data = Uri.parse("package:" + context.packageName) + // don't pass package name when launch ACTION_ACCESSIBILITY_SETTINGS + if (ACTION_ACCESSIBILITY_SETTINGS != action) { + data = Uri.parse("package:" + context.packageName) + } }) } catch (e: Exception) { e.printStackTrace() diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 89b2c1b28..155fcc743 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -931,6 +931,8 @@ class AndroidPermissionManager { gFFI.invokeMethod(AndroidChannel.kStartAction, action); } + /// We use XXPermissions to request permissions, + /// for supported types, see https://github.com/getActivity/XXPermissions/blob/e46caea32a64ad7819df62d448fb1c825481cd28/library/src/main/java/com/hjq/permissions/Permission.java static Future request(String type) { if (isDesktop) { return Future.value(true); @@ -938,17 +940,16 @@ class AndroidPermissionManager { gFFI.invokeMethod("request_permission", type); - // kIgnoreBatteryOptimizations permission doesn't depend on callback result, the result will be checked and updated on page resume - if (type == kIgnoreBatteryOptimizations) { - return Future.value(false); + // clear last task + if (_completer?.isCompleted == false) { + _completer?.complete(false); } + _timer?.cancel(); _current = type; _completer = Completer(); - // timeout - _timer?.cancel(); - _timer = Timer(Duration(seconds: 60), () { + _timer = Timer(Duration(seconds: 120), () { if (_completer == null) return; if (!_completer!.isCompleted) { _completer!.complete(false); diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index 3edafbf62..b075ee76f 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -140,17 +140,14 @@ const kIgnoreDpi = true; /// Android constants const kActionApplicationDetailsSettings = "android.settings.APPLICATION_DETAILS_SETTINGS"; -const kActionRequestIgnoreBatteryOptimizations = - "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"; const kActionAccessibilitySettings = "android.settings.ACCESSIBILITY_SETTINGS"; const kRecordAudio = "android.permission.RECORD_AUDIO"; const kManageExternalStorage = "android.permission.MANAGE_EXTERNAL_STORAGE"; +const kRequestIgnoreBatteryOptimizations = + "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"; const kSystemAlertWindow = "android.permission.SYSTEM_ALERT_WINDOW"; -/// [kIgnoreBatteryOptimizations] not a Android Permission, it is a custom key, used in `ignore battery optimizations` check -const kIgnoreBatteryOptimizations = "ignore_battery_optimizations"; - /// Android channel invoke type key class AndroidChannel { static final kStartAction = "start_action"; diff --git a/flutter/lib/mobile/pages/settings_page.dart b/flutter/lib/mobile/pages/settings_page.dart index 397c117f7..d4887bb58 100644 --- a/flutter/lib/mobile/pages/settings_page.dart +++ b/flutter/lib/mobile/pages/settings_page.dart @@ -65,7 +65,6 @@ class _SettingsState extends State with WidgetsBindingObserver { update = true; } - // TODO need input // start on boot depends on ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS and SYSTEM_ALERT_WINDOW var enableStartOnBoot = await gFFI.invokeMethod(AndroidChannel.kGetStartOnBootOpt); @@ -162,8 +161,8 @@ class _SettingsState extends State with WidgetsBindingObserver { } Future checkAndUpdateIgnoreBatteryStatus() async { - final res = - await AndroidPermissionManager.check(kIgnoreBatteryOptimizations); + final res = await AndroidPermissionManager.check( + kRequestIgnoreBatteryOptimizations); if (_ignoreBatteryOpt != res) { _ignoreBatteryOpt = res; return true; @@ -305,8 +304,8 @@ class _SettingsState extends State with WidgetsBindingObserver { ]), onToggle: (v) async { if (v) { - AndroidPermissionManager.startAction( - kActionRequestIgnoreBatteryOptimizations); + await AndroidPermissionManager.request( + kRequestIgnoreBatteryOptimizations); } else { final res = await gFFI.dialogManager .show((setState, close) => CustomAlertDialog( @@ -332,17 +331,34 @@ class _SettingsState extends State with WidgetsBindingObserver { enhancementsTiles.add(SettingsTile.switchTile( initialValue: _enableStartOnBoot, title: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text("$translate('Start on Boot') (beta)"), + Text("${translate('Start on Boot')} (beta)"), Text( '* ${translate('Start the screen recording service on boot, which requires special permissions')}', style: Theme.of(context).textTheme.bodySmall), ]), - onToggle: (v) async { - if (v) { - // TODO - } else { - gFFI.invokeMethod(AndroidChannel.kSetStartOnBootOpt, false); + onToggle: (toValue) async { + if (toValue) { + // 1. request kIgnoreBatteryOptimizations + if (!await AndroidPermissionManager.check( + kRequestIgnoreBatteryOptimizations)) { + if (!await AndroidPermissionManager.request( + kRequestIgnoreBatteryOptimizations)) { + return; + } + } + + // 2. request kSystemAlertWindow + if (!await AndroidPermissionManager.check(kSystemAlertWindow)) { + if (!await AndroidPermissionManager.request(kSystemAlertWindow)) { + return; + } + } + + // (Optional) 3. request input permission } + setState(() => _enableStartOnBoot = toValue); + + gFFI.invokeMethod(AndroidChannel.kSetStartOnBootOpt, toValue); })); return SettingsList( @@ -446,7 +462,6 @@ class _SettingsState extends State with WidgetsBindingObserver { } bool canStartOnBoot() { - // TODO need input // start on boot depends on ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS and SYSTEM_ALERT_WINDOW if (_hasIgnoreBattery && !_ignoreBatteryOpt) { return false; From fe262abc5d75f1bc92829680314190ca13a7052e Mon Sep 17 00:00:00 2001 From: rustdesk Date: Tue, 28 Feb 2023 20:15:14 +0800 Subject: [PATCH 45/65] remove useless code --- build.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/build.py b/build.py index 8d64553c2..45fe1b132 100755 --- a/build.py +++ b/build.py @@ -315,9 +315,6 @@ def build_flutter_dmg(version, features): # copy dylib system2( "cp target/release/liblibrustdesk.dylib target/release/librustdesk.dylib") - # ffi_bindgen_function_refactor() - # limitations from flutter rust bridge - system2('sed -i "s/char \*\*rustdesk_core_main(int \*args_len);//" flutter/macos/Runner/bridge_generated.h') os.chdir('flutter') system2('flutter build macos --release') system2( From 836249d34cd01277b3d851a62f104cca9c9a600b Mon Sep 17 00:00:00 2001 From: csf Date: Tue, 28 Feb 2023 21:48:40 +0900 Subject: [PATCH 46/65] refactor initFlutterChannel --- .../com/carriez/flutter_hbb/MainActivity.kt | 255 +++++++++--------- .../kotlin/com/carriez/flutter_hbb/common.kt | 2 - 2 files changed, 125 insertions(+), 132 deletions(-) diff --git a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt index e4b42cf08..be8c857ce 100644 --- a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt +++ b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt @@ -13,8 +13,6 @@ import android.content.Intent import android.content.ServiceConnection import android.os.Build import android.os.IBinder -import android.preference.PreferenceManager -import android.provider.Settings import android.util.Log import android.view.WindowManager import androidx.annotation.RequiresApi @@ -44,134 +42,8 @@ class MainActivity : FlutterActivity() { flutterMethodChannel = MethodChannel( flutterEngine.dartExecutor.binaryMessenger, channelTag - ).apply { - // make sure result is set, otherwise flutter will await forever - setMethodCallHandler { call, result -> - when (call.method) { - "init_service" -> { - Intent(activity, MainService::class.java).also { - bindService(it, serviceConnection, Context.BIND_AUTO_CREATE) - } - if (MainService.isReady) { - result.success(false) - return@setMethodCallHandler - } - requestMediaProjection() - result.success(true) - } - "start_capture" -> { - mainService?.let { - result.success(it.startCapture()) - } ?: let { - result.success(false) - } - } - "stop_service" -> { - Log.d(logTag, "Stop service") - mainService?.let { - it.destroy() - result.success(true) - } ?: let { - result.success(false) - } - } - "check_permission" -> { - if (call.arguments is String) { - result.success(XXPermissions.isGranted(context, call.arguments as String)) - } else { - result.success(false) - } - } - "request_permission" -> { - if (call.arguments is String) { - requestPermission(context, call.arguments as String) - result.success(true) - } else { - result.success(false) - } - } - START_ACTION -> { - if (call.arguments is String) { - startAction(context, call.arguments as String) - result.success(true) - } else { - result.success(false) - } - } - "check_video_permission" -> { - mainService?.let { - result.success(it.checkMediaPermission()) - } ?: let { - result.success(false) - } - } - "check_service" -> { - flutterMethodChannel.invokeMethod( - "on_state_changed", - mapOf("name" to "input", "value" to InputService.isOpen.toString()) - ) - flutterMethodChannel.invokeMethod( - "on_state_changed", - mapOf("name" to "media", "value" to MainService.isReady.toString()) - ) - result.success(true) - } - "stop_input" -> { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - InputService.ctx?.disableSelf() - } - InputService.ctx = null - flutterMethodChannel.invokeMethod( - "on_state_changed", - mapOf("name" to "input", "value" to InputService.isOpen.toString()) - ) - result.success(true) - } - "cancel_notification" -> { - try { - val id = call.arguments as Int - mainService?.cancelNotification(id) - } finally { - result.success(true) - } - } - "enable_soft_keyboard" -> { - // https://blog.csdn.net/hanye2020/article/details/105553780 - try { - if (call.arguments as Boolean) { - window.clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) - } else { - window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) - } - } finally { - result.success(true) - } - } - GET_START_ON_BOOT_OPT -> { - val prefs = getSharedPreferences(KEY_SHARED_PREFERENCES, MODE_PRIVATE) - result.success(prefs.getBoolean(KEY_START_ON_BOOT_OPT, false)) - } - SET_START_ON_BOOT_OPT -> { - try { - if (call.arguments is Boolean) { - val prefs = getSharedPreferences(KEY_SHARED_PREFERENCES, MODE_PRIVATE) - val edit = prefs.edit() - edit.putBoolean(KEY_START_ON_BOOT_OPT, call.arguments as Boolean) - edit.apply() - result.success(true) - } else { - result.success(false) - } - } finally { - result.success(false) - } - } - else -> { - result.error("-1", "No such method", null) - } - } - } - } + ) + initFlutterChannel(flutterMethodChannel) } override fun onResume() { @@ -219,4 +91,127 @@ class MainActivity : FlutterActivity() { mainService = null } } + + private fun initFlutterChannel(flutterMethodChannel: MethodChannel) { + flutterMethodChannel.setMethodCallHandler { call, result -> + // make sure result will be invoked, otherwise flutter will await forever + when (call.method) { + "init_service" -> { + Intent(activity, MainService::class.java).also { + bindService(it, serviceConnection, Context.BIND_AUTO_CREATE) + } + if (MainService.isReady) { + result.success(false) + return@setMethodCallHandler + } + requestMediaProjection() + result.success(true) + } + "start_capture" -> { + mainService?.let { + result.success(it.startCapture()) + } ?: let { + result.success(false) + } + } + "stop_service" -> { + Log.d(logTag, "Stop service") + mainService?.let { + it.destroy() + result.success(true) + } ?: let { + result.success(false) + } + } + "check_permission" -> { + if (call.arguments is String) { + result.success(XXPermissions.isGranted(context, call.arguments as String)) + } else { + result.success(false) + } + } + "request_permission" -> { + if (call.arguments is String) { + requestPermission(context, call.arguments as String) + result.success(true) + } else { + result.success(false) + } + } + START_ACTION -> { + if (call.arguments is String) { + startAction(context, call.arguments as String) + result.success(true) + } else { + result.success(false) + } + } + "check_video_permission" -> { + mainService?.let { + result.success(it.checkMediaPermission()) + } ?: let { + result.success(false) + } + } + "check_service" -> { + Companion.flutterMethodChannel.invokeMethod( + "on_state_changed", + mapOf("name" to "input", "value" to InputService.isOpen.toString()) + ) + Companion.flutterMethodChannel.invokeMethod( + "on_state_changed", + mapOf("name" to "media", "value" to MainService.isReady.toString()) + ) + result.success(true) + } + "stop_input" -> { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + InputService.ctx?.disableSelf() + } + InputService.ctx = null + Companion.flutterMethodChannel.invokeMethod( + "on_state_changed", + mapOf("name" to "input", "value" to InputService.isOpen.toString()) + ) + result.success(true) + } + "cancel_notification" -> { + if (call.arguments is Int) { + val id = call.arguments as Int + mainService?.cancelNotification(id) + } else { + result.success(true) + } + } + "enable_soft_keyboard" -> { + // https://blog.csdn.net/hanye2020/article/details/105553780 + if (call.arguments as Boolean) { + window.clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) + } else { + window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) + } + result.success(true) + + } + GET_START_ON_BOOT_OPT -> { + val prefs = getSharedPreferences(KEY_SHARED_PREFERENCES, MODE_PRIVATE) + result.success(prefs.getBoolean(KEY_START_ON_BOOT_OPT, false)) + } + SET_START_ON_BOOT_OPT -> { + if (call.arguments is Boolean) { + val prefs = getSharedPreferences(KEY_SHARED_PREFERENCES, MODE_PRIVATE) + val edit = prefs.edit() + edit.putBoolean(KEY_START_ON_BOOT_OPT, call.arguments as Boolean) + edit.apply() + result.success(true) + } else { + result.success(false) + } + } + else -> { + result.error("-1", "No such method", null) + } + } + } + } } diff --git a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt index 0c34c2223..6970fd137 100644 --- a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt +++ b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt @@ -53,7 +53,6 @@ data class Info( var width: Int, var height: Int, var scale: Int, var dpi: Int ) -@RequiresApi(Build.VERSION_CODES.M) fun requestPermission(context: Context, type: String) { XXPermissions.with(context) .permission(type) @@ -69,7 +68,6 @@ fun requestPermission(context: Context, type: String) { } } -@RequiresApi(Build.VERSION_CODES.M) fun startAction(context: Context, action: String) { try { context.startActivity(Intent(action).apply { From 660d6ff2302e4ad3a3a4091e267a066eef620693 Mon Sep 17 00:00:00 2001 From: csf Date: Tue, 28 Feb 2023 22:26:47 +0900 Subject: [PATCH 47/65] 1. fix check boot on start opt. 2. fix late var flutterMethodChannel --- .../com/carriez/flutter_hbb/BootReceiver.kt | 16 +++++++++++++ .../com/carriez/flutter_hbb/MainActivity.kt | 14 +++++------ .../com/carriez/flutter_hbb/MainService.kt | 4 ++-- .../kotlin/com/carriez/flutter_hbb/common.kt | 2 +- flutter/lib/mobile/pages/settings_page.dart | 24 ++++++++++--------- 5 files changed, 39 insertions(+), 21 deletions(-) diff --git a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/BootReceiver.kt b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/BootReceiver.kt index a49dcc326..8f6767e58 100644 --- a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/BootReceiver.kt +++ b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/BootReceiver.kt @@ -1,11 +1,15 @@ package com.carriez.flutter_hbb +import android.Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS +import android.Manifest.permission.SYSTEM_ALERT_WINDOW import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.os.Build import android.util.Log import android.widget.Toast +import com.hjq.permissions.XXPermissions +import io.flutter.embedding.android.FlutterActivity const val DEBUG_BOOT_COMPLETED = "com.carriez.flutter_hbb.DEBUG_BOOT_COMPLETED" @@ -16,6 +20,18 @@ class BootReceiver : BroadcastReceiver() { Log.d(logTag, "onReceive ${intent.action}") if (Intent.ACTION_BOOT_COMPLETED == intent.action || DEBUG_BOOT_COMPLETED == intent.action) { + // check SharedPreferences config + val prefs = context.getSharedPreferences(KEY_SHARED_PREFERENCES, FlutterActivity.MODE_PRIVATE) + if (!prefs.getBoolean(KEY_START_ON_BOOT_OPT, false)) { + Log.d(logTag, "KEY_START_ON_BOOT_OPT is false") + return + } + // check pre-permission + if (!XXPermissions.isGranted(context, REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, SYSTEM_ALERT_WINDOW)){ + Log.d(logTag, "REQUEST_IGNORE_BATTERY_OPTIMIZATIONS or SYSTEM_ALERT_WINDOW is not granted") + return + } + val it = Intent(context, MainService::class.java).apply { action = ACT_INIT_MEDIA_PROJECTION_AND_SERVICE } diff --git a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt index be8c857ce..79fb60790 100644 --- a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt +++ b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt @@ -24,7 +24,7 @@ import io.flutter.plugin.common.MethodChannel class MainActivity : FlutterActivity() { companion object { - lateinit var flutterMethodChannel: MethodChannel + var flutterMethodChannel: MethodChannel? = null } private val channelTag = "mChannel" @@ -43,14 +43,14 @@ class MainActivity : FlutterActivity() { flutterEngine.dartExecutor.binaryMessenger, channelTag ) - initFlutterChannel(flutterMethodChannel) + initFlutterChannel(flutterMethodChannel!!) } override fun onResume() { super.onResume() val inputPer = InputService.isOpen activity.runOnUiThread { - flutterMethodChannel.invokeMethod( + flutterMethodChannel?.invokeMethod( "on_state_changed", mapOf("name" to "input", "value" to inputPer.toString()) ) @@ -67,7 +67,7 @@ class MainActivity : FlutterActivity() { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == REQ_INVOKE_PERMISSION_ACTIVITY_MEDIA_PROJECTION && resultCode == RES_FAILED) { - flutterMethodChannel.invokeMethod("on_media_projection_canceled", null) + flutterMethodChannel?.invokeMethod("on_media_projection_canceled", null) } } @@ -154,11 +154,11 @@ class MainActivity : FlutterActivity() { } } "check_service" -> { - Companion.flutterMethodChannel.invokeMethod( + Companion.flutterMethodChannel?.invokeMethod( "on_state_changed", mapOf("name" to "input", "value" to InputService.isOpen.toString()) ) - Companion.flutterMethodChannel.invokeMethod( + Companion.flutterMethodChannel?.invokeMethod( "on_state_changed", mapOf("name" to "media", "value" to MainService.isReady.toString()) ) @@ -169,7 +169,7 @@ class MainActivity : FlutterActivity() { InputService.ctx?.disableSelf() } InputService.ctx = null - Companion.flutterMethodChannel.invokeMethod( + Companion.flutterMethodChannel?.invokeMethod( "on_state_changed", mapOf("name" to "input", "value" to InputService.isOpen.toString()) ) diff --git a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt index e28311964..e323d2951 100644 --- a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt +++ b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt @@ -409,13 +409,13 @@ class MainService : Service() { fun checkMediaPermission(): Boolean { Handler(Looper.getMainLooper()).post { - MainActivity.flutterMethodChannel.invokeMethod( + MainActivity.flutterMethodChannel?.invokeMethod( "on_state_changed", mapOf("name" to "media", "value" to isReady.toString()) ) } Handler(Looper.getMainLooper()).post { - MainActivity.flutterMethodChannel.invokeMethod( + MainActivity.flutterMethodChannel?.invokeMethod( "on_state_changed", mapOf("name" to "input", "value" to InputService.isOpen.toString()) ) diff --git a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt index 6970fd137..bd91d582c 100644 --- a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt +++ b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt @@ -59,7 +59,7 @@ fun requestPermission(context: Context, type: String) { .request { _, all -> if (all) { Handler(Looper.getMainLooper()).post { - MainActivity.flutterMethodChannel.invokeMethod( + MainActivity.flutterMethodChannel?.invokeMethod( "on_android_permission_result", mapOf("type" to type, "result" to all) ) diff --git a/flutter/lib/mobile/pages/settings_page.dart b/flutter/lib/mobile/pages/settings_page.dart index d4887bb58..e54f66ffb 100644 --- a/flutter/lib/mobile/pages/settings_page.dart +++ b/flutter/lib/mobile/pages/settings_page.dart @@ -36,7 +36,6 @@ const url = 'https://rustdesk.com/'; class _SettingsState extends State with WidgetsBindingObserver { final _hasIgnoreBattery = androidVersion >= 26; var _ignoreBatteryOpt = false; - var _systemAlertWindow = false; var _enableStartOnBoot = false; var _enableAbr = false; var _denyLANDiscovery = false; @@ -61,7 +60,7 @@ class _SettingsState extends State with WidgetsBindingObserver { } } - if (await checkAndUpdateSystemAlertWindow()) { + if (await checkAndUpdateStartOnBoot()) { update = true; } @@ -69,7 +68,7 @@ class _SettingsState extends State with WidgetsBindingObserver { var enableStartOnBoot = await gFFI.invokeMethod(AndroidChannel.kGetStartOnBootOpt); if (enableStartOnBoot) { - if (!canStartOnBoot()) { + if (!await canStartOnBoot()) { enableStartOnBoot = false; gFFI.invokeMethod(AndroidChannel.kSetStartOnBootOpt, false); } @@ -152,8 +151,9 @@ class _SettingsState extends State with WidgetsBindingObserver { void didChangeAppLifecycleState(AppLifecycleState state) { if (state == AppLifecycleState.resumed) { () async { - if (await checkAndUpdateIgnoreBatteryStatus() || - await checkAndUpdateSystemAlertWindow()) { + final ibs = await checkAndUpdateIgnoreBatteryStatus(); + final sob = await checkAndUpdateStartOnBoot(); + if (ibs || sob) { setState(() {}); } }(); @@ -171,10 +171,12 @@ class _SettingsState extends State with WidgetsBindingObserver { } } - Future checkAndUpdateSystemAlertWindow() async { - final res = await AndroidPermissionManager.check(kSystemAlertWindow); - if (_systemAlertWindow != res) { - _systemAlertWindow = res; + Future checkAndUpdateStartOnBoot() async { + if (!await canStartOnBoot() && _enableStartOnBoot) { + _enableStartOnBoot = false; + debugPrint( + "checkAndUpdateStartOnBoot and set _enableStartOnBoot -> false"); + gFFI.invokeMethod(AndroidChannel.kSetStartOnBootOpt, false); return true; } else { return false; @@ -461,12 +463,12 @@ class _SettingsState extends State with WidgetsBindingObserver { ); } - bool canStartOnBoot() { + Future canStartOnBoot() async { // start on boot depends on ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS and SYSTEM_ALERT_WINDOW if (_hasIgnoreBattery && !_ignoreBatteryOpt) { return false; } - if (!_systemAlertWindow) { + if (!await AndroidPermissionManager.check(kSystemAlertWindow)) { return false; } return true; From be2fa3e4443c3a12af5bc3541757878ce1389232 Mon Sep 17 00:00:00 2001 From: csf Date: Tue, 28 Feb 2023 22:32:51 +0900 Subject: [PATCH 48/65] fix restart service crash --- .../app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt index e323d2951..6b6169c61 100644 --- a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt +++ b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt @@ -278,6 +278,7 @@ class MainService : Service() { Log.d("whichService", "this service: ${Thread.currentThread()}") super.onStartCommand(intent, flags, startId) if (intent?.action == ACT_INIT_MEDIA_PROJECTION_AND_SERVICE) { + createForegroundNotification() Log.d(logTag, "service starting: ${startId}:${Thread.currentThread()}") val mediaProjectionManager = getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager From 20c7075ddb06c102b70e780017e144c24bf8779e Mon Sep 17 00:00:00 2001 From: fufesou Date: Tue, 28 Feb 2023 15:30:46 +0800 Subject: [PATCH 49/65] mobile, canvas size Signed-off-by: fufesou --- flutter/lib/models/input_model.dart | 6 ++---- flutter/lib/models/model.dart | 20 ++++++++++++-------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/flutter/lib/models/input_model.dart b/flutter/lib/models/input_model.dart index 8c6a89377..df9ad2585 100644 --- a/flutter/lib/models/input_model.dart +++ b/flutter/lib/models/input_model.dart @@ -458,10 +458,8 @@ class InputModel { return; } evt['type'] = type; - if (isDesktop) { - y -= CanvasModel.topToEdge; - x -= CanvasModel.leftToEdge; - } + y -= CanvasModel.topToEdge; + x -= CanvasModel.leftToEdge; final canvasModel = parent.target!.canvasModel; final nearThr = 3; var nearRight = (canvasModel.size.width - x) < nearThr; diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 6def57462..802a18a52 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -727,14 +727,18 @@ class CanvasModel with ChangeNotifier { double get scrollX => _scrollX; double get scrollY => _scrollY; - static double get leftToEdge => - windowBorderWidth + kDragToResizeAreaPadding.left; - static double get rightToEdge => - windowBorderWidth + kDragToResizeAreaPadding.right; - static double get topToEdge => - tabBarHeight + windowBorderWidth + kDragToResizeAreaPadding.top; - static double get bottomToEdge => - windowBorderWidth + kDragToResizeAreaPadding.bottom; + static double get leftToEdge => (isDesktop || isWebDesktop) + ? windowBorderWidth + kDragToResizeAreaPadding.left + : 0; + static double get rightToEdge => (isDesktop || isWebDesktop) + ? windowBorderWidth + kDragToResizeAreaPadding.right + : 0; + static double get topToEdge => (isDesktop || isWebDesktop) + ? tabBarHeight + windowBorderWidth + kDragToResizeAreaPadding.top + : 0; + static double get bottomToEdge => (isDesktop || isWebDesktop) + ? windowBorderWidth + kDragToResizeAreaPadding.bottom + : 0; updateViewStyle() async { Size getSize() { From 5375c98e25bcd1d4a7c51d6fcdcb70482312fcda Mon Sep 17 00:00:00 2001 From: rustdesk Date: Tue, 28 Feb 2023 23:04:15 +0800 Subject: [PATCH 50/65] to make macos debug can be run directly without flutter run to skip "mapped file has no Team ID and is not a platform binary (signed with custom identity or adhoc" issue --- flutter/macos/Runner.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/macos/Runner.xcodeproj/project.pbxproj b/flutter/macos/Runner.xcodeproj/project.pbxproj index 0019335ef..c73e666c7 100644 --- a/flutter/macos/Runner.xcodeproj/project.pbxproj +++ b/flutter/macos/Runner.xcodeproj/project.pbxproj @@ -487,7 +487,7 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_IDENTITY = "Apple Development"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; From f26088765e31e7da255633ba717913e86a699978 Mon Sep 17 00:00:00 2001 From: csf Date: Wed, 1 Mar 2023 00:05:06 +0900 Subject: [PATCH 51/65] 1. sync from flutter and pass app_dir from MainService.kt to backend server when app start on boot. 2. add start_service when start on boot. --- .../com/carriez/flutter_hbb/BootReceiver.kt | 1 + .../com/carriez/flutter_hbb/MainActivity.kt | 13 +++++++++++-- .../com/carriez/flutter_hbb/MainService.kt | 18 ++++++++++++++++-- .../kotlin/com/carriez/flutter_hbb/common.kt | 3 +++ flutter/lib/consts.dart | 1 + flutter/lib/main.dart | 1 + flutter/lib/models/native_model.dart | 10 +++++++--- src/flutter_ffi.rs | 18 ++++++++++++++++-- 8 files changed, 56 insertions(+), 9 deletions(-) diff --git a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/BootReceiver.kt b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/BootReceiver.kt index 8f6767e58..71bbba754 100644 --- a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/BootReceiver.kt +++ b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/BootReceiver.kt @@ -34,6 +34,7 @@ class BootReceiver : BroadcastReceiver() { val it = Intent(context, MainService::class.java).apply { action = ACT_INIT_MEDIA_PROJECTION_AND_SERVICE + putExtra(EXT_INIT_FROM_BOOT, true) } Toast.makeText(context, "RustDesk is Open", Toast.LENGTH_LONG).show() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { diff --git a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt index 79fb60790..52a5ff75e 100644 --- a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt +++ b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt @@ -15,7 +15,6 @@ import android.os.Build import android.os.IBinder import android.util.Log import android.view.WindowManager -import androidx.annotation.RequiresApi import com.hjq.permissions.XXPermissions import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine @@ -31,7 +30,6 @@ class MainActivity : FlutterActivity() { private val logTag = "mMainActivity" private var mainService: MainService? = null - @RequiresApi(Build.VERSION_CODES.M) override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) if (MainService.isReady) { @@ -208,6 +206,17 @@ class MainActivity : FlutterActivity() { result.success(false) } } + SYNC_APP_DIR_CONFIG_PATH -> { + if (call.arguments is String) { + val prefs = getSharedPreferences(KEY_SHARED_PREFERENCES, MODE_PRIVATE) + val edit = prefs.edit() + edit.putString(KEY_APP_DIR_CONFIG_PATH, call.arguments as String) + edit.apply() + result.success(true) + } else { + result.success(false) + } + } else -> { result.error("-1", "No such method", null) } diff --git a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt index 6b6169c61..fa7440c8d 100644 --- a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt +++ b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt @@ -35,6 +35,7 @@ import androidx.annotation.RequiresApi import androidx.core.app.ActivityCompat import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat +import io.flutter.embedding.android.FlutterActivity import java.util.concurrent.Executors import kotlin.concurrent.thread import org.json.JSONException @@ -143,7 +144,11 @@ class MainService : Service() { // jvm call rust private external fun init(ctx: Context) - private external fun startServer() + + /// When app start on boot, app_dir will not be passed from flutter + /// so pass a app_dir here to rust server + private external fun startServer(app_dir: String) + private external fun startService() private external fun onVideoFrameUpdate(buf: ByteBuffer) private external fun onAudioFrameUpdate(buf: ByteBuffer) private external fun translateLocale(localeName: String, input: String): String @@ -199,7 +204,12 @@ class MainService : Service() { } updateScreenInfo(resources.configuration.orientation) initNotification() - startServer() + + // keep the config dir same with flutter + val prefs = applicationContext.getSharedPreferences(KEY_SHARED_PREFERENCES, FlutterActivity.MODE_PRIVATE) + val configPath = prefs.getString(KEY_APP_DIR_CONFIG_PATH, "") ?: "" + startServer(configPath) + createForegroundNotification() } @@ -279,6 +289,10 @@ class MainService : Service() { super.onStartCommand(intent, flags, startId) if (intent?.action == ACT_INIT_MEDIA_PROJECTION_AND_SERVICE) { createForegroundNotification() + + if (intent.getBooleanExtra(EXT_INIT_FROM_BOOT, false)) { + startService() + } Log.d(logTag, "service starting: ${startId}:${Thread.currentThread()}") val mediaProjectionManager = getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager diff --git a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt index bd91d582c..f8ef07fd1 100644 --- a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt +++ b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/common.kt @@ -27,6 +27,7 @@ import java.util.* const val ACT_REQUEST_MEDIA_PROJECTION = "REQUEST_MEDIA_PROJECTION" const val ACT_INIT_MEDIA_PROJECTION_AND_SERVICE = "INIT_MEDIA_PROJECTION_AND_SERVICE" const val ACT_LOGIN_REQ_NOTIFY = "LOGIN_REQ_NOTIFY" +const val EXT_INIT_FROM_BOOT = "EXT_INIT_FROM_BOOT" const val EXT_MEDIA_PROJECTION_RES_INTENT = "MEDIA_PROJECTION_RES_INTENT" const val EXT_LOGIN_REQ_NOTIFY = "LOGIN_REQ_NOTIFY" @@ -41,9 +42,11 @@ const val RES_FAILED = -100 const val START_ACTION = "start_action" const val GET_START_ON_BOOT_OPT = "get_start_on_boot_opt" const val SET_START_ON_BOOT_OPT = "set_start_on_boot_opt" +const val SYNC_APP_DIR_CONFIG_PATH = "sync_app_dir" const val KEY_SHARED_PREFERENCES = "KEY_SHARED_PREFERENCES" const val KEY_START_ON_BOOT_OPT = "KEY_START_ON_BOOT_OPT" +const val KEY_APP_DIR_CONFIG_PATH = "KEY_APP_DIR_CONFIG_PATH" @SuppressLint("ConstantLocale") val LOCAL_NAME = Locale.getDefault().toString() diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index b075ee76f..95e4d17e7 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -153,6 +153,7 @@ class AndroidChannel { static final kStartAction = "start_action"; static final kGetStartOnBootOpt = "get_start_on_boot_opt"; static final kSetStartOnBootOpt = "set_start_on_boot_opt"; + static final kSyncAppDirConfigPath = "sync_app_dir"; } /// flutter/packages/flutter/lib/src/services/keyboard_key.dart -> _keyLabels diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index baf7193b3..6d3f863e7 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -153,6 +153,7 @@ void runMainApp(bool startService) async { void runMobileApp() async { await initEnv(kAppTypeMain); if (isAndroid) androidChannelInit(); + platformFFI.syncAndroidServiceAppDirConfigPath(); runApp(App()); } diff --git a/flutter/lib/models/native_model.dart b/flutter/lib/models/native_model.dart index 13f5b4587..28dc8085e 100644 --- a/flutter/lib/models/native_model.dart +++ b/flutter/lib/models/native_model.dart @@ -30,7 +30,7 @@ typedef F4Dart = int Function(Pointer); typedef F5 = Void Function(Pointer); typedef F5Dart = void Function(Pointer); typedef HandleEvent = Future Function(Map evt); -// pub fn session_register_texture(id: *const char, ptr: usize) +// pub fn session_register_texture(id: *const char, ptr: usize) typedef F6 = Void Function(Pointer, Uint64); typedef F6Dart = void Function(Pointer, int); @@ -56,7 +56,6 @@ class PlatformFFI { F4Dart? _session_get_rgba_size; F5Dart? _session_next_rgba; F6Dart? _session_register_texture; - static get localeName => Platform.localeName; @@ -162,7 +161,8 @@ class PlatformFFI { dylib.lookupFunction("session_get_rgba_size"); _session_next_rgba = dylib.lookupFunction("session_next_rgba"); - _session_register_texture = dylib.lookupFunction("session_register_texture"); + _session_register_texture = + dylib.lookupFunction("session_register_texture"); try { // SYSTEM user failed _dir = (await getApplicationDocumentsDirectory()).path; @@ -301,4 +301,8 @@ class PlatformFFI { if (!isAndroid) return Future(() => false); return await _toAndroidChannel.invokeMethod(method, arguments); } + + void syncAndroidServiceAppDirConfigPath() { + invokeMethod(AndroidChannel.kSyncAppDirConfigPath, _dir); + } } diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index e49ba65f7..e5b24fa53 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -1361,7 +1361,7 @@ pub fn send_url_scheme(_url: String) { #[cfg(target_os = "android")] pub mod server_side { - use hbb_common::log; + use hbb_common::{log, config}; use jni::{ objects::{JClass, JString}, sys::jstring, @@ -1374,11 +1374,25 @@ pub mod server_side { pub unsafe extern "system" fn Java_com_carriez_flutter_1hbb_MainService_startServer( env: JNIEnv, _class: JClass, + app_dir: JString, ) { - log::debug!("startServer from java"); + log::debug!("startServer from jvm"); + if let Ok(app_dir) = env.get_string(app_dir) { + *config::APP_DIR.write().unwrap() = app_dir.into(); + } std::thread::spawn(move || start_server(true)); } + #[no_mangle] + pub unsafe extern "system" fn Java_com_carriez_flutter_1hbb_MainService_startService( + env: JNIEnv, + _class: JClass, + ) { + log::debug!("startService from jvm"); + config::Config::set_option("stop-service".into(), "".into()); + crate::rendezvous_mediator::RendezvousMediator::restart(); + } + #[no_mangle] pub unsafe extern "system" fn Java_com_carriez_flutter_1hbb_MainService_translateLocale( env: JNIEnv, From 2cb3ca4ed00a22d4f512e70f0202a6f05bc1be13 Mon Sep 17 00:00:00 2001 From: csf Date: Wed, 1 Mar 2023 00:14:37 +0900 Subject: [PATCH 52/65] update lang, start on boot --- flutter/lib/mobile/pages/settings_page.dart | 2 +- src/lang/ca.rs | 2 ++ src/lang/cn.rs | 2 ++ src/lang/cs.rs | 4 +++- src/lang/da.rs | 2 ++ src/lang/de.rs | 4 +++- src/lang/eo.rs | 2 ++ src/lang/es.rs | 2 ++ src/lang/fa.rs | 4 +++- src/lang/fr.rs | 2 ++ src/lang/gr.rs | 2 ++ src/lang/hu.rs | 2 ++ src/lang/id.rs | 2 ++ src/lang/it.rs | 4 +++- src/lang/ja.rs | 2 ++ src/lang/ko.rs | 2 ++ src/lang/kz.rs | 2 ++ src/lang/nl.rs | 2 ++ src/lang/pl.rs | 5 ++--- src/lang/pt_PT.rs | 4 +++- src/lang/ptbr.rs | 2 ++ src/lang/ro.rs | 2 ++ src/lang/ru.rs | 2 ++ src/lang/sk.rs | 2 ++ src/lang/sl.rs | 2 ++ src/lang/sq.rs | 2 ++ src/lang/sr.rs | 2 ++ src/lang/sv.rs | 2 ++ src/lang/template.rs | 2 ++ src/lang/th.rs | 2 ++ src/lang/tr.rs | 2 ++ src/lang/tw.rs | 2 ++ src/lang/ua.rs | 2 ++ src/lang/vn.rs | 2 ++ 34 files changed, 72 insertions(+), 9 deletions(-) diff --git a/flutter/lib/mobile/pages/settings_page.dart b/flutter/lib/mobile/pages/settings_page.dart index e54f66ffb..e07f8f59f 100644 --- a/flutter/lib/mobile/pages/settings_page.dart +++ b/flutter/lib/mobile/pages/settings_page.dart @@ -335,7 +335,7 @@ class _SettingsState extends State with WidgetsBindingObserver { title: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("${translate('Start on Boot')} (beta)"), Text( - '* ${translate('Start the screen recording service on boot, which requires special permissions')}', + '* ${translate('Start the screen sharing service on boot, requires special permissions')}', style: Theme.of(context).textTheme.bodySmall), ]), onToggle: (toValue) async { diff --git a/src/lang/ca.rs b/src/lang/ca.rs index aa33ae6e5..53ec69b5f 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "Mantenir RustDesk com a servei en segon pla"), ("Ignore Battery Optimizations", "Ignorar optimizacions de la bateria"), ("android_open_battery_optimizations_tip", ""), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "Connexió no disponible"), ("Legacy mode", "Mode heretat"), ("Map mode", "Mode mapa"), diff --git a/src/lang/cn.rs b/src/lang/cn.rs index f975e343f..4c037234b 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "保持 RustDesk 后台服务"), ("Ignore Battery Optimizations", "忽略电池优化"), ("android_open_battery_optimizations_tip", "如需关闭此功能,请在接下来的 RustDesk 应用设置页面中,找到并进入 [电源] 页面,取消勾选 [不受限制]"), + ("Start on Boot", "开机自启动"), + ("Start the screen sharing service on boot, requires special permissions", "开机自动启动屏幕共享服务,此功能需要一些特殊权限。"), ("Connection not allowed", "对方不允许连接"), ("Legacy mode", "传统模式"), ("Map mode", "1:1 传输"), diff --git a/src/lang/cs.rs b/src/lang/cs.rs index cfe69924c..25a494eef 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", ""), ("Ignore Battery Optimizations", ""), ("android_open_battery_optimizations_tip", ""), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", ""), ("Legacy mode", ""), ("Map mode", ""), @@ -454,8 +456,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Stop voice call", ""), ("relay_hint_tip", ""), ("Reconnect", ""), - ("No transfers in progress", ""), ("Codec", ""), ("Resolution", ""), + ("No transfers in progress", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index 19310357b..8fd6f9be1 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "Behold RustDesk baggrundstjeneste"), ("Ignore Battery Optimizations", "Ignorer betteri optimeringer"), ("android_open_battery_optimizations_tip", ""), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "Forbindelse ikke tilladt"), ("Legacy mode", "Bagudkompatibilitetstilstand"), ("Map mode", ""), diff --git a/src/lang/de.rs b/src/lang/de.rs index 3d95832ec..754d7b9ef 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "RustDesk im Hintergrund ausführen"), ("Ignore Battery Optimizations", "Akkuoptimierung ignorieren"), ("android_open_battery_optimizations_tip", "Möchten Sie die Einstellungen zur Akkuoptimierung öffnen?"), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "Verbindung abgelehnt"), ("Legacy mode", "Kompatibilitätsmodus"), ("Map mode", "Kartenmodus"), @@ -457,5 +459,5 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Codec", "Codec"), ("Resolution", "Auflösung"), ("No transfers in progress", "Keine Übertragungen im Gange"), - ].iter().cloned().collect(); + ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 9b7912cff..dfee4fb87 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", ""), ("Ignore Battery Optimizations", ""), ("android_open_battery_optimizations_tip", ""), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", ""), ("Legacy mode", ""), ("Map mode", ""), diff --git a/src/lang/es.rs b/src/lang/es.rs index af0da0479..8477ba99b 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "Dejar RustDesk como Servicio en 2do plano"), ("Ignore Battery Optimizations", "Ignorar optimizacioens de bateria"), ("android_open_battery_optimizations_tip", "Si deseas deshabilitar esta característica, por favor, ve a la página siguiente de ajustes, busca y entra en [Batería] y desmarca [Sin restricción]"), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "Conexión no disponible"), ("Legacy mode", "Modo heredado"), ("Map mode", "Modo mapa"), diff --git a/src/lang/fa.rs b/src/lang/fa.rs index 0c31e1531..2cefaa98f 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "را در پس زمینه نگه دارید RustDesk سرویس"), ("Ignore Battery Optimizations", "بهینه سازی باتری نادیده گرفته شود"), ("android_open_battery_optimizations_tip", "به صفحه تنظیمات بعدی بروید"), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "اتصال مجاز نیست"), ("Legacy mode", "legacy حالت"), ("Map mode", "map حالت"), @@ -454,8 +456,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Stop voice call", "توقف تماس صوتی"), ("relay_hint_tip", " را به شناسه اضافه کنید یا گزینه \"همیشه از طریق رله متصل شوید\" را در کارت همتا انتخاب کنید. همچنین، اگر می‌خواهید فوراً از سرور رله استفاده کنید، می‌توانید پسوند \"/r\".\n اتصال مستقیم ممکن است امکان پذیر نباشد. در این صورت می توانید سعی کنید از طریق سرور رله متصل شوید"), ("Reconnect", "اتصال مجدد"), - ("No transfers in progress", ""), ("Codec", ""), ("Resolution", ""), + ("No transfers in progress", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index 0e45827f7..28f1dd9d1 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "Gardez le service RustDesk en arrière plan"), ("Ignore Battery Optimizations", "Ignorer les optimisations batterie"), ("android_open_battery_optimizations_tip", "Conseil android d'optimisation de batterie"), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "Connexion non autorisée"), ("Legacy mode", "Mode hérité"), ("Map mode", ""), diff --git a/src/lang/gr.rs b/src/lang/gr.rs index fca98f228..55a3c9bb7 100644 --- a/src/lang/gr.rs +++ b/src/lang/gr.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "Εκτέλεση του RustDesk στο παρασκήνιο"), ("Ignore Battery Optimizations", "Παράβλεψη βελτιστοποιήσεων μπαταρίας"), ("android_open_battery_optimizations_tip", "Θέλετε να ανοίξετε τις ρυθμίσεις βελτιστοποίησης μπαταρίας;"), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "Η σύνδεση απορρίφθηκε"), ("Legacy mode", "Λειτουργία συμβατότητας"), ("Map mode", "Map mode"), diff --git a/src/lang/hu.rs b/src/lang/hu.rs index 437cf445a..f47d522db 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "RustDesk futtatása a háttérben"), ("Ignore Battery Optimizations", "Akkumulátorkímélő figyelmen kívűl hagyása"), ("android_open_battery_optimizations_tip", "Ha le szeretné tiltani ezt a funkciót, lépjen a RustDesk alkalmazás beállítási oldalára, keresse meg az [Akkumulátorkímélő] lehetőséget és válassza a nincs korlátozás lehetőséget."), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "A csatlakozás nem engedélyezett"), ("Legacy mode", ""), ("Map mode", ""), diff --git a/src/lang/id.rs b/src/lang/id.rs index 84892a7f8..7d02e154d 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "Pertahankan RustDesk berjalan pada background service"), ("Ignore Battery Optimizations", "Abaikan Pengoptimalan Baterai"), ("android_open_battery_optimizations_tip", ""), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "Koneksi tidak dijinkan"), ("Legacy mode", "Mode lama"), ("Map mode", "Mode peta"), diff --git a/src/lang/it.rs b/src/lang/it.rs index 101685c4a..8aedc04f6 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "Mantieni il servizio di RustDesk in background"), ("Ignore Battery Optimizations", "Ignora le ottimizzazioni della batteria"), ("android_open_battery_optimizations_tip", "Se si desidera disabilitare questa funzione, andare nelle impostazioni dell'applicazione RustDesk, aprire la sezione [Batteria] e deselezionare [Senza restrizioni]."), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "Connessione non consentita"), ("Legacy mode", "Modalità legacy"), ("Map mode", "Modalità mappa"), @@ -454,8 +456,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Stop voice call", "Interrompi la chiamata vocale"), ("relay_hint_tip", "Se non è possibile connettersi direttamente, si può provare a farlo tramite relay.\nInoltre, se si desidera utilizzare il relay al primo tentativo, è possibile aggiungere il suffisso \"/r\" all'ID o selezionare l'opzione \"Collegati sempre tramite relay\" nella scheda peer."), ("Reconnect", "Riconnetti"), - ("No transfers in progress", "Nessun trasferimento in corso"), ("Codec", "Codec"), ("Resolution", "Risoluzione"), + ("No transfers in progress", "Nessun trasferimento in corso"), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index c19b607ca..d097a8b61 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "RustDesk バックグラウンドサービスを維持"), ("Ignore Battery Optimizations", "バッテリーの最適化を無効にする"), ("android_open_battery_optimizations_tip", "この機能を使わない場合は、次のRestDeskアプリ設定ページから「バッテリー」に進み、「制限なし」の選択を外してください"), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "接続が許可されていません"), ("Legacy mode", ""), ("Map mode", ""), diff --git a/src/lang/ko.rs b/src/lang/ko.rs index 97574e67d..8ca881f16 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "RustDesk 백그라운드 서비스로 유지하기"), ("Ignore Battery Optimizations", "배터리 최적화 무시하기"), ("android_open_battery_optimizations_tip", "해당 기능을 비활성화하려면 RustDesk 응용 프로그램 설정 페이지로 이동하여 [배터리]에서 [제한 없음] 선택을 해제하십시오."), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "연결이 허용되지 않음"), ("Legacy mode", ""), ("Map mode", ""), diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 54a51b439..a9acdce65 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "Артжақтағы RustDesk сербесін сақтап тұру"), ("Ignore Battery Optimizations", "Бәтері Оңтайландыруларын Елемеу"), ("android_open_battery_optimizations_tip", "Егер де бұл ерекшелікті өшіруді қаласаңыз, келесі RustDesk апылқат орнатпалары бетіне барып, [Бәтері]'ні тауып кіріңіз де [Шектеусіз]'ден құсбелгіні алып тастауды өтінеміз"), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "Қосылу рұқсат етілмеген"), ("Legacy mode", ""), ("Map mode", ""), diff --git a/src/lang/nl.rs b/src/lang/nl.rs index f38c14791..cf3eb430c 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "RustDesk achtergronddienst behouden"), ("Ignore Battery Optimizations", "Negeer Batterij Optimalisaties"), ("android_open_battery_optimizations_tip", "Ga naar de volgende pagina met instellingen"), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "Verbinding niet toegestaan"), ("Legacy mode", "Verouderde modus"), ("Map mode", "Map mode"), diff --git a/src/lang/pl.rs b/src/lang/pl.rs index 13027a682..a0808f5bf 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "Zachowaj usługę RustDesk w tle"), ("Ignore Battery Optimizations", "Ignoruj optymalizację baterii"), ("android_open_battery_optimizations_tip", "Jeśli chcesz wyłączyć tę funkcję, przejdź do następnej strony ustawień aplikacji RustDesk, znajdź i wprowadź [Bateria], odznacz [Bez ograniczeń]"), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "Połączenie niedozwolone"), ("Legacy mode", "Tryb kompatybilności wstecznej (legacy)"), ("Map mode", "Tryb mapowania"), @@ -456,9 +458,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Reconnect", "Połącz ponownie"), ("Codec", "Kodek"), ("Resolution", "Rozdzielczość"), - ("Use temporary password", "Użyj hasła tymczasowego"), - ("Set temporary password length", "Ustaw długość hasła tymczasowego"), - ("Key", "Klucz"), ("No transfers in progress", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 923bbab05..b62bd5a31 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "Manter o serviço RustDesk em funcionamento"), ("Ignore Battery Optimizations", "Ignorar optimizações de Bateria"), ("android_open_battery_optimizations_tip", ""), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "Ligação não autorizada"), ("Legacy mode", ""), ("Map mode", ""), @@ -454,8 +456,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Stop voice call", ""), ("relay_hint_tip", ""), ("Reconnect", ""), - ("No transfers in progress", ""), ("Codec", ""), ("Resolution", ""), + ("No transfers in progress", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index aa491f951..546ef2a3c 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "Manter o serviço do RustDesk executando em segundo plano"), ("Ignore Battery Optimizations", "Ignorar otimizações de bateria"), ("android_open_battery_optimizations_tip", "Abrir otimizações de bateria"), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "Conexão não permitida"), ("Legacy mode", "Modo legado"), ("Map mode", "Modo mapa"), diff --git a/src/lang/ro.rs b/src/lang/ro.rs index e992b19d8..af9389a29 100644 --- a/src/lang/ro.rs +++ b/src/lang/ro.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "Rulează serviciul RustDesk în fundal"), ("Ignore Battery Optimizations", "Ignoră optimizările de baterie"), ("android_open_battery_optimizations_tip", "Pentru dezactivarea acestei funcții, accesează setările aplicației RustDesk, deschide secțiunea [Baterie] și deselectează [Fără restricții]."), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "Conexiune neautoriztă"), ("Legacy mode", "Mod legacy"), ("Map mode", "Mod hartă"), diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 3bfb5357d..b9af4ce98 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "Держать в фоне службу RustDesk"), ("Ignore Battery Optimizations", "Игнорировать оптимизацию батареи"), ("android_open_battery_optimizations_tip", "Перейдите на следующую страницу настроек"), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "Подключение не разрешено"), ("Legacy mode", "Устаревший режим"), ("Map mode", "Режим сопоставления"), diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 6468b7eef..8a6b765be 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", ""), ("Ignore Battery Optimizations", ""), ("android_open_battery_optimizations_tip", ""), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", ""), ("Legacy mode", ""), ("Map mode", ""), diff --git a/src/lang/sl.rs b/src/lang/sl.rs index d128e7322..5721d01f4 100755 --- a/src/lang/sl.rs +++ b/src/lang/sl.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "Ohrani RustDeskovo storitev v ozadju"), ("Ignore Battery Optimizations", "Prezri optimizacije baterije"), ("android_open_battery_optimizations_tip", "Če želite izklopiti to možnost, pojdite v nastavitve aplikacije RustDesk, poiščite »Baterija« in izklopite »Neomejeno«"), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "Povezava ni dovoljena"), ("Legacy mode", "Stari način"), ("Map mode", "Način preslikave"), diff --git a/src/lang/sq.rs b/src/lang/sq.rs index 29c5cbbf8..1c488d470 100644 --- a/src/lang/sq.rs +++ b/src/lang/sq.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "Mbaje shërbimin e sfondit të RustDesk"), ("Ignore Battery Optimizations", "Injoro optimizimet e baterisë"), ("android_open_battery_optimizations_tip", "Nëse dëshironi ta çaktivizoni këtë veçori, ju lutemi shkoni te faqja tjetër e cilësimeve të aplikacionit RustDesk, gjeni dhe shtypni [Batteri], hiqni zgjedhjen [Te pakufizuara]"), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "Lidhja nuk lejohet"), ("Legacy mode", "Modaliteti i trashëgimisë"), ("Map mode", "Modaliteti i hartës"), diff --git a/src/lang/sr.rs b/src/lang/sr.rs index 63173dc11..249c0b599 100644 --- a/src/lang/sr.rs +++ b/src/lang/sr.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "Zadrži RustDesk kao pozadinski servis"), ("Ignore Battery Optimizations", "Zanemari optimizacije baterije"), ("android_open_battery_optimizations_tip", "Ako želite da onemogućite ovu funkciju, molimo idite na sledeću stranicu za podešavanje RustDesk aplikacije, pronađite i uđite u [Battery], isključite [Unrestricted]"), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "Konekcija nije dozvoljena"), ("Legacy mode", "Zastareli mod"), ("Map mode", "Mod mapiranja"), diff --git a/src/lang/sv.rs b/src/lang/sv.rs index 1a00ece43..90ec8c1cf 100644 --- a/src/lang/sv.rs +++ b/src/lang/sv.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "Behåll RustDesk i bakgrunden"), ("Ignore Battery Optimizations", "Ignorera batterioptimering"), ("android_open_battery_optimizations_tip", "Om du vill stänga av denna funktion, gå till nästa RustDesk programs inställningar, hitta [Batteri], Checka ur [Obegränsad]"), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "Anslutning ej tillåten"), ("Legacy mode", "Legacy mode"), ("Map mode", "Kartläge"), diff --git a/src/lang/template.rs b/src/lang/template.rs index 2c83f9474..6563d6056 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", ""), ("Ignore Battery Optimizations", ""), ("android_open_battery_optimizations_tip", ""), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", ""), ("Legacy mode", ""), ("Map mode", ""), diff --git a/src/lang/th.rs b/src/lang/th.rs index 6fcf02ed2..316622395 100644 --- a/src/lang/th.rs +++ b/src/lang/th.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "คงสถานะการทำงานเบื้องหลังของเซอร์วิส RustDesk"), ("Ignore Battery Optimizations", "เพิกเฉยการตั้งค่าการใช้งาน Battery Optimization"), ("android_open_battery_optimizations_tip", "หากคุณต้องการปิดการใช้งานฟีเจอร์นี้ กรุณาไปยังหน้าตั้งค่าในแอปพลิเคชัน RustDesk ค้นหาหัวข้อ [Battery] และยกเลิกการเลือกรายการ [Unrestricted]"), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "การเชื่อมต่อไม่อนุญาต"), ("Legacy mode", ""), ("Map mode", ""), diff --git a/src/lang/tr.rs b/src/lang/tr.rs index d35d288d6..7359bf064 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "RustDesk arka plan hizmetini sürdürün"), ("Ignore Battery Optimizations", "Pil Optimizasyonlarını Yoksay"), ("android_open_battery_optimizations_tip", ""), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "bağlantıya izin verilmedi"), ("Legacy mode", "Eski mod"), ("Map mode", "Haritalama modu"), diff --git a/src/lang/tw.rs b/src/lang/tw.rs index 20a2998ec..70533c482 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "保持RustDesk後台服務"), ("Ignore Battery Optimizations", "忽略電池優化"), ("android_open_battery_optimizations_tip", "如需關閉此功能,請在接下來的RustDesk應用設置頁面中,找到並進入 [電源] 頁面,取消勾選 [不受限制]"), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "對方不允許連接"), ("Legacy mode", "傳統模式"), ("Map mode", "1:1傳輸"), diff --git a/src/lang/ua.rs b/src/lang/ua.rs index 4c4b5d4bc..6b54c83c3 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "Зберегти фонову службу RustDesk"), ("Ignore Battery Optimizations", "Ігнорувати оптимізацію батареї"), ("android_open_battery_optimizations_tip", "Перейдіть на наступну сторінку налаштувань"), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "Підключення не дозволено"), ("Legacy mode", "Застарілий режим"), ("Map mode", "Режим карти"), diff --git a/src/lang/vn.rs b/src/lang/vn.rs index 32cd084cb..a379b3185 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -312,6 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "Giữ dịch vụ nền RustDesk"), ("Ignore Battery Optimizations", "Bỏ qua các tối ưu pin"), ("android_open_battery_optimizations_tip", "Nếu bạn muốn tắt tính năng này, vui lòng chuyển đến trang cài đặt ứng dụng RustDesk tiếp theo, tìm và nhập [Pin], Bỏ chọn [Không hạn chế]"), + ("Start on Boot", ""), + ("Start the screen sharing service on boot, requires special permissions", ""), ("Connection not allowed", "Kết nối không đuợc phép"), ("Legacy mode", ""), ("Map mode", ""), From e28317a8dd26a358abc4f2fe1f4035f09185b320 Mon Sep 17 00:00:00 2001 From: csf Date: Wed, 1 Mar 2023 10:12:10 +0900 Subject: [PATCH 53/65] fix lang.py --- res/lang.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/lang.py b/res/lang.py index 481d65553..aa5f99f83 100644 --- a/res/lang.py +++ b/res/lang.py @@ -36,11 +36,11 @@ def main(): def expand(): for fn in glob.glob('./src/lang/*'): lang = os.path.basename(fn)[:-3] - if lang in ['en','cn']: continue + if lang in ['en','template']: continue print(lang) dict = get_lang(lang) fw = open("./src/lang/%s.rs"%lang, "wt", encoding='utf8') - for line in open('./src/lang/cn.rs', encoding='utf8'): + for line in open('./src/lang/template.rs', encoding='utf8'): line_strip = line.strip() if line_strip.startswith('("'): k, v = line_split(line_strip) From cff2ca9df8d4d7c64731b1d27c3cd4b274b56987 Mon Sep 17 00:00:00 2001 From: csf Date: Wed, 1 Mar 2023 10:22:51 +0900 Subject: [PATCH 54/65] fix UI translate (One-time password) --- flutter/lib/mobile/pages/server_page.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flutter/lib/mobile/pages/server_page.dart b/flutter/lib/mobile/pages/server_page.dart index 648448f41..bab2911f1 100644 --- a/flutter/lib/mobile/pages/server_page.dart +++ b/flutter/lib/mobile/pages/server_page.dart @@ -41,14 +41,14 @@ class ServerPage extends StatefulWidget implements PageShape { value: "setTemporaryPasswordLength", enabled: gFFI.serverModel.verificationMethod != kUsePermanentPassword, - child: Text(translate("Set temporary password length")), + child: Text(translate("One-time password length")), ), const PopupMenuDivider(), PopupMenuItem( padding: const EdgeInsets.symmetric(horizontal: 0.0), value: kUseTemporaryPassword, child: ListTile( - title: Text(translate("Use temporary password")), + title: Text(translate("Use one-time password")), trailing: Icon( Icons.check, color: gFFI.serverModel.verificationMethod == From 138f6fe36b3530a72fa619026dcf627308a75d26 Mon Sep 17 00:00:00 2001 From: fufesou Date: Wed, 1 Mar 2023 09:54:40 +0800 Subject: [PATCH 55/65] fix keyboard options, revert change Signed-off-by: fufesou --- flutter/lib/desktop/widgets/remote_menubar.dart | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/flutter/lib/desktop/widgets/remote_menubar.dart b/flutter/lib/desktop/widgets/remote_menubar.dart index f236a7828..47d58ce5e 100644 --- a/flutter/lib/desktop/widgets/remote_menubar.dart +++ b/flutter/lib/desktop/widgets/remote_menubar.dart @@ -1561,9 +1561,8 @@ class _KeyboardMenu extends StatelessWidget { @override Widget build(BuildContext context) { - // Do not check permission here? - // var ffiModel = Provider.of(context); - // if (ffiModel.permissions['keyboard'] == false) return Offstage(); + var ffiModel = Provider.of(context); + if (ffiModel.permissions['keyboard'] == false) return Offstage(); if (stateGlobal.grabKeyboard) { if (bind.sessionIsKeyboardModeSupported(id: id, mode: _kKeyMapMode)) { bind.sessionSetKeyboardMode(id: id, value: _kKeyMapMode); From 69e95bc245ab928455d6d7ab166796def6027a4d Mon Sep 17 00:00:00 2001 From: 21pages Date: Wed, 1 Mar 2023 11:17:46 +0800 Subject: [PATCH 56/65] fix windows uninstall can not delete the installation directory Signed-off-by: 21pages --- src/platform/windows.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 0bba649f4..561bb4570 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -976,7 +976,7 @@ fn get_after_install(exe: &str) -> String { } pub fn install_me(options: &str, path: String, silent: bool, debug: bool) -> ResultType<()> { - let uninstall_str = get_uninstall(); + let uninstall_str = get_uninstall(false); let mut path = path.trim_end_matches('\\').to_owned(); let (subkey, _path, start_menu, exe) = get_default_install_info(); let mut exe = exe; @@ -1188,30 +1188,35 @@ pub fn run_after_install() -> ResultType<()> { } pub fn run_before_uninstall() -> ResultType<()> { - run_cmds(get_before_uninstall(), true, "before_install") + run_cmds(get_before_uninstall(true), true, "before_install") } -fn get_before_uninstall() -> String { +fn get_before_uninstall(kill_self: bool) -> String { let app_name = crate::get_app_name(); let ext = app_name.to_lowercase(); + let filter = if kill_self { + "".to_string() + } else { + format!(" /FI \"PID ne {}\"", get_current_pid()) + }; format!( " chcp 65001 sc stop {app_name} sc delete {app_name} taskkill /F /IM {broker_exe} - taskkill /F /IM {app_name}.exe /FI \"PID ne {cur_pid}\" + taskkill /F /IM {app_name}.exe{filter} reg delete HKEY_CLASSES_ROOT\\.{ext} /f netsh advfirewall firewall delete rule name=\"{app_name} Service\" ", app_name = app_name, broker_exe = crate::win_privacy::INJECTED_PROCESS_EXE, ext = ext, - cur_pid = get_current_pid(), + filter = filter, ) } -fn get_uninstall() -> String { +fn get_uninstall(kill_self: bool) -> String { let (subkey, path, start_menu, _) = get_install_info(); format!( " @@ -1222,7 +1227,7 @@ fn get_uninstall() -> String { if exist \"%PUBLIC%\\Desktop\\{app_name}.lnk\" del /f /q \"%PUBLIC%\\Desktop\\{app_name}.lnk\" if exist \"%PROGRAMDATA%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\{app_name} Tray.lnk\" del /f /q \"%PROGRAMDATA%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\{app_name} Tray.lnk\" ", - before_uninstall=get_before_uninstall(), + before_uninstall=get_before_uninstall(kill_self), subkey=subkey, app_name = crate::get_app_name(), path = path, @@ -1231,7 +1236,7 @@ fn get_uninstall() -> String { } pub fn uninstall_me() -> ResultType<()> { - run_cmds(get_uninstall(), true, "uninstall") + run_cmds(get_uninstall(true), true, "uninstall") } fn write_cmds(cmds: String, ext: &str, tip: &str) -> ResultType { From 303462a87ca9261fd69429f28d0bf130dd9841f5 Mon Sep 17 00:00:00 2001 From: fufesou Date: Wed, 1 Mar 2023 11:55:56 +0800 Subject: [PATCH 57/65] default config filed Signed-off-by: fufesou --- libs/hbb_common/examples/config.rs | 5 +++++ libs/hbb_common/src/config.rs | 26 ++++++++++++++++---------- 2 files changed, 21 insertions(+), 10 deletions(-) create mode 100644 libs/hbb_common/examples/config.rs diff --git a/libs/hbb_common/examples/config.rs b/libs/hbb_common/examples/config.rs new file mode 100644 index 000000000..95169df8e --- /dev/null +++ b/libs/hbb_common/examples/config.rs @@ -0,0 +1,5 @@ +extern crate hbb_common; + +fn main() { + println!("{:?}", hbb_common::config::PeerConfig::load("455058072")); +} diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 7bc82ed95..6fb2c895e 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -110,10 +110,10 @@ macro_rules! serde_field_string { } macro_rules! serde_field_bool { - ($struct_name: ident, $field_name: literal, $func: ident) => { + ($struct_name: ident, $field_name: literal, $func: ident, $default: literal) => { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct $struct_name { - #[serde(rename = $field_name)] + #[serde(default = $default, rename = $field_name)] pub v: bool, } impl Default for $struct_name { @@ -963,6 +963,7 @@ impl PeerConfig { }; let c = PeerConfig::load(&id_decoded_string); + log::info!("REMOVE ME ============================== peer config {:?}", &c); if c.info.platform.is_empty() { fs::remove_file(p).ok(); } @@ -1037,32 +1038,37 @@ impl PeerConfig { serde_field_bool!( ShowRemoteCursor, "show_remote_cursor", - default_show_remote_cursor + default_show_remote_cursor, + "ShowRemoteCursor::default_show_remote_cursor" ); serde_field_bool!( ShowQualityMonitor, "show_quality_monitor", - default_show_quality_monitor + default_show_quality_monitor, + "ShowQualityMonitor::default_show_quality_monitor" ); -serde_field_bool!(DisableAudio, "disable_audio", default_disable_audio); +serde_field_bool!(DisableAudio, "disable_audio", default_disable_audio, "DisableAudio::default_disable_audio"); serde_field_bool!( EnableFileTransfer, "enable_file_transfer", - default_enable_file_transfer + default_enable_file_transfer, + "EnableFileTransfer::default_enable_file_transfer" ); serde_field_bool!( DisableClipboard, "disable_clipboard", - default_disable_clipboard + default_disable_clipboard, + "DisableClipboard::default_disable_clipboard" ); serde_field_bool!( LockAfterSessionEnd, "lock_after_session_end", - default_lock_after_session_end + default_lock_after_session_end, + "LockAfterSessionEnd::default_lock_after_session_end" ); -serde_field_bool!(PrivacyMode, "privacy_mode", default_privacy_mode); +serde_field_bool!(PrivacyMode, "privacy_mode", default_privacy_mode, "PrivacyMode::default_privacy_mode"); -serde_field_bool!(AllowSwapKey, "allow_swap_key", default_swap_key); +serde_field_bool!(AllowSwapKey, "allow_swap_key", default_allow_swap_key, "AllowSwapKey::default_allow_swap_key"); #[derive(Debug, Default, Serialize, Deserialize, Clone)] pub struct LocalConfig { From 0d64ee39de95f90c915a51937b408645c728b55b Mon Sep 17 00:00:00 2001 From: fufesou Date: Wed, 1 Mar 2023 12:20:54 +0800 Subject: [PATCH 58/65] remove print Signed-off-by: fufesou --- libs/hbb_common/src/config.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 6fb2c895e..ed7270a85 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -963,7 +963,6 @@ impl PeerConfig { }; let c = PeerConfig::load(&id_decoded_string); - log::info!("REMOVE ME ============================== peer config {:?}", &c); if c.info.platform.is_empty() { fs::remove_file(p).ok(); } From 874d22168b171e12829b1808cfc564d4a620aefe Mon Sep 17 00:00:00 2001 From: FastAct <93490087+FastAct@users.noreply.github.com> Date: Wed, 1 Mar 2023 07:49:45 +0100 Subject: [PATCH 59/65] Update nl.rs --- src/lang/nl.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lang/nl.rs b/src/lang/nl.rs index cf3eb430c..c0e627c68 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -454,10 +454,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Voice call", "Spraakoproep"), ("Text chat", "Tekst chat"), ("Stop voice call", "Stop spraakoproep"), - ("relay_hint_tip", ""), - ("Reconnect", ""), - ("Codec", ""), - ("Resolution", ""), - ("No transfers in progress", ""), + ("relay_hint_tip", "Indien een directe verbinding niet mogelijk is, kunt u proberen verbinding te maken via een Relay Server. \nAls u bij de eerste poging een relaisverbinding tot stand wilt brengen, kunt u het achtervoegsel \"/r\" toevoegen aan het ID of de optie \"Altijd verbinden via relaisserver\" selecteren op de externe terminal."), + ("Reconnect", "Herverbinden"), + ("Codec", "odec"), + ("Resolution", "Resolutie"), + ("No transfers in progress", "Geen overdrachten in uitvoering"), ].iter().cloned().collect(); } From 80c39574f8c57d0e4e3bcc84a7eb2ea40fd9767a Mon Sep 17 00:00:00 2001 From: FastAct <93490087+FastAct@users.noreply.github.com> Date: Wed, 1 Mar 2023 08:09:11 +0100 Subject: [PATCH 60/65] Update nl.rs --- src/lang/nl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/nl.rs b/src/lang/nl.rs index c0e627c68..d1c154546 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -456,7 +456,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Stop voice call", "Stop spraakoproep"), ("relay_hint_tip", "Indien een directe verbinding niet mogelijk is, kunt u proberen verbinding te maken via een Relay Server. \nAls u bij de eerste poging een relaisverbinding tot stand wilt brengen, kunt u het achtervoegsel \"/r\" toevoegen aan het ID of de optie \"Altijd verbinden via relaisserver\" selecteren op de externe terminal."), ("Reconnect", "Herverbinden"), - ("Codec", "odec"), + ("Codec", "Codec"), ("Resolution", "Resolutie"), ("No transfers in progress", "Geen overdrachten in uitvoering"), ].iter().cloned().collect(); From 2417a079aab290f07d782c90c769185d594b995f Mon Sep 17 00:00:00 2001 From: Michal Witek Date: Wed, 1 Mar 2023 09:52:26 +0100 Subject: [PATCH 61/65] Additional translation for `pl.rs` --- src/lang/pl.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/lang/pl.rs b/src/lang/pl.rs index a0808f5bf..494715527 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -312,8 +312,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", "Zachowaj usługę RustDesk w tle"), ("Ignore Battery Optimizations", "Ignoruj optymalizację baterii"), ("android_open_battery_optimizations_tip", "Jeśli chcesz wyłączyć tę funkcję, przejdź do następnej strony ustawień aplikacji RustDesk, znajdź i wprowadź [Bateria], odznacz [Bez ograniczeń]"), - ("Start on Boot", ""), - ("Start the screen sharing service on boot, requires special permissions", ""), + ("Start on Boot", "Autostart"), + ("Start the screen sharing service on boot, requires special permissions", "Uruchom usługę udostępniania ekranu podczas startu, wymaga specjalnych uprawnień"), ("Connection not allowed", "Połączenie niedozwolone"), ("Legacy mode", "Tryb kompatybilności wstecznej (legacy)"), ("Map mode", "Tryb mapowania"), @@ -458,6 +458,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Reconnect", "Połącz ponownie"), ("Codec", "Kodek"), ("Resolution", "Rozdzielczość"), - ("No transfers in progress", ""), + ("Key", "Klucz"), + ("No transfers in progress", "Brak transferów w toku"), ].iter().cloned().collect(); } From 7b80269dabcc23a57c529bed7c0e0127dfb2eb17 Mon Sep 17 00:00:00 2001 From: 21pages Date: Wed, 1 Mar 2023 14:18:46 +0800 Subject: [PATCH 62/65] install page use custom titlebar Signed-off-by: 21pages --- flutter/lib/desktop/pages/install_page.dart | 48 ++++++++++++++++++- .../lib/desktop/widgets/tabbar_widget.dart | 16 ++++--- flutter/lib/main.dart | 11 +++-- 3 files changed, 64 insertions(+), 11 deletions(-) diff --git a/flutter/lib/desktop/pages/install_page.dart b/flutter/lib/desktop/pages/install_page.dart index d7202e300..00ca2bb23 100644 --- a/flutter/lib/desktop/pages/install_page.dart +++ b/flutter/lib/desktop/pages/install_page.dart @@ -1,7 +1,9 @@ import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hbb/common.dart'; +import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart'; import 'package:flutter_hbb/models/platform_model.dart'; +import 'package:flutter_hbb/models/state_model.dart'; import 'package:get/get.dart'; import 'package:url_launcher/url_launcher_string.dart'; import 'package:window_manager/window_manager.dart'; @@ -13,7 +15,51 @@ class InstallPage extends StatefulWidget { State createState() => _InstallPageState(); } -class _InstallPageState extends State with WindowListener { +class _InstallPageState extends State { + final tabController = DesktopTabController(tabType: DesktopTabType.main); + + @override + void initState() { + super.initState(); + Get.put(tabController); + const lable = "install"; + tabController.add(TabInfo( + key: lable, + label: lable, + closable: false, + page: _InstallPageBody( + key: const ValueKey(lable), + ))); + } + + @override + void dispose() { + super.dispose(); + Get.delete(); + } + + @override + Widget build(BuildContext context) { + return DragToResizeArea( + resizeEdgeSize: stateGlobal.resizeEdgeSize.value, + child: Container( + child: Scaffold( + backgroundColor: Theme.of(context).colorScheme.background, + body: DesktopTab(controller: tabController)), + ), + ); + } +} + +class _InstallPageBody extends StatefulWidget { + const _InstallPageBody({Key? key}) : super(key: key); + + @override + State<_InstallPageBody> createState() => _InstallPageBodyState(); +} + +class _InstallPageBodyState extends State<_InstallPageBody> + with WindowListener { late final TextEditingController controller; final RxBool startmenu = true.obs; final RxBool desktopicon = true.obs; diff --git a/flutter/lib/desktop/widgets/tabbar_widget.dart b/flutter/lib/desktop/widgets/tabbar_widget.dart index 958c4c035..edc779fba 100644 --- a/flutter/lib/desktop/widgets/tabbar_widget.dart +++ b/flutter/lib/desktop/widgets/tabbar_widget.dart @@ -53,6 +53,7 @@ enum DesktopTabType { remoteScreen, fileTransfer, portForward, + install, } class DesktopTabState { @@ -249,8 +250,9 @@ class DesktopTab extends StatelessWidget { this.unSelectedTabBackgroundColor, }) : super(key: key) { tabType = controller.tabType; - isMainWindow = - tabType == DesktopTabType.main || tabType == DesktopTabType.cm; + isMainWindow = tabType == DesktopTabType.main || + tabType == DesktopTabType.cm || + tabType == DesktopTabType.install; } static RxString labelGetterAlias(String peerId) { @@ -361,7 +363,8 @@ class DesktopTab extends StatelessWidget { /// - hide single item when only has one item (home) on [DesktopTabPage]. bool isHideSingleItem() { return state.value.tabs.length == 1 && - controller.tabType == DesktopTabType.main; + (controller.tabType == DesktopTabType.main || + controller.tabType == DesktopTabType.install); } Widget _buildBar() { @@ -524,8 +527,8 @@ class WindowActionPanelState extends State } void _setMaximize(bool maximize) { - stateGlobal.setMaximize(maximize); - setState(() {}); + stateGlobal.setMaximize(maximize); + setState(() {}); } @override @@ -759,7 +762,8 @@ class _ListView extends StatelessWidget { /// - hide single item when only has one item (home) on [DesktopTabPage]. bool isHideSingleItem() { return state.value.tabs.length == 1 && - controller.tabType == DesktopTabType.main; + controller.tabType == DesktopTabType.main || + controller.tabType == DesktopTabType.install; } @override diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index 6d3f863e7..bb1b4f552 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -293,16 +293,19 @@ void runInstallPage() async { await windowManager.ensureInitialized(); await initEnv(kAppTypeMain); _runApp('', const InstallPage(), MyTheme.currentThemeMode()); - windowManager.waitUntilReadyToShow( - WindowOptions(size: Size(800, 600), center: true), () async { + WindowOptions windowOptions = + getHiddenTitleBarWindowOptions(size: Size(800, 600), center: true); + windowManager.waitUntilReadyToShow(windowOptions, () async { windowManager.show(); windowManager.focus(); windowManager.setOpacity(1); windowManager.setAlignment(Alignment.center); // ensure + windowManager.setTitle(getWindowName()); }); } -WindowOptions getHiddenTitleBarWindowOptions({Size? size}) { +WindowOptions getHiddenTitleBarWindowOptions( + {Size? size, bool center = false}) { var defaultTitleBarStyle = TitleBarStyle.hidden; // we do not hide titlebar on win7 because of the frame overflow. if (kUseCompatibleUiMode) { @@ -310,7 +313,7 @@ WindowOptions getHiddenTitleBarWindowOptions({Size? size}) { } return WindowOptions( size: size, - center: false, + center: center, backgroundColor: Colors.transparent, skipTaskbar: false, titleBarStyle: defaultTitleBarStyle, From d1f58a444d0bf143e9658cb0b2a43f363347530f Mon Sep 17 00:00:00 2001 From: 21pages Date: Wed, 1 Mar 2023 16:30:39 +0800 Subject: [PATCH 63/65] dark theme disabled button color, disabled combox color Signed-off-by: 21pages --- flutter/lib/common.dart | 21 ++++++++++++++----- .../desktop/pages/desktop_setting_page.dart | 8 +++++-- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index e0306a3a7..e049c0fe1 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -218,19 +218,30 @@ class MyTheme { labelColor: Colors.white70, ), scrollbarTheme: ScrollbarThemeData( - thumbColor: MaterialStateProperty.all(Colors.grey[500]) + thumbColor: MaterialStateProperty.all(Colors.grey[500]), ), splashColor: Colors.transparent, highlightColor: Colors.transparent, splashFactory: isDesktop ? NoSplash.splashFactory : null, outlinedButtonTheme: OutlinedButtonThemeData( - style: - OutlinedButton.styleFrom(side: BorderSide(color: Colors.white38))), + style: OutlinedButton.styleFrom( + side: BorderSide(color: Colors.white38), + disabledForegroundColor: Colors.white70, + ), + ), textButtonTheme: isDesktop ? TextButtonThemeData( - style: ButtonStyle(splashFactory: NoSplash.splashFactory), - ) + style: TextButton.styleFrom( + splashFactory: NoSplash.splashFactory, + disabledForegroundColor: Colors.white70, + )) : null, + elevatedButtonTheme: ElevatedButtonThemeData( + style: ElevatedButton.styleFrom( + disabledForegroundColor: Colors.white70, + disabledBackgroundColor: Colors.white10, + ), + ), checkboxTheme: const CheckboxThemeData(checkColor: MaterialStatePropertyAll(dark)), colorScheme: ColorScheme.fromSwatch( diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index 52f64c0e3..7d907d727 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -538,6 +538,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { translate('Screen Share'), translate('Deny remote access'), ], + enabled: enabled, initialKey: initialKey, onChanged: (mode) async { String modeValue; @@ -667,6 +668,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { return _Card(title: 'Password', children: [ _ComboBox( + enabled: !locked, keys: modeKeys, values: modeValues, initialKey: modeInitialKey, @@ -1722,7 +1724,6 @@ class _ComboBox extends StatelessWidget { required this.values, required this.initialKey, required this.onChanged, - // ignore: unused_element this.enabled = true, }) : super(key: key); @@ -1735,7 +1736,9 @@ class _ComboBox extends StatelessWidget { var ref = values[index].obs; current = keys[index]; return Container( - decoration: BoxDecoration(border: Border.all(color: MyTheme.border)), + decoration: BoxDecoration( + border: Border.all( + color: _disabledTextColor(context, enabled) ?? MyTheme.border)), height: 30, child: Obx(() => DropdownButton( isExpanded: true, @@ -1744,6 +1747,7 @@ class _ComboBox extends StatelessWidget { underline: Container( height: 25, ), + style: TextStyle(color: _disabledTextColor(context, enabled)), icon: const Icon( Icons.expand_more_sharp, size: 20, From 279fd7de67e5482c01a19f67057189d28edc7bae Mon Sep 17 00:00:00 2001 From: fufesou Date: Wed, 1 Mar 2023 17:38:01 +0800 Subject: [PATCH 64/65] win, fix fullscreen with 3 pixels offset Signed-off-by: fufesou --- flutter/pubspec.lock | 4 ++-- flutter/pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/flutter/pubspec.lock b/flutter/pubspec.lock index 5ffe805b8..76fe929e5 100644 --- a/flutter/pubspec.lock +++ b/flutter/pubspec.lock @@ -325,8 +325,8 @@ packages: dependency: "direct main" description: path: "." - ref: f37357ed98a10717576eb9ed8413e92b2ec5d13a - resolved-ref: f37357ed98a10717576eb9ed8413e92b2ec5d13a + ref: "3e2655677c54f421f9e378680d8171b95a211e0f" + resolved-ref: "3e2655677c54f421f9e378680d8171b95a211e0f" url: "https://github.com/Kingtous/rustdesk_desktop_multi_window" source: git version: "0.1.0" diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index 8d390d370..71a840c9c 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -59,7 +59,7 @@ dependencies: desktop_multi_window: git: url: https://github.com/Kingtous/rustdesk_desktop_multi_window - ref: e383fffb5c4529c9e0a710f1025a0c590b99ee08 + ref: 3e2655677c54f421f9e378680d8171b95a211e0f freezed_annotation: ^2.0.3 flutter_custom_cursor: ^0.0.4 window_size: From 6267d56b45e64e6b119489566274156425ee7723 Mon Sep 17 00:00:00 2001 From: 21pages Date: Wed, 1 Mar 2023 19:31:52 +0800 Subject: [PATCH 65/65] fix combox theme Signed-off-by: 21pages --- flutter/lib/common.dart | 8 +++++++- flutter/lib/desktop/pages/desktop_setting_page.dart | 10 ++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index e049c0fe1..c438a3c7b 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -109,27 +109,32 @@ class IconFont { class ColorThemeExtension extends ThemeExtension { const ColorThemeExtension({ required this.border, + required this.border2, required this.highlight, }); final Color? border; + final Color? border2; final Color? highlight; static const light = ColorThemeExtension( border: Color(0xFFCCCCCC), + border2: Color(0xFFBBBBBB), highlight: Color(0xFFE5E5E5), ); static const dark = ColorThemeExtension( border: Color(0xFF555555), + border2: Color(0xFFE5E5E5), highlight: Color(0xFF3F3F3F), ); @override ThemeExtension copyWith( - {Color? border, Color? highlight}) { + {Color? border, Color? border2, Color? highlight}) { return ColorThemeExtension( border: border ?? this.border, + border2: border2 ?? this.border2, highlight: highlight ?? this.highlight, ); } @@ -142,6 +147,7 @@ class ColorThemeExtension extends ThemeExtension { } return ColorThemeExtension( border: Color.lerp(border, other.border, t), + border2: Color.lerp(border2, other.border2, t), highlight: Color.lerp(highlight, other.highlight, t), ); } diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index 7d907d727..0aafd48bb 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -1738,7 +1738,10 @@ class _ComboBox extends StatelessWidget { return Container( decoration: BoxDecoration( border: Border.all( - color: _disabledTextColor(context, enabled) ?? MyTheme.border)), + color: enabled + ? MyTheme.color(context).border2 ?? MyTheme.border + : MyTheme.border, + )), height: 30, child: Obx(() => DropdownButton( isExpanded: true, @@ -1747,7 +1750,10 @@ class _ComboBox extends StatelessWidget { underline: Container( height: 25, ), - style: TextStyle(color: _disabledTextColor(context, enabled)), + style: TextStyle( + color: enabled + ? Theme.of(context).textTheme.titleMedium?.color + : _disabledTextColor(context, enabled)), icon: const Icon( Icons.expand_more_sharp, size: 20,