Merge branch 'master' of https://github.com/rustdesk/rustdesk into android_start_on_boot

This commit is contained in:
csf 2023-03-01 00:22:40 +09:00
commit 761203e778
18 changed files with 180 additions and 40 deletions

View File

@ -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 }

View File

@ -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

2
Cargo.lock generated
View File

@ -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",

View File

@ -315,13 +315,10 @@ 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(
"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("..")

View File

@ -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,

View File

@ -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;

View File

@ -920,6 +920,7 @@ class _DisplayMenuState extends State<_DisplayMenu> {
disableClipboard(),
lockAfterSessionEnd(),
privacyMode(),
swapKey(),
]);
}
@ -953,12 +954,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 +1029,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);
}
@ -1527,6 +1529,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 {

View File

@ -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,

View File

@ -458,10 +458,8 @@ class InputModel {
return;
}
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;
var nearRight = (canvasModel.size.width - x) < nearThr;

View File

@ -727,12 +727,25 @@ class CanvasModel with ChangeNotifier {
double get scrollX => _scrollX;
double get scrollY => _scrollY;
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() {
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 - leftToEdge - rightToEdge;
double h = size.height - topToEdge - bottomToEdge;
return Size(w < 0 ? 0 : w, h < 0 ? 0 : h);
}
@ -806,10 +819,14 @@ 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) {
return;
}
// On mobile platforms, move the canvas with the cursor.
final dw = getDisplayWidth() * _scale;
final dh = getDisplayHeight() * _scale;

View File

@ -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;

View File

@ -217,6 +217,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)]
@ -1060,6 +1062,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)]

View File

@ -1230,6 +1230,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
@ -1383,6 +1385,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()
}
@ -1807,6 +1811,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));
}
@ -2033,6 +2038,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.

View File

@ -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."),

View File

@ -458,6 +458,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();
}

View File

@ -456,8 +456,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Stop voice call", "توقف تماس صوتی"),
("relay_hint_tip", " را به شناسه اضافه کنید یا گزینه \"همیشه از طریق رله متصل شوید\" را در کارت همتا انتخاب کنید. همچنین، اگر می‌خواهید فوراً از سرور رله استفاده کنید، می‌توانید پسوند \"/r\".\n اتصال مستقیم ممکن است امکان پذیر نباشد. در این صورت می توانید سعی کنید از طریق سرور رله متصل شوید"),
("Reconnect", "اتصال مجدد"),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
("Codec", "کدک"),
("Resolution", "وضوح"),
("No transfers in progress", "هیچ انتقالی در حال انجام نیست"),
].iter().cloned().collect();
}

View File

@ -198,6 +198,7 @@ class Header: Reactor.Component {
{keyboard_enabled && clipboard_enabled ? <li #disable-clipboard .toggle-option><span>{svg_checkmark}</span>{translate('Disable clipboard')}</li> : ""}
{keyboard_enabled ? <li #lock-after-session-end .toggle-option><span>{svg_checkmark}</span>{translate('Lock after session end')}</li> : ""}
{keyboard_enabled && pi.platform == "Windows" ? <li #privacy-mode><span>{svg_checkmark}</span>{translate('Privacy mode')}</li> : ""}
{keyboard_enabled && ((is_osx && pi.platform != "Mac OS") || (!is_osx && pi.platform == "Mac OS")) ? <li #allow_swap_key .toggle-option><span>{svg_checkmark}</span>{translate('Swap control-command key')}</li> : ""}
</menu>
</popup>;
}
@ -440,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);

View File

@ -373,10 +373,87 @@ impl<T: InvokeUiSession> Session<T> {
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_scancode(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_scancode_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));
}
@ -934,6 +1011,23 @@ impl<T: InvokeUiSession> Interface for Session<T> {
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<T: InvokeUiSession> Session<T> {