mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
Merge branch 'master' of https://github.com/rustdesk/rustdesk
This commit is contained in:
commit
6c577dc117
97
.github/workflows/flutter-nightly.yml
vendored
97
.github/workflows/flutter-nightly.yml
vendored
@ -142,13 +142,42 @@ jobs:
|
||||
job:
|
||||
- {
|
||||
target: x86_64-apple-darwin,
|
||||
os: macos-10.15,
|
||||
os: macos-latest,
|
||||
extra-build-args: "",
|
||||
}
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Import the codesign cert
|
||||
uses: apple-actions/import-codesign-certs@v1
|
||||
with:
|
||||
p12-file-base64: ${{ secrets.MACOS_P12_BASE64 }}
|
||||
p12-password: ${{ secrets.MACOS_P12_PASSWORD }}
|
||||
keychain: rustdesk
|
||||
|
||||
- name: Check sign and import sign key
|
||||
run: |
|
||||
security default-keychain -s rustdesk.keychain
|
||||
security find-identity -v
|
||||
|
||||
- name: Import notarize key
|
||||
uses: timheuer/base64-to-file@v1.2
|
||||
with:
|
||||
# https://gregoryszorc.com/docs/apple-codesign/stable/apple_codesign_rcodesign.html#notarizing-and-stapling
|
||||
fileName: rustdesk.json
|
||||
fileDir: ${{ github.workspace }}
|
||||
encodedString: ${{ secrets.MACOS_NOTARIZE_JSON }}
|
||||
|
||||
- name: Install rcodesign tool
|
||||
shell: bash
|
||||
run: |
|
||||
pushd /tmp
|
||||
wget https://github.com/indygreg/apple-platform-rs/releases/download/apple-codesign%2F0.22.0/apple-codesign-0.22.0-macos-universal.tar.gz
|
||||
tar -zxvf apple-codesign-0.22.0-macos-universal.tar.gz
|
||||
mv apple-codesign-0.22.0-macos-universal/rcodesign /usr/local/bin
|
||||
popd
|
||||
|
||||
- name: Install build runtime
|
||||
run: |
|
||||
brew install llvm create-dmg nasm yasm cmake gcc wget ninja
|
||||
@ -158,7 +187,6 @@ jobs:
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
cache: true
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
@ -177,8 +205,12 @@ jobs:
|
||||
run: |
|
||||
dart pub global activate ffigen --version 5.0.1
|
||||
# flutter_rust_bridge
|
||||
pushd /tmp && git clone https://github.com/SoLongAndThanksForAllThePizza/flutter_rust_bridge --depth=1 && popd
|
||||
pushd /tmp/flutter_rust_bridge/frb_codegen && cargo install --path . && popd
|
||||
pushd /tmp
|
||||
wget https://github.com/Kingtous/flutter_rust_bridge/releases/download/1.32.0-rustdesk/flutter_rust_bridge_codegen-x86_64-darwin.tgz
|
||||
tar -zxvf flutter_rust_bridge_codegen-x86_64-darwin.tgz
|
||||
mkdir -p ~/.cargo/bin
|
||||
mv flutter_rust_bridge_codegen ~/.cargo/bin; chmod +x ~/.cargo/bin/flutter_rust_bridge_codegen
|
||||
popd
|
||||
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
|
||||
|
||||
@ -192,10 +224,6 @@ jobs:
|
||||
run: |
|
||||
$VCPKG_ROOT/vcpkg install libvpx libyuv opus
|
||||
|
||||
- name: Install cargo bundle tools
|
||||
run: |
|
||||
cargo install cargo-bundle
|
||||
|
||||
- name: Show version information (Rust, cargo, Clang)
|
||||
shell: bash
|
||||
run: |
|
||||
@ -211,6 +239,18 @@ jobs:
|
||||
# --hwcodec not supported on macos yet
|
||||
./build.py --flutter ${{ matrix.job.extra-build-args }}
|
||||
|
||||
- name: Codesign app and create signed dmg
|
||||
run: |
|
||||
security default-keychain -s rustdesk.keychain
|
||||
security unlock-keychain -p ${{ secrets.MACOS_P12_PASSWORD }} rustdesk.keychain
|
||||
# start sign the rustdesk.app and dmg
|
||||
rm rustdesk-${{ env.VERSION }}.dmg || true
|
||||
codesign --force --options runtime -s ${{ secrets.MACOS_CODESIGN_IDENTITY }} --deep ./flutter/build/macos/Build/Products/Release/rustdesk.app -v
|
||||
create-dmg --icon "rustdesk.app" 200 190 --hide-extension "rustdesk.app" --window-size 800 400 --app-drop-link 600 185 rustdesk-${{ env.VERSION }}.dmg ./flutter/build/macos/Build/Products/Release/rustdesk.app
|
||||
codesign --force --options runtime -s ${{ secrets.MACOS_CODESIGN_IDENTITY }} --deep rustdesk-${{ env.VERSION }}.dmg -v
|
||||
# notarize the rustdesk-${{ env.VERSION }}.dmg
|
||||
rcodesign notary-submit --api-key-path ${{ github.workspace }}/rustdesk.json --staple rustdesk-${{ env.VERSION }}.dmg
|
||||
|
||||
- name: Rename rustdesk
|
||||
run: |
|
||||
for name in rustdesk*??.dmg; do
|
||||
@ -559,6 +599,12 @@ jobs:
|
||||
os: ubuntu-20.04,
|
||||
extra-build-features: "flatpak",
|
||||
}
|
||||
- {
|
||||
arch: x86_64,
|
||||
target: x86_64-unknown-linux-gnu,
|
||||
os: ubuntu-20.04,
|
||||
extra-build-features: "appimage",
|
||||
}
|
||||
# - { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
|
||||
steps:
|
||||
- name: Maximize build space
|
||||
@ -1108,6 +1154,12 @@ jobs:
|
||||
os: ubuntu-18.04,
|
||||
extra-build-features: "flatpak",
|
||||
}
|
||||
- {
|
||||
arch: x86_64,
|
||||
target: x86_64-unknown-linux-gnu,
|
||||
os: ubuntu-18.04,
|
||||
extra-build-features: "appimage",
|
||||
}
|
||||
# - { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
@ -1122,7 +1174,7 @@ jobs:
|
||||
- name: Prepare env
|
||||
run: |
|
||||
sudo apt update -y
|
||||
sudo apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev
|
||||
sudo apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev libarchive-tools
|
||||
mkdir -p ./target/release/
|
||||
|
||||
- name: Restore the rustdesk lib file
|
||||
@ -1177,10 +1229,12 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
for name in rustdesk*??.deb; do
|
||||
mv "$name" "${name%%.deb}-${{ matrix.job.target }}-${{ matrix.job.os }}.deb"
|
||||
# use cp to duplicate deb files to fit other packages.
|
||||
cp "$name" "${name%%.deb}-${{ matrix.job.target }}-${{ matrix.job.os }}.deb"
|
||||
done
|
||||
|
||||
- name: Publish debian package
|
||||
if: ${{ matrix.job.extra-build-features == '' }}
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
prerelease: true
|
||||
@ -1244,6 +1298,29 @@ jobs:
|
||||
files: |
|
||||
res/rustdesk*.zst
|
||||
|
||||
- name: Build appimage package
|
||||
if: ${{ matrix.job.extra-build-features == 'appimage' }}
|
||||
shell: bash
|
||||
run: |
|
||||
# set-up appimage-builder
|
||||
pushd /tmp
|
||||
wget -O appimage-builder-x86_64.AppImage https://github.com/AppImageCrafters/appimage-builder/releases/download/v1.1.0/appimage-builder-1.1.0-x86_64.AppImage
|
||||
chmod +x appimage-builder-x86_64.AppImage
|
||||
sudo mv appimage-builder-x86_64.AppImage /usr/local/bin/appimage-builder
|
||||
popd
|
||||
# run appimage-builder
|
||||
pushd appimage
|
||||
sudo appimage-builder --skip-tests
|
||||
|
||||
- name: Publish appimage package
|
||||
if: ${{ matrix.job.extra-build-features == 'appimage' }}
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
prerelease: true
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
files: |
|
||||
./appimage/rustdesk-${{ env.VERSION }}-*.AppImage
|
||||
|
||||
- name: Publish fedora28/centos8 package
|
||||
if: ${{ matrix.job.extra-build-features == '' }}
|
||||
uses: softprops/action-gh-release@v1
|
||||
|
||||
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -4562,6 +4562,7 @@ dependencies = [
|
||||
"arboard",
|
||||
"async-process",
|
||||
"async-trait",
|
||||
"backtrace",
|
||||
"base64",
|
||||
"bytes",
|
||||
"cc",
|
||||
|
||||
@ -119,6 +119,7 @@ dbus-crossroads = "0.5"
|
||||
gtk = "0.15"
|
||||
libappindicator = "0.7"
|
||||
glib = "0.16.5"
|
||||
backtrace = "0.3"
|
||||
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
android_logger = "0.11"
|
||||
|
||||
87
appimage/AppImageBuilder.yml
Normal file
87
appimage/AppImageBuilder.yml
Normal file
@ -0,0 +1,87 @@
|
||||
# appimage-builder recipe see https://appimage-builder.readthedocs.io for details
|
||||
version: 1
|
||||
script:
|
||||
- rm -rf ./AppDir || true
|
||||
- bsdtar -zxvf ../rustdesk-1.2.0.deb
|
||||
- tar -xvf ./data.tar.xz
|
||||
- mkdir ./AppDir
|
||||
- mv ./usr ./AppDir/usr
|
||||
# 32x32 icon
|
||||
- for i in {32,64,128}; do mkdir -p ./AppDir/usr/share/icons/hicolor/$i\x$i/apps/; cp ../res/$i\x$i.png ./AppDir/usr/share/icons/hicolor/$i\x$i/apps/rustdesk.png; done
|
||||
# desktop file
|
||||
# - sed -i "s/Icon=\/usr\/share\/rustdesk\/files\/rustdesk.png/Icon=rustdesk/g" ./AppDir/usr/share/applications/rustdesk.desktop
|
||||
- rm -rf ./AppDir/usr/share/applications
|
||||
AppDir:
|
||||
path: ./AppDir
|
||||
app_info:
|
||||
id: rustdesk
|
||||
name: rustdesk
|
||||
icon: rustdesk
|
||||
version: 1.2.0
|
||||
exec: usr/lib/rustdesk/rustdesk
|
||||
exec_args: $@
|
||||
apt:
|
||||
arch:
|
||||
- amd64
|
||||
allow_unauthenticated: true
|
||||
sources:
|
||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic main restricted
|
||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-updates main restricted
|
||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic universe
|
||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-updates universe
|
||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic multiverse
|
||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-updates multiverse
|
||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-backports main restricted
|
||||
universe multiverse
|
||||
- sourceline: deb http://ppa.launchpad.net/pipewire-debian/pipewire-upstream/ubuntu
|
||||
bionic main
|
||||
include:
|
||||
- libc6:amd64
|
||||
- libgtk-3-0
|
||||
- libxcb-randr0
|
||||
- libxdo3
|
||||
- libxfixes3
|
||||
- libxcb-shape0
|
||||
- libxcb-xfixes0
|
||||
- libasound2
|
||||
- libsystemd0
|
||||
- curl
|
||||
- libva-drm2
|
||||
- libva-x11-2
|
||||
- libvdpau1
|
||||
- libgstreamer-plugins-base1.0-0
|
||||
exclude:
|
||||
- humanity-icon-theme
|
||||
- hicolor-icon-theme
|
||||
- adwaita-icon-theme
|
||||
- ubuntu-mono
|
||||
files:
|
||||
include: []
|
||||
exclude:
|
||||
- usr/share/man
|
||||
- usr/share/doc/*/README.*
|
||||
- usr/share/doc/*/changelog.*
|
||||
- usr/share/doc/*/NEWS.*
|
||||
- usr/share/doc/*/TODO.*
|
||||
runtime:
|
||||
env:
|
||||
GIO_MODULE_DIR: $APPDIR/usr/lib/x86_64-linux-gnu/gio/modules/
|
||||
test:
|
||||
fedora-30:
|
||||
image: appimagecrafters/tests-env:fedora-30
|
||||
command: ./AppRun
|
||||
debian-stable:
|
||||
image: appimagecrafters/tests-env:debian-stable
|
||||
command: ./AppRun
|
||||
archlinux-latest:
|
||||
image: appimagecrafters/tests-env:archlinux-latest
|
||||
command: ./AppRun
|
||||
centos-7:
|
||||
image: appimagecrafters/tests-env:centos-7
|
||||
command: ./AppRun
|
||||
ubuntu-xenial:
|
||||
image: appimagecrafters/tests-env:ubuntu-xenial
|
||||
command: ./AppRun
|
||||
AppImage:
|
||||
arch: x86_64
|
||||
update-information: guess
|
||||
19
build.py
19
build.py
@ -99,6 +99,11 @@ def make_parser():
|
||||
action='store_true',
|
||||
help='Build rustdesk libs with the flatpak feature enabled'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--appimage',
|
||||
action='store_true',
|
||||
help='Build rustdesk libs with the appimage feature enabled'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--skip-cargo',
|
||||
action='store_true',
|
||||
@ -236,6 +241,8 @@ def get_features(args):
|
||||
features.append('flutter')
|
||||
if args.flatpak:
|
||||
features.append('flatpak')
|
||||
if args.appimage:
|
||||
features.append('appimage')
|
||||
print("features:", features)
|
||||
return features
|
||||
|
||||
@ -305,7 +312,8 @@ def build_flutter_deb(version, features):
|
||||
|
||||
def build_flutter_dmg(version, features):
|
||||
if not skip_cargo:
|
||||
os.system(f'cargo build --features {features} --lib --release')
|
||||
# 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')
|
||||
# copy dylib
|
||||
os.system(
|
||||
"cp target/release/liblibrustdesk.dylib target/release/librustdesk.dylib")
|
||||
@ -469,6 +477,7 @@ def main():
|
||||
if pa:
|
||||
os.system('''
|
||||
# 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
|
||||
#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/libsciter.dylib
|
||||
#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
|
||||
@ -481,9 +490,15 @@ def main():
|
||||
version, 'rustdesk-%s.dmg' % version)
|
||||
if pa:
|
||||
os.system('''
|
||||
# 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/
|
||||
# goto xcode and login with apple id, manager certificates (Developer ID Application and/or Developer ID Installer) online there (only download and double click (install) cer file can not export p12 because no private key)
|
||||
#rcodesign sign --p12-file ~/.p12/rustdesk-developer-id.p12 --p12-password-file ~/.p12/.cert-pass --code-signature-flags runtime ./rustdesk-{1}.dmg
|
||||
codesign -s "Developer ID Application: {0}" --force --options runtime ./rustdesk-{1}.dmg
|
||||
# https://pyoxidizer.readthedocs.io/en/latest/apple_codesign_rcodesign.html
|
||||
# https://appstoreconnect.apple.com/access/api
|
||||
# https://gregoryszorc.com/docs/apple-codesign/0.16.0/apple_codesign_rcodesign.html#notarizing-and-stapling
|
||||
# p8 file is generated when you generate api key, download and put it under ~/.private_keys/
|
||||
rcodesign notarize --api-issuer {2} --api-key {3} --staple ./rustdesk-{1}.dmg
|
||||
# verify: spctl -a -t exec -v /Applications/RustDesk.app
|
||||
'''.format(pa, version, os.environ.get('api-issuer'), os.environ.get('api-key')))
|
||||
|
||||
16
build.rs
16
build.rs
@ -1,9 +1,16 @@
|
||||
#[cfg(windows)]
|
||||
fn build_windows() {
|
||||
cc::Build::new().file("src/windows.cc").compile("windows");
|
||||
let file = "src/platform/windows.cc";
|
||||
cc::Build::new().file(file).compile("windows");
|
||||
println!("cargo:rustc-link-lib=WtsApi32");
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed=windows.cc");
|
||||
println!("cargo:rerun-if-changed={}", file);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn build_mac() {
|
||||
let file = "src/platform/macos.mm";
|
||||
cc::Build::new().file(file).compile("macos");
|
||||
println!("cargo:rerun-if-changed={}", file);
|
||||
}
|
||||
|
||||
#[cfg(all(windows, feature = "inline"))]
|
||||
@ -117,5 +124,8 @@ fn main() {
|
||||
#[cfg(windows)]
|
||||
build_windows();
|
||||
#[cfg(target_os = "macos")]
|
||||
build_mac();
|
||||
#[cfg(target_os = "macos")]
|
||||
println!("cargo:rustc-link-lib=framework=ApplicationServices");
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
}
|
||||
|
||||
1
flutter/.gitignore
vendored
1
flutter/.gitignore
vendored
@ -54,3 +54,4 @@ lib/generated_bridge.freezed.dart
|
||||
flutter_export_environment.sh
|
||||
Flutter-Generated.xcconfig
|
||||
key.jks
|
||||
macos/rustdesk.xcodeproj/project.xcworkspace/
|
||||
|
||||
@ -1418,7 +1418,7 @@ bool isRunningInPortableMode() {
|
||||
}
|
||||
|
||||
/// Window status callback
|
||||
void onActiveWindowChanged() async {
|
||||
Future<void> onActiveWindowChanged() async {
|
||||
print(
|
||||
"[MultiWindowHandler] active window changed: ${rustDeskWinManager.getActiveWindows()}");
|
||||
if (rustDeskWinManager.getActiveWindows().isEmpty) {
|
||||
|
||||
@ -100,6 +100,8 @@ const kRemoteImageQualityLow = 'low';
|
||||
/// [kRemoteImageQualityCustom] Custom image quality.
|
||||
const kRemoteImageQualityCustom = 'custom';
|
||||
|
||||
const kIgnoreDpi = true;
|
||||
|
||||
/// flutter/packages/flutter/lib/src/services/keyboard_key.dart -> _keyLabels
|
||||
/// see [LogicalKeyboardKey.keyLabel]
|
||||
const Map<int, String> logicalKeyMap = <int, String>{
|
||||
|
||||
@ -6,7 +6,6 @@ import 'dart:io';
|
||||
|
||||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hbb/common/widgets/address_book.dart';
|
||||
import 'package:flutter_hbb/consts.dart';
|
||||
import 'package:flutter_hbb/desktop/widgets/scroll_wrapper.dart';
|
||||
import 'package:get/get.dart';
|
||||
@ -16,7 +15,6 @@ import 'package:window_manager/window_manager.dart';
|
||||
import '../../common.dart';
|
||||
import '../../common/formatter/id_formatter.dart';
|
||||
import '../../common/widgets/peer_tab_page.dart';
|
||||
import '../../common/widgets/peers_view.dart';
|
||||
import '../../models/platform_model.dart';
|
||||
import '../widgets/button.dart';
|
||||
|
||||
@ -172,6 +170,7 @@ class _ConnectionPageState extends State<ConnectionPage>
|
||||
Expanded(
|
||||
child: Obx(
|
||||
() => TextField(
|
||||
maxLength: 90,
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
keyboardType: TextInputType.visiblePassword,
|
||||
@ -179,12 +178,13 @@ class _ConnectionPageState extends State<ConnectionPage>
|
||||
style: const TextStyle(
|
||||
fontFamily: 'WorkSans',
|
||||
fontSize: 22,
|
||||
height: 1,
|
||||
height: 1.25,
|
||||
),
|
||||
maxLines: 1,
|
||||
cursorColor:
|
||||
Theme.of(context).textTheme.titleLarge?.color,
|
||||
decoration: InputDecoration(
|
||||
counterText: '',
|
||||
hintText: _idInputFocused.value
|
||||
? null
|
||||
: translate('Enter Remote ID'),
|
||||
|
||||
@ -42,6 +42,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
var svcStopped = false.obs;
|
||||
var watchIsCanScreenRecording = false;
|
||||
var watchIsProcessTrust = false;
|
||||
var watchIsInputMonitoring = false;
|
||||
Timer? _updateTimer;
|
||||
|
||||
@override
|
||||
@ -334,6 +335,12 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
bind.mainIsProcessTrusted(prompt: true);
|
||||
watchIsProcessTrust = true;
|
||||
}, help: 'Help', link: translate("doc_mac_permission"));
|
||||
} else if (!bind.mainIsCanInputMonitoring(prompt: false)) {
|
||||
return buildInstallCard("Permissions", "config_input", "Configure",
|
||||
() async {
|
||||
bind.mainIsCanInputMonitoring(prompt: true);
|
||||
watchIsInputMonitoring = true;
|
||||
}, help: 'Help', link: translate("doc_mac_permission"));
|
||||
} else if (!svcStopped.value &&
|
||||
bind.mainIsInstalled() &&
|
||||
!bind.mainIsInstalledDaemon(prompt: false)) {
|
||||
@ -467,6 +474,12 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
if (watchIsInputMonitoring) {
|
||||
if (bind.mainIsCanInputMonitoring(prompt: false)) {
|
||||
watchIsInputMonitoring = false;
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
});
|
||||
Get.put<RxBool>(svcStopped, tag: 'stop-service');
|
||||
rustDeskWinManager.registerActiveWindowListener(onActiveWindowChanged);
|
||||
@ -500,9 +513,9 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
} else if (call.method == kWindowActionRebuild) {
|
||||
reloadCurrentWindow();
|
||||
} else if (call.method == kWindowEventShow) {
|
||||
rustDeskWinManager.registerActiveWindow(call.arguments["id"]);
|
||||
await rustDeskWinManager.registerActiveWindow(call.arguments["id"]);
|
||||
} else if (call.method == kWindowEventHide) {
|
||||
rustDeskWinManager.unregisterActiveWindow(call.arguments["id"]);
|
||||
await rustDeskWinManager.unregisterActiveWindow(call.arguments["id"]);
|
||||
} else if (call.method == kWindowConnect) {
|
||||
await connectMainDesktop(
|
||||
call.arguments['id'],
|
||||
|
||||
@ -274,6 +274,15 @@ class _GeneralState extends State<_General> {
|
||||
_OptionCheckBox(context, 'Confirm before closing multiple tabs',
|
||||
'enable-confirm-closing-tabs'),
|
||||
_OptionCheckBox(context, 'Adaptive Bitrate', 'enable-abr'),
|
||||
if (Platform.isLinux)
|
||||
Tooltip(
|
||||
message: translate('software_render_tip'),
|
||||
child: _OptionCheckBox(
|
||||
context,
|
||||
"Always use software rendering",
|
||||
'allow-always-software-render',
|
||||
),
|
||||
)
|
||||
]);
|
||||
}
|
||||
|
||||
@ -1223,7 +1232,7 @@ Widget _OptionCheckBox(BuildContext context, String label, String key,
|
||||
ref.value = option;
|
||||
if (reverse) option = !option;
|
||||
String value = bool2option(key, option);
|
||||
bind.mainSetOption(key: key, value: value);
|
||||
await bind.mainSetOption(key: key, value: value);
|
||||
update?.call();
|
||||
}
|
||||
}
|
||||
|
||||
@ -402,35 +402,36 @@ class _ImagePaintState extends State<ImagePaint> {
|
||||
onHover: (evt) {},
|
||||
child: child));
|
||||
|
||||
if (c.scrollStyle == ScrollStyle.scrollbar) {
|
||||
if (c.imageOverflow.isTrue && c.scrollStyle == ScrollStyle.scrollbar) {
|
||||
final imageWidth = c.getDisplayWidth() * s;
|
||||
final imageHeight = c.getDisplayHeight() * s;
|
||||
final imageSize = Size(imageWidth, imageHeight);
|
||||
final imageWidget = CustomPaint(
|
||||
size: Size(imageWidth, imageHeight),
|
||||
size: imageSize,
|
||||
painter: ImagePainter(image: m.image, x: 0, y: 0, scale: s),
|
||||
);
|
||||
|
||||
return NotificationListener<ScrollNotification>(
|
||||
onNotification: (notification) {
|
||||
final percentX = _horizontal.hasClients
|
||||
? _horizontal.position.extentBefore /
|
||||
(_horizontal.position.extentBefore +
|
||||
_horizontal.position.extentInside +
|
||||
_horizontal.position.extentAfter)
|
||||
: 0.0;
|
||||
final percentY = _vertical.hasClients
|
||||
? _vertical.position.extentBefore /
|
||||
(_vertical.position.extentBefore +
|
||||
_vertical.position.extentInside +
|
||||
_vertical.position.extentAfter)
|
||||
: 0.0;
|
||||
c.setScrollPercent(percentX, percentY);
|
||||
return false;
|
||||
},
|
||||
child: mouseRegion(
|
||||
child: _buildCrossScrollbar(context, _buildListener(imageWidget),
|
||||
Size(imageWidth, imageHeight))),
|
||||
);
|
||||
onNotification: (notification) {
|
||||
final percentX = _horizontal.hasClients
|
||||
? _horizontal.position.extentBefore /
|
||||
(_horizontal.position.extentBefore +
|
||||
_horizontal.position.extentInside +
|
||||
_horizontal.position.extentAfter)
|
||||
: 0.0;
|
||||
final percentY = _vertical.hasClients
|
||||
? _vertical.position.extentBefore /
|
||||
(_vertical.position.extentBefore +
|
||||
_vertical.position.extentInside +
|
||||
_vertical.position.extentAfter)
|
||||
: 0.0;
|
||||
c.setScrollPercent(percentX, percentY);
|
||||
return false;
|
||||
},
|
||||
child: mouseRegion(
|
||||
child: Obx(() => _buildCrossScrollbarFromLayout(
|
||||
context, _buildListener(imageWidget), c.size, imageSize)),
|
||||
));
|
||||
} else {
|
||||
final imageWidget = CustomPaint(
|
||||
size: Size(c.size.width, c.size.height),
|
||||
@ -565,24 +566,6 @@ class _ImagePaintState extends State<ImagePaint> {
|
||||
return widget;
|
||||
}
|
||||
|
||||
Widget _buildCrossScrollbar(BuildContext context, Widget child, Size size) {
|
||||
var layoutSize = MediaQuery.of(context).size;
|
||||
// If minimized, w or h may be negative here.
|
||||
final w = layoutSize.width - kWindowBorderWidth * 2;
|
||||
final h =
|
||||
layoutSize.height - kWindowBorderWidth * 2 - kDesktopRemoteTabBarHeight;
|
||||
layoutSize = Size(
|
||||
w < 0 ? 0 : w,
|
||||
h < 0 ? 0 : h,
|
||||
);
|
||||
bool overflow =
|
||||
layoutSize.width < size.width || layoutSize.height < size.height;
|
||||
return overflow
|
||||
? Obx(() =>
|
||||
_buildCrossScrollbarFromLayout(context, child, layoutSize, size))
|
||||
: _buildCrossScrollbarFromLayout(context, child, layoutSize, size);
|
||||
}
|
||||
|
||||
Widget _buildListener(Widget child) {
|
||||
if (listenerBuilder != null) {
|
||||
return listenerBuilder!(child);
|
||||
|
||||
@ -118,6 +118,15 @@ abstract class MenuEntryBase<T> {
|
||||
this.enabled,
|
||||
});
|
||||
List<mod_menu.PopupMenuEntry<T>> build(BuildContext context, MenuConfig conf);
|
||||
|
||||
enabledStyle(BuildContext context) => TextStyle(
|
||||
color: Theme.of(context).textTheme.titleLarge?.color,
|
||||
fontSize: MenuConfig.fontSize,
|
||||
fontWeight: FontWeight.normal);
|
||||
disabledStyle() => TextStyle(
|
||||
color: Colors.grey,
|
||||
fontSize: MenuConfig.fontSize,
|
||||
fontWeight: FontWeight.normal);
|
||||
}
|
||||
|
||||
class MenuEntryDivider<T> extends MenuEntryBase<T> {
|
||||
@ -189,54 +198,76 @@ class MenuEntryRadios<T> extends MenuEntryBase<T> {
|
||||
|
||||
mod_menu.PopupMenuEntry<T> _buildMenuItem(
|
||||
BuildContext context, MenuConfig conf, MenuEntryRadioOption opt) {
|
||||
Widget getTextChild() {
|
||||
final enabledTextChild = Text(
|
||||
opt.text,
|
||||
style: enabledStyle(context),
|
||||
);
|
||||
final disabledTextChild = Text(
|
||||
opt.text,
|
||||
style: disabledStyle(),
|
||||
);
|
||||
if (opt.enabled == null) {
|
||||
return enabledTextChild;
|
||||
} else {
|
||||
return Obx(
|
||||
() => opt.enabled!.isTrue ? enabledTextChild : disabledTextChild);
|
||||
}
|
||||
}
|
||||
|
||||
final child = Container(
|
||||
padding: padding,
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
constraints:
|
||||
BoxConstraints(minHeight: conf.height, maxHeight: conf.height),
|
||||
child: Row(
|
||||
children: [
|
||||
getTextChild(),
|
||||
Expanded(
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Transform.scale(
|
||||
scale: MenuConfig.iconScale,
|
||||
child: Obx(() => opt.value == curOption.value
|
||||
? IconButton(
|
||||
padding:
|
||||
const EdgeInsets.fromLTRB(8.0, 0.0, 8.0, 0.0),
|
||||
hoverColor: Colors.transparent,
|
||||
focusColor: Colors.transparent,
|
||||
onPressed: () {},
|
||||
icon: Icon(
|
||||
Icons.check,
|
||||
color: (opt.enabled ?? true.obs).isTrue
|
||||
? conf.commonColor
|
||||
: Colors.grey,
|
||||
))
|
||||
: const SizedBox.shrink()),
|
||||
))),
|
||||
],
|
||||
),
|
||||
);
|
||||
onPressed() {
|
||||
if (opt.dismissOnClicked && Navigator.canPop(context)) {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
setOption(opt.value);
|
||||
}
|
||||
|
||||
return mod_menu.PopupMenuItem(
|
||||
padding: EdgeInsets.zero,
|
||||
height: conf.height,
|
||||
child: Container(
|
||||
width: conf.boxWidth,
|
||||
child: TextButton(
|
||||
child: Container(
|
||||
padding: padding,
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
constraints: BoxConstraints(
|
||||
minHeight: conf.height, maxHeight: conf.height),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
opt.text,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).textTheme.titleLarge?.color,
|
||||
fontSize: MenuConfig.fontSize,
|
||||
fontWeight: FontWeight.normal),
|
||||
),
|
||||
Expanded(
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Transform.scale(
|
||||
scale: MenuConfig.iconScale,
|
||||
child: Obx(() => opt.value == curOption.value
|
||||
? IconButton(
|
||||
padding: const EdgeInsets.fromLTRB(
|
||||
8.0, 0.0, 8.0, 0.0),
|
||||
hoverColor: Colors.transparent,
|
||||
focusColor: Colors.transparent,
|
||||
onPressed: () {},
|
||||
icon: Icon(
|
||||
Icons.check,
|
||||
color: conf.commonColor,
|
||||
))
|
||||
: const SizedBox.shrink()),
|
||||
))),
|
||||
],
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
if (opt.dismissOnClicked && Navigator.canPop(context)) {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
setOption(opt.value);
|
||||
},
|
||||
)),
|
||||
width: conf.boxWidth,
|
||||
child: opt.enabled == null
|
||||
? TextButton(
|
||||
child: child,
|
||||
onPressed: onPressed,
|
||||
)
|
||||
: Obx(() => TextButton(
|
||||
child: child,
|
||||
onPressed: opt.enabled!.isTrue ? onPressed : null,
|
||||
)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -567,12 +598,9 @@ class MenuEntrySubMenu<T> extends MenuEntryBase<T> {
|
||||
const SizedBox(width: MenuConfig.midPadding),
|
||||
Obx(() => Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
color: super.enabled!.value
|
||||
? Theme.of(context).textTheme.titleLarge?.color
|
||||
: Colors.grey,
|
||||
fontSize: MenuConfig.fontSize,
|
||||
fontWeight: FontWeight.normal),
|
||||
style: super.enabled!.value
|
||||
? enabledStyle(context)
|
||||
: disabledStyle(),
|
||||
)),
|
||||
Expanded(
|
||||
child: Align(
|
||||
@ -605,14 +633,6 @@ class MenuEntryButton<T> extends MenuEntryBase<T> {
|
||||
);
|
||||
|
||||
Widget _buildChild(BuildContext context, MenuConfig conf) {
|
||||
final enabledStyle = TextStyle(
|
||||
color: Theme.of(context).textTheme.titleLarge?.color,
|
||||
fontSize: MenuConfig.fontSize,
|
||||
fontWeight: FontWeight.normal);
|
||||
const disabledStyle = TextStyle(
|
||||
color: Colors.grey,
|
||||
fontSize: MenuConfig.fontSize,
|
||||
fontWeight: FontWeight.normal);
|
||||
super.enabled ??= true.obs;
|
||||
return Obx(() => Container(
|
||||
width: conf.boxWidth,
|
||||
@ -631,7 +651,7 @@ class MenuEntryButton<T> extends MenuEntryBase<T> {
|
||||
constraints:
|
||||
BoxConstraints(minHeight: conf.height, maxHeight: conf.height),
|
||||
child: childBuilder(
|
||||
super.enabled!.value ? enabledStyle : disabledStyle),
|
||||
super.enabled!.value ? enabledStyle(context) : disabledStyle()),
|
||||
),
|
||||
)));
|
||||
}
|
||||
|
||||
@ -699,7 +699,7 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
||||
if (_screen == null) {
|
||||
return false;
|
||||
}
|
||||
double scale = _screen!.scaleFactor;
|
||||
final scale = kIgnoreDpi ? 1.0 : _screen!.scaleFactor;
|
||||
double selfWidth = _screen!.visibleFrame.width;
|
||||
double selfHeight = _screen!.visibleFrame.height;
|
||||
if (isFullscreen) {
|
||||
@ -936,11 +936,13 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
||||
text: translate('ScrollAuto'),
|
||||
value: kRemoteScrollStyleAuto,
|
||||
dismissOnClicked: true,
|
||||
enabled: widget.ffi.canvasModel.imageOverflow,
|
||||
),
|
||||
MenuEntryRadioOption(
|
||||
text: translate('Scrollbar'),
|
||||
value: kRemoteScrollStyleBar,
|
||||
dismissOnClicked: true,
|
||||
enabled: widget.ffi.canvasModel.imageOverflow,
|
||||
),
|
||||
],
|
||||
curOptionGetter: () async =>
|
||||
@ -986,15 +988,17 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
||||
wndRect.bottom - wndRect.top - mediaSize.height * scale;
|
||||
|
||||
final canvasModel = widget.ffi.canvasModel;
|
||||
final width = (canvasModel.getDisplayWidth() +
|
||||
canvasModel.windowBorderWidth * 2) *
|
||||
scale +
|
||||
magicWidth;
|
||||
final height = (canvasModel.getDisplayHeight() +
|
||||
canvasModel.tabBarHeight +
|
||||
canvasModel.windowBorderWidth * 2) *
|
||||
scale +
|
||||
magicHeight;
|
||||
final width =
|
||||
(canvasModel.getDisplayWidth() * canvasModel.scale +
|
||||
canvasModel.windowBorderWidth * 2) *
|
||||
scale +
|
||||
magicWidth;
|
||||
final height =
|
||||
(canvasModel.getDisplayHeight() * canvasModel.scale +
|
||||
canvasModel.tabBarHeight +
|
||||
canvasModel.windowBorderWidth * 2) *
|
||||
scale +
|
||||
magicHeight;
|
||||
double left = wndRect.left + (wndRect.width - width) / 2;
|
||||
double top = wndRect.top + (wndRect.height - height) / 2;
|
||||
|
||||
@ -1198,7 +1202,6 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
||||
},
|
||||
optionSetter: (String oldValue, String newValue) async {
|
||||
await bind.sessionSetKeyboardMode(id: widget.id, value: newValue);
|
||||
widget.ffi.canvasModel.updateViewStyle();
|
||||
},
|
||||
)
|
||||
];
|
||||
|
||||
@ -527,13 +527,19 @@ class WindowActionPanelState extends State<WindowActionPanel>
|
||||
void onWindowClose() async {
|
||||
// hide window on close
|
||||
if (widget.isMainWindow) {
|
||||
await rustDeskWinManager.unregisterActiveWindow(0);
|
||||
// `hide` must be placed after unregisterActiveWindow, because once all windows are hidden,
|
||||
// flutter closes the application on macOS. We should ensure the post-run logic has ran successfully.
|
||||
// e.g.: saving window position.
|
||||
await windowManager.hide();
|
||||
rustDeskWinManager.unregisterActiveWindow(0);
|
||||
} else {
|
||||
widget.onClose?.call();
|
||||
// it's safe to hide the subwindow
|
||||
await WindowController.fromWindowId(windowId!).hide();
|
||||
rustDeskWinManager
|
||||
.call(WindowType.Main, kWindowEventHide, {"id": windowId!});
|
||||
await Future.wait([
|
||||
rustDeskWinManager
|
||||
.call(WindowType.Main, kWindowEventHide, {"id": windowId!}),
|
||||
widget.onClose?.call() ?? Future.microtask(() => null)
|
||||
]);
|
||||
}
|
||||
super.onWindowClose();
|
||||
}
|
||||
|
||||
@ -196,6 +196,8 @@ void runMultiWindow(
|
||||
// no such appType
|
||||
exit(0);
|
||||
}
|
||||
// show window from hidden status
|
||||
WindowController.fromWindowId(windowId!).show();
|
||||
}
|
||||
|
||||
void runConnectionManagerScreen(bool hide) async {
|
||||
|
||||
@ -466,15 +466,21 @@ class InputModel {
|
||||
evt['y'] = '${y.round()}';
|
||||
var buttons = '';
|
||||
switch (evt['buttons']) {
|
||||
case 1:
|
||||
case kPrimaryMouseButton:
|
||||
buttons = 'left';
|
||||
break;
|
||||
case 2:
|
||||
case kSecondaryMouseButton:
|
||||
buttons = 'right';
|
||||
break;
|
||||
case 4:
|
||||
case kMiddleMouseButton:
|
||||
buttons = 'wheel';
|
||||
break;
|
||||
case kBackMouseButton:
|
||||
buttons = 'back';
|
||||
break;
|
||||
case kForwardMouseButton:
|
||||
buttons = 'forward';
|
||||
break;
|
||||
}
|
||||
evt['buttons'] = buttons;
|
||||
bind.sessionSendMouse(id: id, msg: json.encode(evt));
|
||||
|
||||
@ -22,6 +22,7 @@ import 'package:tuple/tuple.dart';
|
||||
import 'package:image/image.dart' as img2;
|
||||
import 'package:flutter_custom_cursor/cursor_manager.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../common.dart';
|
||||
import '../common/shared_state.dart';
|
||||
@ -528,6 +529,7 @@ class CanvasModel with ChangeNotifier {
|
||||
double _y = 0;
|
||||
// image scale
|
||||
double _scale = 1.0;
|
||||
Size _size = Size.zero;
|
||||
// the tabbar over the image
|
||||
// double tabBarHeight = 0.0;
|
||||
// the window border's width
|
||||
@ -541,6 +543,8 @@ class CanvasModel with ChangeNotifier {
|
||||
ScrollStyle _scrollStyle = ScrollStyle.scrollauto;
|
||||
ViewStyle _lastViewStyle = ViewStyle();
|
||||
|
||||
final _imageOverflow = false.obs;
|
||||
|
||||
WeakReference<FFI> parent;
|
||||
|
||||
CanvasModel(this.parent);
|
||||
@ -548,8 +552,10 @@ class CanvasModel with ChangeNotifier {
|
||||
double get x => _x;
|
||||
double get y => _y;
|
||||
double get scale => _scale;
|
||||
Size get size => _size;
|
||||
ScrollStyle get scrollStyle => _scrollStyle;
|
||||
ViewStyle get viewStyle => _lastViewStyle;
|
||||
RxBool get imageOverflow => _imageOverflow;
|
||||
|
||||
_resetScroll() => setScrollPercent(0.0, 0.0);
|
||||
|
||||
@ -562,18 +568,26 @@ class CanvasModel with ChangeNotifier {
|
||||
double get scrollY => _scrollY;
|
||||
|
||||
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;
|
||||
return Size(w < 0 ? 0 : w, h < 0 ? 0 : h);
|
||||
}
|
||||
|
||||
final style = await bind.sessionGetViewStyle(id: id);
|
||||
if (style == null) {
|
||||
return;
|
||||
}
|
||||
final sizeWidth = size.width;
|
||||
final sizeHeight = size.height;
|
||||
|
||||
_size = getSize();
|
||||
final displayWidth = getDisplayWidth();
|
||||
final displayHeight = getDisplayHeight();
|
||||
final viewStyle = ViewStyle(
|
||||
style: style,
|
||||
width: sizeWidth,
|
||||
height: sizeHeight,
|
||||
width: size.width,
|
||||
height: size.height,
|
||||
displayWidth: displayWidth,
|
||||
displayHeight: displayHeight,
|
||||
);
|
||||
@ -585,8 +599,13 @@ class CanvasModel with ChangeNotifier {
|
||||
}
|
||||
_lastViewStyle = viewStyle;
|
||||
_scale = viewStyle.scale;
|
||||
_x = (sizeWidth - displayWidth * _scale) / 2;
|
||||
_y = (sizeHeight - displayHeight * _scale) / 2;
|
||||
|
||||
if (kIgnoreDpi && style == kRemoteViewStyleOriginal) {
|
||||
_scale = 1.0 / ui.window.devicePixelRatio;
|
||||
}
|
||||
_x = (size.width - displayWidth * _scale) / 2;
|
||||
_y = (size.height - displayHeight * _scale) / 2;
|
||||
_imageOverflow.value = _x < 0 || y < 0;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@ -628,14 +647,6 @@ class CanvasModel with ChangeNotifier {
|
||||
double get windowBorderWidth => stateGlobal.windowBorderWidth.value;
|
||||
double get tabBarHeight => stateGlobal.tabBarHeight;
|
||||
|
||||
Size get size {
|
||||
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;
|
||||
return Size(w < 0 ? 0 : w, h < 0 ? 0 : h);
|
||||
}
|
||||
|
||||
moveDesktopMouse(double x, double y) {
|
||||
// On mobile platforms, move the canvas with the cursor.
|
||||
final dw = getDisplayWidth() * _scale;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:desktop_multi_window/desktop_multi_window.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hbb/common.dart';
|
||||
@ -34,7 +35,7 @@ class RustDeskMultiWindowManager {
|
||||
static final instance = RustDeskMultiWindowManager._();
|
||||
|
||||
final List<int> _activeWindows = List.empty(growable: true);
|
||||
final List<VoidCallback> _windowActiveCallbacks = List.empty(growable: true);
|
||||
final List<AsyncCallback> _windowActiveCallbacks = List.empty(growable: true);
|
||||
int? _remoteDesktopWindowId;
|
||||
int? _fileTransferWindowId;
|
||||
int? _portForwardWindowId;
|
||||
@ -191,19 +192,19 @@ class RustDeskMultiWindowManager {
|
||||
return _activeWindows;
|
||||
}
|
||||
|
||||
void _notifyActiveWindow() {
|
||||
Future<void> _notifyActiveWindow() async {
|
||||
for (final callback in _windowActiveCallbacks) {
|
||||
callback.call();
|
||||
await callback.call();
|
||||
}
|
||||
}
|
||||
|
||||
void registerActiveWindow(int windowId) {
|
||||
Future<void> registerActiveWindow(int windowId) async {
|
||||
if (_activeWindows.contains(windowId)) {
|
||||
// ignore
|
||||
} else {
|
||||
_activeWindows.add(windowId);
|
||||
}
|
||||
_notifyActiveWindow();
|
||||
await _notifyActiveWindow();
|
||||
}
|
||||
|
||||
/// Remove active window which has [`windowId`]
|
||||
@ -212,20 +213,20 @@ class RustDeskMultiWindowManager {
|
||||
/// This function should only be called from main window.
|
||||
/// For other windows, please post a unregister(hide) event to main window handler:
|
||||
/// `rustDeskWinManager.call(WindowType.Main, kWindowEventHide, {"id": windowId!});`
|
||||
void unregisterActiveWindow(int windowId) {
|
||||
Future<void> unregisterActiveWindow(int windowId) async {
|
||||
if (!_activeWindows.contains(windowId)) {
|
||||
// ignore
|
||||
} else {
|
||||
_activeWindows.remove(windowId);
|
||||
}
|
||||
_notifyActiveWindow();
|
||||
await _notifyActiveWindow();
|
||||
}
|
||||
|
||||
void registerActiveWindowListener(VoidCallback callback) {
|
||||
void registerActiveWindowListener(AsyncCallback callback) {
|
||||
_windowActiveCallbacks.add(callback);
|
||||
}
|
||||
|
||||
void unregisterActiveWindowListener(VoidCallback callback) {
|
||||
void unregisterActiveWindowListener(AsyncCallback callback) {
|
||||
_windowActiveCallbacks.remove(callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,7 +23,15 @@ static void my_application_activate(GApplication* application) {
|
||||
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
|
||||
// we have custom window frame
|
||||
gtk_window_set_decorated(window, FALSE);
|
||||
|
||||
// try setting icon for rustdesk, which uses the system cache
|
||||
GtkIconTheme* theme = gtk_icon_theme_get_default();
|
||||
gint icons[4] = {256, 128, 64, 32};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
GdkPixbuf* icon = gtk_icon_theme_load_icon(theme, "rustdesk", icons[i], GTK_ICON_LOOKUP_NO_SVG, NULL);
|
||||
if (icon != nullptr) {
|
||||
gtk_window_set_icon(window, icon);
|
||||
}
|
||||
}
|
||||
// Use a header bar when running in GNOME as this is the common style used
|
||||
// by applications and is the setup most users will be using (e.g. Ubuntu
|
||||
// desktop).
|
||||
|
||||
@ -411,6 +411,7 @@
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
@ -436,8 +437,11 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@ -546,6 +550,7 @@
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
@ -558,6 +563,12 @@
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_LDFLAGS = (
|
||||
"-sectcreate",
|
||||
__CGPreLoginApp,
|
||||
__cgpreloginapp,
|
||||
/dev/null,
|
||||
);
|
||||
SDKROOT = macosx;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
@ -571,8 +582,10 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@ -598,8 +611,11 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@ -610,6 +626,12 @@
|
||||
../../target/release,
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
OTHER_LDFLAGS = (
|
||||
"-sectcreate",
|
||||
__CGPreLoginApp,
|
||||
__cgpreloginapp,
|
||||
/dev/null,
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.carriez.rustdesk;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
"SWIFT_OBJC_BRIDGING_HEADER[arch=*]" = Runner/bridge_generated.h;
|
||||
|
||||
@ -6,6 +6,8 @@
|
||||
<false/>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.audio-input</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
</dict>
|
||||
|
||||
@ -49,7 +49,8 @@ class MainFlutterWindow: NSWindow {
|
||||
super.awakeFromNib()
|
||||
}
|
||||
|
||||
// override func bitsdojo_window_configure() -> UInt {
|
||||
// return BDW_CUSTOM_FRAME | BDW_HIDE_ON_STARTUP
|
||||
// }
|
||||
override public func order(_ place: NSWindow.OrderingMode, relativeTo otherWin: Int) {
|
||||
super.order(place, relativeTo: otherWin)
|
||||
hiddenWindowAtLaunch()
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,10 @@
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<false/>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.audio-input</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
</dict>
|
||||
|
||||
@ -108,6 +108,12 @@
|
||||
PRODUCT_NAME = rustdesk;
|
||||
SDKROOT = macosx;
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
OTHER_LDFLAGS = (
|
||||
"-sectcreate",
|
||||
__CGPreLoginApp,
|
||||
__cgpreloginapp,
|
||||
/dev/null,
|
||||
);
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
||||
@ -35,7 +35,7 @@ packages:
|
||||
name: archive
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.3.1"
|
||||
version: "3.3.5"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -63,7 +63,7 @@ packages:
|
||||
name: back_button_interceptor
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.0.1"
|
||||
version: "6.0.2"
|
||||
bot_toast:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -84,7 +84,7 @@ packages:
|
||||
name: build_config
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.1.1"
|
||||
build_daemon:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -105,14 +105,14 @@ packages:
|
||||
name: build_runner
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
version: "2.3.3"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_runner_core
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "7.2.4"
|
||||
version: "7.2.7"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -126,7 +126,7 @@ packages:
|
||||
name: built_value
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "8.4.1"
|
||||
version: "8.4.2"
|
||||
cached_network_image:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -154,7 +154,7 @@ packages:
|
||||
name: characters
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
version: "1.2.0"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -175,14 +175,14 @@ packages:
|
||||
name: clock
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
version: "1.1.0"
|
||||
code_builder:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: code_builder
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.3.0"
|
||||
version: "4.4.0"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -203,7 +203,7 @@ packages:
|
||||
name: convert
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
version: "3.1.0"
|
||||
cross_file:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -352,7 +352,7 @@ packages:
|
||||
name: file_picker
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.2.3"
|
||||
version: "5.2.4"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -441,7 +441,7 @@ packages:
|
||||
name: flutter_svg
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.5"
|
||||
version: "1.1.6"
|
||||
flutter_web_plugins:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@ -467,7 +467,7 @@ packages:
|
||||
name: frontend_server_client
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
version: "3.2.0"
|
||||
get:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -481,21 +481,21 @@ packages:
|
||||
name: glob
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "2.1.1"
|
||||
graphs:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: graphs
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "2.2.0"
|
||||
html:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: html
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.15.0"
|
||||
version: "0.15.1"
|
||||
http:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -516,7 +516,7 @@ packages:
|
||||
name: http_parser
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.0.1"
|
||||
version: "4.0.2"
|
||||
icons_launcher:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@ -530,7 +530,7 @@ packages:
|
||||
name: image
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.2.0"
|
||||
version: "3.2.2"
|
||||
image_picker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -544,7 +544,7 @@ packages:
|
||||
name: image_picker_android
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.8.5+3"
|
||||
version: "0.8.5+4"
|
||||
image_picker_for_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -558,7 +558,7 @@ packages:
|
||||
name: image_picker_ios
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.8.6+1"
|
||||
version: "0.8.6+3"
|
||||
image_picker_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -600,7 +600,7 @@ packages:
|
||||
name: lints
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
version: "2.0.1"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -621,14 +621,14 @@ packages:
|
||||
name: material_color_utilities
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.5"
|
||||
version: "0.1.4"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.0"
|
||||
version: "1.7.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -705,7 +705,7 @@ packages:
|
||||
name: path
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.2"
|
||||
version: "1.8.1"
|
||||
path_drawing:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -733,7 +733,7 @@ packages:
|
||||
name: path_provider_android
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.20"
|
||||
version: "2.0.22"
|
||||
path_provider_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -797,6 +797,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
pointycastle:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pointycastle
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.6.2"
|
||||
pool:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -817,14 +824,14 @@ packages:
|
||||
name: provider
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.0.3"
|
||||
version: "6.0.5"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pub_semver
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.1.3"
|
||||
pubspec_parse:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -845,7 +852,7 @@ packages:
|
||||
name: rxdart
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.27.5"
|
||||
version: "0.27.7"
|
||||
screen_retriever:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -882,7 +889,7 @@ packages:
|
||||
name: shelf_web_socket
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
version: "1.0.3"
|
||||
simple_observable:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -901,7 +908,7 @@ packages:
|
||||
name: source_gen
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.5"
|
||||
version: "1.2.6"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -922,7 +929,7 @@ packages:
|
||||
name: sqflite_common
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
version: "2.4.0"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -943,7 +950,7 @@ packages:
|
||||
name: stream_transform
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "2.1.0"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1034,14 +1041,14 @@ packages:
|
||||
name: url_launcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.1.6"
|
||||
version: "6.1.7"
|
||||
url_launcher_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_android
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.0.19"
|
||||
version: "6.0.22"
|
||||
url_launcher_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1090,7 +1097,7 @@ packages:
|
||||
name: uuid
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.6"
|
||||
version: "3.0.7"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1104,35 +1111,35 @@ packages:
|
||||
name: video_player
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.4.9"
|
||||
version: "2.4.10"
|
||||
video_player_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: video_player_android
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.3.9"
|
||||
version: "2.3.10"
|
||||
video_player_avfoundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: video_player_avfoundation
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.3.7"
|
||||
version: "2.3.8"
|
||||
video_player_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: video_player_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.1.4"
|
||||
version: "6.0.1"
|
||||
video_player_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: video_player_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.12"
|
||||
version: "2.0.13"
|
||||
visibility_detector:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -1181,7 +1188,7 @@ packages:
|
||||
name: watcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
version: "1.0.2"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1195,7 +1202,7 @@ packages:
|
||||
name: win32
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
version: "3.1.3"
|
||||
win32_registry:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@ -63,7 +63,7 @@ dependencies:
|
||||
desktop_multi_window:
|
||||
git:
|
||||
url: https://github.com/Kingtous/rustdesk_desktop_multi_window
|
||||
ref: 82f9eab81cb2c7bfb938def7a1b399a6279bbc75
|
||||
ref: 057e6eb1bc7dcbcf9dafd1384274a611e4fe7124
|
||||
freezed_annotation: ^2.0.3
|
||||
flutter_custom_cursor: ^0.0.2
|
||||
window_size:
|
||||
|
||||
@ -104,6 +104,10 @@ pub enum MouseButton {
|
||||
Middle,
|
||||
/// Right mouse button
|
||||
Right,
|
||||
/// Back mouse button
|
||||
Back,
|
||||
/// Forward mouse button
|
||||
Forward,
|
||||
|
||||
/// Scroll up button
|
||||
ScrollUp,
|
||||
|
||||
@ -57,6 +57,8 @@ fn mousebutton(button: MouseButton) -> c_int {
|
||||
MouseButton::ScrollDown => 5,
|
||||
MouseButton::ScrollLeft => 6,
|
||||
MouseButton::ScrollRight => 7,
|
||||
MouseButton::Back => 8,
|
||||
MouseButton::Forward => 9,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -226,7 +226,10 @@ impl MouseControllable for Enigo {
|
||||
MouseButton::Left => (CGMouseButton::Left, CGEventType::LeftMouseDown),
|
||||
MouseButton::Middle => (CGMouseButton::Center, CGEventType::OtherMouseDown),
|
||||
MouseButton::Right => (CGMouseButton::Right, CGEventType::RightMouseDown),
|
||||
_ => unimplemented!(),
|
||||
_ => {
|
||||
log::info!("Unsupported button {:?}", button);
|
||||
return Ok(());
|
||||
},
|
||||
};
|
||||
let dest = CGPoint::new(current_x as f64, current_y as f64);
|
||||
if let Some(src) = self.event_source.as_ref() {
|
||||
@ -249,7 +252,10 @@ impl MouseControllable for Enigo {
|
||||
MouseButton::Left => (CGMouseButton::Left, CGEventType::LeftMouseUp),
|
||||
MouseButton::Middle => (CGMouseButton::Center, CGEventType::OtherMouseUp),
|
||||
MouseButton::Right => (CGMouseButton::Right, CGEventType::RightMouseUp),
|
||||
_ => unimplemented!(),
|
||||
_ => {
|
||||
log::info!("Unsupported button {:?}", button);
|
||||
return;
|
||||
},
|
||||
};
|
||||
let dest = CGPoint::new(current_x as f64, current_y as f64);
|
||||
if let Some(src) = self.event_source.as_ref() {
|
||||
|
||||
@ -56,6 +56,20 @@ fn keybd_event(flags: u32, vk: u16, scan: u16) -> DWORD {
|
||||
input.type_ = INPUT_KEYBOARD;
|
||||
unsafe {
|
||||
let dst_ptr = (&mut input.u as *mut _) as *mut u8;
|
||||
let flags = match vk as _ {
|
||||
winapi::um::winuser::VK_HOME |
|
||||
winapi::um::winuser::VK_UP |
|
||||
winapi::um::winuser::VK_PRIOR |
|
||||
winapi::um::winuser::VK_LEFT |
|
||||
winapi::um::winuser::VK_RIGHT |
|
||||
winapi::um::winuser::VK_END |
|
||||
winapi::um::winuser::VK_DOWN |
|
||||
winapi::um::winuser::VK_NEXT |
|
||||
winapi::um::winuser::VK_INSERT |
|
||||
winapi::um::winuser::VK_DELETE => flags | winapi::um::winuser::KEYEVENTF_EXTENDEDKEY,
|
||||
_ => flags,
|
||||
};
|
||||
|
||||
let k = KEYBDINPUT {
|
||||
wVk: vk,
|
||||
wScan: scan,
|
||||
@ -134,9 +148,18 @@ impl MouseControllable for Enigo {
|
||||
MouseButton::Left => MOUSEEVENTF_LEFTDOWN,
|
||||
MouseButton::Middle => MOUSEEVENTF_MIDDLEDOWN,
|
||||
MouseButton::Right => MOUSEEVENTF_RIGHTDOWN,
|
||||
_ => unimplemented!(),
|
||||
MouseButton::Back => MOUSEEVENTF_XDOWN,
|
||||
MouseButton::Forward => MOUSEEVENTF_XDOWN,
|
||||
_ => {
|
||||
log::info!("Unsupported button {:?}", button);
|
||||
return Ok(());
|
||||
}
|
||||
},
|
||||
match button {
|
||||
MouseButton::Back => XBUTTON1 as _,
|
||||
MouseButton::Forward => XBUTTON2 as _,
|
||||
_ => 0,
|
||||
},
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
);
|
||||
@ -155,9 +178,18 @@ impl MouseControllable for Enigo {
|
||||
MouseButton::Left => MOUSEEVENTF_LEFTUP,
|
||||
MouseButton::Middle => MOUSEEVENTF_MIDDLEUP,
|
||||
MouseButton::Right => MOUSEEVENTF_RIGHTUP,
|
||||
_ => unimplemented!(),
|
||||
MouseButton::Back => MOUSEEVENTF_XUP,
|
||||
MouseButton::Forward => MOUSEEVENTF_XUP,
|
||||
_ => {
|
||||
log::info!("Unsupported button {:?}", button);
|
||||
return;
|
||||
}
|
||||
},
|
||||
match button {
|
||||
MouseButton::Back => XBUTTON1 as _,
|
||||
MouseButton::Forward => XBUTTON2 as _,
|
||||
_ => 0,
|
||||
},
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
);
|
||||
|
||||
@ -4,7 +4,6 @@ use std::{io, sync::RwLock, time::Duration};
|
||||
|
||||
pub struct Capturer(Display, Box<dyn Recorder>, bool, Vec<u8>);
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const IS_CURSOR_EMBEDDED: bool = true;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
|
||||
@ -3,7 +3,6 @@ use std::{io, ops, time::Duration};
|
||||
|
||||
pub struct Capturer(x11::Capturer);
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const IS_CURSOR_EMBEDDED: bool = false;
|
||||
|
||||
impl Capturer {
|
||||
|
||||
BIN
res/64x64.png
Normal file
BIN
res/64x64.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
@ -38,6 +38,17 @@ pub fn core_main() -> Option<Vec<String>> {
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(feature = "flutter")]
|
||||
{
|
||||
crate::platform::linux::register_breakdown_handler();
|
||||
let (k, v) = ("LIBGL_ALWAYS_SOFTWARE", "true");
|
||||
if !hbb_common::config::Config::get_option("allow-always-software-render").is_empty() {
|
||||
std::env::set_var(k, v);
|
||||
} else {
|
||||
std::env::remove_var(k);
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "flutter")]
|
||||
if _is_flutter_connect {
|
||||
return core_main_invoke_new_connection(std::env::args());
|
||||
|
||||
@ -885,9 +885,11 @@ pub fn session_send_mouse(id: String, msg: String) {
|
||||
}
|
||||
if let Some(buttons) = m.get("buttons") {
|
||||
mask |= match buttons.as_str() {
|
||||
"left" => 1,
|
||||
"right" => 2,
|
||||
"wheel" => 4,
|
||||
"left" => 0x01,
|
||||
"right" => 0x02,
|
||||
"wheel" => 0x04,
|
||||
"back" => 0x08,
|
||||
"forward" => 0x10,
|
||||
_ => 0,
|
||||
} << 3;
|
||||
}
|
||||
@ -1111,6 +1113,10 @@ pub fn main_is_can_screen_recording(prompt: bool) -> SyncReturn<bool> {
|
||||
SyncReturn(is_can_screen_recording(prompt))
|
||||
}
|
||||
|
||||
pub fn main_is_can_input_monitoring(prompt: bool) -> SyncReturn<bool> {
|
||||
SyncReturn(is_can_input_monitoring(prompt))
|
||||
}
|
||||
|
||||
pub fn main_is_share_rdp() -> SyncReturn<bool> {
|
||||
SyncReturn(is_share_rdp())
|
||||
}
|
||||
|
||||
@ -30,6 +30,7 @@ mod sv;
|
||||
mod sq;
|
||||
mod sr;
|
||||
mod th;
|
||||
mod sl;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref LANGS: Value =
|
||||
@ -63,6 +64,7 @@ lazy_static::lazy_static! {
|
||||
("sq", "Shqip"),
|
||||
("sr", "Srpski"),
|
||||
("th", "ภาษาไทย"),
|
||||
("sl", "Slovenščina"),
|
||||
]);
|
||||
}
|
||||
|
||||
@ -120,6 +122,7 @@ pub fn translate_locale(name: String, locale: &str) -> String {
|
||||
"sq" => sq::T.deref(),
|
||||
"sr" => sr::T.deref(),
|
||||
"th" => th::T.deref(),
|
||||
"sl" => sl::T.deref(),
|
||||
_ => en::T.deref(),
|
||||
};
|
||||
if let Some(v) = m.get(&name as &str) {
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Password", "密码"),
|
||||
("Ready", "就绪"),
|
||||
("Established", "已建立"),
|
||||
("connecting_status", "正在接入RustDesk网络..."),
|
||||
("connecting_status", "正在接入 RustDesk 网络..."),
|
||||
("Enable Service", "允许服务"),
|
||||
("Start Service", "启动服务"),
|
||||
("Service is running", "服务正在运行"),
|
||||
@ -138,13 +138,13 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Failed to make direct connection to remote desktop", "无法建立直接连接"),
|
||||
("Set Password", "设置密码"),
|
||||
("OS Password", "操作系统密码"),
|
||||
("install_tip", "你正在运行未安装版本,由于UAC限制,作为被控端,会在某些情况下无法控制鼠标键盘,或者录制屏幕,请点击下面的按钮将RustDesk安装到系统,从而规避上述问题。"),
|
||||
("install_tip", "你正在运行未安装版本,由于UAC限制,作为被控端,会在某些情况下无法控制鼠标键盘,或者录制屏幕,请点击下面的按钮将 RustDesk 安装到系统,从而规避上述问题。"),
|
||||
("Click to upgrade", "点击这里升级"),
|
||||
("Click to download", "点击这里下载"),
|
||||
("Click to update", "点击这里更新"),
|
||||
("Configure", "配置"),
|
||||
("config_acc", "为了能够远程控制你的桌面, 请给予RustDesk\"辅助功能\" 权限。"),
|
||||
("config_screen", "为了能够远程访问你的桌面, 请给予RustDesk\"屏幕录制\" 权限。"),
|
||||
("config_acc", "为了能够远程控制你的桌面, 请给予 RustDesk \"辅助功能\" 权限。"),
|
||||
("config_screen", "为了能够远程访问你的桌面, 请给予 RustDesk \"屏幕录制\" 权限。"),
|
||||
("Installing ...", "安装 ..."),
|
||||
("Install", "安装"),
|
||||
("Installation", "安装"),
|
||||
@ -303,9 +303,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("In privacy mode", "进入隐私模式"),
|
||||
("Out privacy mode", "退出隐私模式"),
|
||||
("Language", "语言"),
|
||||
("Keep RustDesk background service", "保持RustDesk后台服务"),
|
||||
("Keep RustDesk background service", "保持 RustDesk 后台服务"),
|
||||
("Ignore Battery Optimizations", "忽略电池优化"),
|
||||
("android_open_battery_optimizations_tip", "如需关闭此功能,请在接下来的RustDesk应用设置页面中,找到并进入 [电源] 页面,取消勾选 [不受限制]"),
|
||||
("android_open_battery_optimizations_tip", "如需关闭此功能,请在接下来的 RustDesk 应用设置页面中,找到并进入 [电源] 页面,取消勾选 [不受限制]"),
|
||||
("Connection not allowed", "对方不允许连接"),
|
||||
("Legacy mode", "传统模式"),
|
||||
("Map mode", "1:1传输"),
|
||||
@ -385,7 +385,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland 需要更高版本的 linux 发行版。 请尝试 X11 桌面或更改您的操作系统。"),
|
||||
("JumpLink", "查看"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "请选择要分享的画面(对端操作)。"),
|
||||
("Show RustDesk", "显示rustdesk"),
|
||||
("Show RustDesk", "显示 RustDesk"),
|
||||
("This PC", "此电脑"),
|
||||
("or", "或"),
|
||||
("Continue with", "使用"),
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", "被web控制台手动关闭"),
|
||||
("Local keyboard type", "本地键盘类型"),
|
||||
("Select local keyboard type", "请选择本地键盘类型"),
|
||||
("software_render_tip", "如果你使用英伟达显卡, 并且远程窗口在会话建立后会立刻关闭, 那么安装nouveau驱动并且选择使用软件渲染可能会有帮助。重启软件后生效。"),
|
||||
("Always use software rendering", "使用软件渲染"),
|
||||
("config_input", "为了能够通过键盘控制远程桌面, 请给予 RustDesk \"输入监控\" 权限。"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Established", "Verbunden"),
|
||||
("connecting_status", "Verbinden mit dem RustDesk-Netzwerk..."),
|
||||
("Enable Service", "Vermittlungsdienst aktivieren"),
|
||||
("Start Service", "Starte Vermittlungsdienst"),
|
||||
("Start Service", "Vermittlungsdienst starten"),
|
||||
("Service is running", "Vermittlungsdienst aktiv"),
|
||||
("Service is not running", "Vermittlungsdienst deaktiviert"),
|
||||
("not_ready_status", "Nicht bereit. Bitte überprüfen Sie Ihre Netzwerkverbindung."),
|
||||
@ -35,7 +35,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Export server configuration successfully", "Serverkonfiguration erfolgreich exportiert"),
|
||||
("Invalid server configuration", "Ungültige Serverkonfiguration"),
|
||||
("Clipboard is empty", "Zwischenablage ist leer"),
|
||||
("Stop service", "Vermittlungsdienst deaktivieren"),
|
||||
("Stop service", "Vermittlungsdienst stoppen"),
|
||||
("Change ID", "ID ändern"),
|
||||
("Website", "Webseite"),
|
||||
("About", "Über"),
|
||||
@ -165,7 +165,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Local Port", "Lokaler Port"),
|
||||
("Local Address", "Lokale Adresse"),
|
||||
("Change Local Port", "Lokalen Port ändern"),
|
||||
("setup_server_tip", "für eine schnellere Verbindung richten Sie bitte Ihren eigenen Verbindungsserver ein."),
|
||||
("setup_server_tip", "für eine schnellere Verbindung richten Sie bitte Ihren eigenen Server ein."),
|
||||
("Too short, at least 6 characters.", "Zu kurz, mindestens 6 Zeichen."),
|
||||
("The confirmation is not identical.", "Die Passwörter stimmen nicht überein."),
|
||||
("Permissions", "Berechtigungen"),
|
||||
@ -244,7 +244,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Are you sure to close the connection?", "Möchten Sie diese Verbindung wirklich trennen?"),
|
||||
("Download new version", "Neue Version herunterladen"),
|
||||
("Touch mode", "Touch-Modus"),
|
||||
("Mouse mode", "Maus-Modus"),
|
||||
("Mouse mode", "Mausmodus"),
|
||||
("One-Finger Tap", "1-Finger-Tipp"),
|
||||
("Left Mouse", "Linksklick"),
|
||||
("One-Long Tap", "1-Finger-Halten"),
|
||||
@ -260,8 +260,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Pinch to Zoom", "2-Finger-Zoom"),
|
||||
("Canvas Zoom", "Sichtfeld-Zoom"),
|
||||
("Reset canvas", "Sichtfeld zurücksetzen"),
|
||||
("No permission of file transfer", "Keine Berechtigung für den Dateizugriff"),
|
||||
("Note", "Anmerkung"),
|
||||
("No permission of file transfer", "Keine Berechtigung für die Dateiübertragung"),
|
||||
("Note", "Hinweis"),
|
||||
("Connection", "Verbindung"),
|
||||
("Share Screen", "Bildschirm freigeben"),
|
||||
("CLOSE", "DEAKTIV."),
|
||||
@ -278,7 +278,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Do you accept?", "Verbindung zulassen?"),
|
||||
("Open System Setting", "Systemeinstellung öffnen"),
|
||||
("How to get Android input permission?", "Wie erhalte ich eine Android-Eingabeberechtigung?"),
|
||||
("android_input_permission_tip1", "Damit ein Remote-Gerät Ihr Android-Gerät steuern kann, müssen Sie RustDesk erlauben, den Dienst \"Barrierefreiheit\" zu verwenden."),
|
||||
("android_input_permission_tip1", "Damit ein entferntes Gerät Ihr Android-Gerät steuern kann, müssen Sie RustDesk erlauben, den Dienst \"Barrierefreiheit\" zu verwenden."),
|
||||
("android_input_permission_tip2", "Bitte gehen Sie zur nächsten Systemeinstellungsseite, suchen Sie [Installierte Dienste] und schalten Sie den Dienst [RustDesk Input] ein."),
|
||||
("android_new_connection_tip", "möchte ihr Gerät steuern."),
|
||||
("android_service_will_start_tip", "Durch das Aktivieren der Bildschirmfreigabe wird der Dienst automatisch gestartet, sodass andere Geräte dieses Android-Gerät steuern können."),
|
||||
@ -295,9 +295,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Succeeded", "Erfolgreich"),
|
||||
("Someone turns on privacy mode, exit", "Jemand hat den Datenschutzmodus aktiviert, beende..."),
|
||||
("Unsupported", "Nicht unterstützt"),
|
||||
("Peer denied", "Die Gegenstelle hat die Verbindung abgelehnt"),
|
||||
("Peer denied", "Die Gegenstelle hat die Verbindung abgelehnt."),
|
||||
("Please install plugins", "Bitte installieren Sie Plugins"),
|
||||
("Peer exit", "Die Gegenstelle hat die Verbindung getrennt"),
|
||||
("Peer exit", "Die Gegenstelle hat die Verbindung getrennt."),
|
||||
("Failed to turn off", "Ausschalten fehlgeschlagen"),
|
||||
("Turned off", "Ausgeschaltet"),
|
||||
("In privacy mode", "Datenschutzmodus aktivieren"),
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", "Manuell über die Webkonsole beendet"),
|
||||
("Local keyboard type", "Lokaler Tastaturtyp"),
|
||||
("Select local keyboard type", "Lokalen Tastaturtyp auswählen"),
|
||||
("software_render_tip", "Wenn Sie eine Nvidia-Grafikkarte haben und sich das entfernte Fenster sofort nach dem Herstellen der Verbindung schließt, kann es helfen, den Nouveau-Treiber zu installieren und Software-Rendering zu verwenden. Ein Neustart der Software ist erforderlich."),
|
||||
("Always use software rendering", "Software-Rendering immer verwenden"),
|
||||
("config_input", "Um den entfernten Desktop mit der Tastatur steuern zu können, müssen Sie RustDesk \"Input Monitoring\"-Rechte erteilen."),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -37,5 +37,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("wayland_experiment_tip", "Wayland support is in experimental stage, please use X11 if you require unattended access."),
|
||||
("Slogan_tip", "Made with heart in this chaotic world!"),
|
||||
("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."),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Change ID", "Cambiar ID"),
|
||||
("Website", "Sitio web"),
|
||||
("About", "Acerca de"),
|
||||
("Slogan_tip", ""),
|
||||
("Slogan_tip", "Hecho con corazón en este mundo caótico!"),
|
||||
("Privacy Statement", ""),
|
||||
("Mute", "Silenciar"),
|
||||
("Audio Input", "Entrada de audio"),
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", "Cerrado manualmente por la consola web"),
|
||||
("Local keyboard type", "Tipo de teclado local"),
|
||||
("Select local keyboard type", "Seleccionar tipo de teclado local"),
|
||||
("software_render_tip", "Si tienes una gráfica Nvidia y la ventana remota se cierra inmediatamente, instalar el driver nouveau y elegir renderizado por software podría ayudar. Se requiere reiniciar la aplicación."),
|
||||
("Always use software rendering", "Usar siempre renderizado por software"),
|
||||
("config_input", "Para controlar el escritorio remoto con el teclado necesitas dar a RustDesk permisos de \"Monitorización de entrada\"."),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", "Fermé manuellement par la console Web"),
|
||||
("Local keyboard type", "Disposition du clavier local"),
|
||||
("Select local keyboard type", "Selectionner la disposition du clavier local"),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", "Chiudi manualmente dalla console Web"),
|
||||
("Local keyboard type", "Tipo di tastiera locale"),
|
||||
("Select local keyboard type", "Seleziona il tipo di tastiera locale"),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -206,7 +206,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the peer", "Закрыто удалённым узлом вручную"),
|
||||
("Enable remote configuration modification", "Разрешить удалённое изменение конфигурации"),
|
||||
("Run without install", "Запустить без установки"),
|
||||
("Always connected via relay", "Всегда подключён через ретрансляционный сервер"),
|
||||
("Always connected via relay", "Всегда подключается через ретрансляционный сервер"),
|
||||
("Always connect via relay", "Всегда подключаться через ретрансляционный сервер"),
|
||||
("whitelist_tip", "Только IP-адреса из белого списка могут получить доступ ко мне"),
|
||||
("Login", "Войти"),
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", "Закрыто вручную через веб-консоль"),
|
||||
("Local keyboard type", "Тип локальной клавиатуры"),
|
||||
("Select local keyboard type", "Выберите тип локальной клавиатуры"),
|
||||
("software_render_tip", "Если у вас видеокарта Nvidia и удалённое окно закрывается сразу после подключения, может помочь установка драйвера Nouveau и выбор использования программной визуализации. Потребуется перезапуск."),
|
||||
("Always use software rendering", "Использовать программную визуализацию"),
|
||||
("config_input", "Чтобы управлять удалённым рабочим столом с помощью клавиатуры, необходимо предоставить RustDesk разрешения \"Мониторинг ввода\"."),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
417
src/lang/sl.rs
Executable file
417
src/lang/sl.rs
Executable file
@ -0,0 +1,417 @@
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
[
|
||||
("Status", "Stanje"),
|
||||
("Your Desktop", "Vaše namizje"),
|
||||
("desk_tip", "Do vašega namizja lahko dostopate s spodnjim IDjem in geslom"),
|
||||
("Password", "Geslo"),
|
||||
("Ready", "Pripravljen"),
|
||||
("Established", "Povezava vzpostavljena"),
|
||||
("connecting_status", "Vzpostavljanje povezave z omrežjem RustDesk..."),
|
||||
("Enable Service", "Omogoči storitev"),
|
||||
("Start Service", "Zaženi storitev"),
|
||||
("Service is running", "Storitev se izvaja"),
|
||||
("Service is not running", "Storitev se ne izvaja"),
|
||||
("not_ready_status", "Ni pripravljeno, preverite vašo mrežno povezavo"),
|
||||
("Control Remote Desktop", "Nadzoruj oddaljeno namizje"),
|
||||
("Transfer File", "Prenos datotek"),
|
||||
("Connect", "Poveži"),
|
||||
("Recent Sessions", "Nedavne seje"),
|
||||
("Address Book", "Adresar"),
|
||||
("Confirmation", "Potrditev"),
|
||||
("TCP Tunneling", "TCP tuneliranje"),
|
||||
("Remove", "Odstrani"),
|
||||
("Refresh random password", "Osveži naključno geslo"),
|
||||
("Set your own password", "Nastavi lastno geslo"),
|
||||
("Enable Keyboard/Mouse", "Omogoči tipkovnico in miško"),
|
||||
("Enable Clipboard", "Omogoči odložišče"),
|
||||
("Enable File Transfer", "Omogoči prenos datotek"),
|
||||
("Enable TCP Tunneling", "Omogoči TCP tuneliranje"),
|
||||
("IP Whitelisting", "Omogoči seznam dovoljenih IPjev"),
|
||||
("ID/Relay Server", "Strežnik za ID/posredovanje"),
|
||||
("Import Server Config", "Uvozi nastavitve strežnika"),
|
||||
("Export Server Config", "Izvozi nastavitve strežnika"),
|
||||
("Import server configuration successfully", "Nastavitve strežnika uspešno uvožene"),
|
||||
("Export server configuration successfully", "Nastavitve strežnika uspešno izvožene"),
|
||||
("Invalid server configuration", "Neveljavne nastavitve strežnika"),
|
||||
("Clipboard is empty", "Odložišče je prazno"),
|
||||
("Stop service", "Ustavi storitev"),
|
||||
("Change ID", "Spremeni ID"),
|
||||
("Website", "Spletna stran"),
|
||||
("About", "O programu"),
|
||||
("Slogan_tip", ""),
|
||||
("Privacy Statement", ""),
|
||||
("Mute", "Izklopi zvok"),
|
||||
("Audio Input", "Avdio vhod"),
|
||||
("Enhancements", "Izboljšave"),
|
||||
("Hardware Codec", "Strojni kodek"),
|
||||
("Adaptive Bitrate", "Prilagodljiva bitna hitrost"),
|
||||
("ID Server", "ID strežnik"),
|
||||
("Relay Server", "Posredniški strežnik"),
|
||||
("API Server", "API strežnik"),
|
||||
("invalid_http", "mora se začeti s http:// ali https://"),
|
||||
("Invalid IP", "Neveljaven IP"),
|
||||
("id_change_tip", "Dovoljeni znaki so a-z, A-Z (brez šumnikov), 0-9 in _. Prvi znak mora biti črka, dolžina od 6 do 16 znakov."),
|
||||
("Invalid format", "Neveljavna oblika"),
|
||||
("server_not_support", "Strežnik še ne podpira"),
|
||||
("Not available", "Ni na voljo"),
|
||||
("Too frequent", "Prepogosto"),
|
||||
("Cancel", "Prekliči"),
|
||||
("Skip", "Izpusti"),
|
||||
("Close", "Zapri"),
|
||||
("Retry", "Ponovi"),
|
||||
("OK", "V redu"),
|
||||
("Password Required", "Potrebno je geslo"),
|
||||
("Please enter your password", "Vnesite vaše geslo"),
|
||||
("Remember password", "Zapomni si geslo"),
|
||||
("Wrong Password", "Napačno geslo"),
|
||||
("Do you want to enter again?", "Želite znova vnesti?"),
|
||||
("Connection Error", "Napaka pri povezavi"),
|
||||
("Error", "Napaka"),
|
||||
("Reset by the peer", "Povezava prekinjena"),
|
||||
("Connecting...", "Povezovanje..."),
|
||||
("Connection in progress. Please wait.", "Vzpostavljanje povezave, prosim počakajte."),
|
||||
("Please try 1 minute later", "Poizkusite čez 1 minuto"),
|
||||
("Login Error", "Napaka pri prijavi"),
|
||||
("Successful", "Uspešno"),
|
||||
("Connected, waiting for image...", "Povezava vzpostavljena, čakam na sliko..."),
|
||||
("Name", "Ime"),
|
||||
("Type", "Vrsta"),
|
||||
("Modified", "Čas spremembe"),
|
||||
("Size", "Velikost"),
|
||||
("Show Hidden Files", "Prikaži skrite datoteke"),
|
||||
("Receive", "Prejmi"),
|
||||
("Send", "Pošlji"),
|
||||
("Refresh File", "Osveži datoteko"),
|
||||
("Local", "Lokalno"),
|
||||
("Remote", "Oddaljeno"),
|
||||
("Remote Computer", "Oddaljeni računalnik"),
|
||||
("Local Computer", "Lokalni računalnik"),
|
||||
("Confirm Delete", "Potrdi izbris"),
|
||||
("Delete", "Izbriši"),
|
||||
("Properties", "Lastnosti"),
|
||||
("Multi Select", "Večkratna izbira"),
|
||||
("Select All", "Izberi vse"),
|
||||
("Unselect All", "Počisti vse"),
|
||||
("Empty Directory", "Prazen imenik"),
|
||||
("Not an empty directory", "Imenik ni prazen"),
|
||||
("Are you sure you want to delete this file?", "Ali res želite izbrisati to datoteko?"),
|
||||
("Are you sure you want to delete this empty directory?", "Ali res želite izbrisati to prazno mapo?"),
|
||||
("Are you sure you want to delete the file of this directory?", "Ali res želite datoteko iz mape?"),
|
||||
("Do this for all conflicts", "Naredi to za vse"),
|
||||
("This is irreversible!", "Tega dejanja ni mogoče razveljaviti!"),
|
||||
("Deleting", "Brisanje"),
|
||||
("files", "datoteke"),
|
||||
("Waiting", "Čakanje"),
|
||||
("Finished", "Opravljeno"),
|
||||
("Speed", "Hitrost"),
|
||||
("Custom Image Quality", "Kakovost slike po meri"),
|
||||
("Privacy mode", "Zasebni način"),
|
||||
("Block user input", "Onemogoči uporabnikov vnos"),
|
||||
("Unblock user input", "Omogoči uporabnikov vnos"),
|
||||
("Adjust Window", "Prilagodi okno"),
|
||||
("Original", "Originalno"),
|
||||
("Shrink", "Skrči"),
|
||||
("Stretch", "Raztegni"),
|
||||
("Scrollbar", "Drsenje z drsniki"),
|
||||
("ScrollAuto", "Samodejno drsenje"),
|
||||
("Good image quality", "Visoka kakovost slike"),
|
||||
("Balanced", "Uravnoteženo"),
|
||||
("Optimize reaction time", "Optimiraj odzivni čas"),
|
||||
("Custom", "Po meri"),
|
||||
("Show remote cursor", "Prikaži oddaljeni kazalec miške"),
|
||||
("Show quality monitor", "Prikaži nadzornik kakovosti"),
|
||||
("Disable clipboard", "Onemogoči odložišče"),
|
||||
("Lock after session end", "Zakleni ob koncu seje"),
|
||||
("Insert", "Vstavi"),
|
||||
("Insert Lock", "Zakleni oddaljeni računalnik"),
|
||||
("Refresh", "Osveži"),
|
||||
("ID does not exist", "ID ne obstaja"),
|
||||
("Failed to connect to rendezvous server", "Ni se bilo mogoče povezati na povezovalni strežnik"),
|
||||
("Please try later", "Poizkusite znova kasneje"),
|
||||
("Remote desktop is offline", "Oddaljeno namizje ni dosegljivo"),
|
||||
("Key mismatch", "Ključ ni ustrezen"),
|
||||
("Timeout", "Časovna omejitev"),
|
||||
("Failed to connect to relay server", "Ni se bilo mogoče povezati na posredniški strežnik"),
|
||||
("Failed to connect via rendezvous server", "Ni se bilo mogoče povezati preko povezovalnega strežnika"),
|
||||
("Failed to connect via relay server", "Ni se bilo mogoče povezati preko posredniškega strežnika"),
|
||||
("Failed to make direct connection to remote desktop", "Ni bilo mogoče vzpostaviti neposredne povezave z oddaljenim namizjem"),
|
||||
("Set Password", "Nastavi geslo"),
|
||||
("OS Password", "Geslo operacijskega sistema"),
|
||||
("install_tip", "Zaradi nadzora uporabniškega računa, RustDesk v nekaterih primerih na oddaljeni strani ne deluje pravilno. Temu se lahko izognete z namestitvijo."),
|
||||
("Click to upgrade", "Klikni za nadgradnjo"),
|
||||
("Click to download", "Klikni za prenos"),
|
||||
("Click to update", "Klikni za posodobitev"),
|
||||
("Configure", "Nastavi"),
|
||||
("config_acc", "Za oddaljeni nadzor namizja morate RustDesku dodeliti pravico za dostopnost"),
|
||||
("config_screen", "Za oddaljeni dostop do namizja morate RustDesku dodeliti pravico snemanje zaslona"),
|
||||
("Installing ...", "Nameščanje..."),
|
||||
("Install", "Namesti"),
|
||||
("Installation", "Namestitev"),
|
||||
("Installation Path", "Pot za namestitev"),
|
||||
("Create start menu shortcuts", "Ustvari bližnjice v meniju Začetek"),
|
||||
("Create desktop icon", "Ustvari ikono na namizju"),
|
||||
("agreement_tip", "Z namestitvijo se strinjate z licenčno pogodbo"),
|
||||
("Accept and Install", "Sprejmi in namesti"),
|
||||
("End-user license agreement", "Licenčna pogodba za končnega uporabnika"),
|
||||
("Generating ...", "Ustvarjanje ..."),
|
||||
("Your installation is lower version.", "Vaša namestitev je starejša"),
|
||||
("not_close_tcp_tip", "Med uporabo tunela ne zaprite tega okna"),
|
||||
("Listening ...", "Poslušam ..."),
|
||||
("Remote Host", "Oddaljeni gostitelj"),
|
||||
("Remote Port", "Oddaljena vrata"),
|
||||
("Action", "Dejanje"),
|
||||
("Add", "Dodaj"),
|
||||
("Local Port", "Lokalna vrata"),
|
||||
("Local Address", "Lokalni naslov"),
|
||||
("Change Local Port", "Spremeni lokalna vrata"),
|
||||
("setup_server_tip", "Za hitrejšo povezavo uporabite lasten strežnik"),
|
||||
("Too short, at least 6 characters.", "Prekratek, mora biti najmanj 6 znakov."),
|
||||
("The confirmation is not identical.", "Potrditev ni enaka."),
|
||||
("Permissions", "Dovoljenja"),
|
||||
("Accept", "Sprejmi"),
|
||||
("Dismiss", "Opusti"),
|
||||
("Disconnect", "Prekini povezavo"),
|
||||
("Allow using keyboard and mouse", "Dovoli uporabo tipkovnice in miške"),
|
||||
("Allow using clipboard", "Dovoli uporabo odložišča"),
|
||||
("Allow hearing sound", "Dovoli prenos zvoka"),
|
||||
("Allow file copy and paste", "Dovoli kopiranje in lepljenje datotek"),
|
||||
("Connected", "Povezan"),
|
||||
("Direct and encrypted connection", "Neposredna šifrirana povezava"),
|
||||
("Relayed and encrypted connection", "Posredovana šifrirana povezava"),
|
||||
("Direct and unencrypted connection", "Neposredna nešifrirana povezava"),
|
||||
("Relayed and unencrypted connection", "Posredovana šifrirana povezava"),
|
||||
("Enter Remote ID", "Vnesi oddaljeni ID"),
|
||||
("Enter your password", "Vnesi geslo"),
|
||||
("Logging in...", "Prijavljanje..."),
|
||||
("Enable RDP session sharing", "Omogoči deljenje RDP seje"),
|
||||
("Auto Login", "Samodejna prijava"),
|
||||
("Enable Direct IP Access", "Omogoči neposredni dostop preko IP"),
|
||||
("Rename", "Preimenuj"),
|
||||
("Space", "Prazno"),
|
||||
("Create Desktop Shortcut", "Ustvari bližnjico na namizju"),
|
||||
("Change Path", "Spremeni pot"),
|
||||
("Create Folder", "Ustvari mapo"),
|
||||
("Please enter the folder name", "Vnesite ime mape"),
|
||||
("Fix it", "Popravi"),
|
||||
("Warning", "Opozorilo"),
|
||||
("Login screen using Wayland is not supported", "Prijava z Waylandom ni podprta"),
|
||||
("Reboot required", "Potreben je ponovni zagon"),
|
||||
("Unsupported display server ", "Nepodprt zaslonski strežnik"),
|
||||
("x11 expected", "Pričakovan X11"),
|
||||
("Port", "Vrata"),
|
||||
("Settings", "Nastavitve"),
|
||||
("Username", "Uporabniško ime"),
|
||||
("Invalid port", "Neveljavno geslo"),
|
||||
("Closed manually by the peer", "Povezavo ročno prekinil odjemalec"),
|
||||
("Enable remote configuration modification", "Omogoči oddaljeno spreminjanje nastavitev"),
|
||||
("Run without install", "Zaženi brez namestitve"),
|
||||
("Always connected via relay", "Vedno povezan preko posrednika"),
|
||||
("Always connect via relay", "Vedno poveži preko posrednika"),
|
||||
("whitelist_tip", "Dostop je možen samo iz dovoljenih IPjev"),
|
||||
("Login", "Prijavi"),
|
||||
("Verify", ""),
|
||||
("Remember me", ""),
|
||||
("Trust this device", ""),
|
||||
("Verification code", ""),
|
||||
("verification_tip", ""),
|
||||
("Logout", "Odjavi"),
|
||||
("Tags", "Oznake"),
|
||||
("Search ID", "Išči ID"),
|
||||
("Current Wayland display server is not supported", "Trenutni Wayland zaslonski strežnik ni podprt"),
|
||||
("whitelist_sep", "Naslovi ločeni z vejico, podpičjem, presledkom ali novo vrstico"),
|
||||
("Add ID", "Dodaj ID"),
|
||||
("Add Tag", "Dodaj oznako"),
|
||||
("Unselect all tags", ""),
|
||||
("Network error", "Omrežna napaka"),
|
||||
("Username missed", "Up. ime izpuščeno"),
|
||||
("Password missed", "Geslo izpuščeno"),
|
||||
("Wrong credentials", "Napačne poverilnice"),
|
||||
("Edit Tag", "Uredi oznako"),
|
||||
("Unremember Password", "Pozabi geslo"),
|
||||
("Favorites", "Priljubljene"),
|
||||
("Add to Favorites", "Dodaj med priljubljene"),
|
||||
("Remove from Favorites", "Odstrani iz priljubljenih"),
|
||||
("Empty", "Prazno"),
|
||||
("Invalid folder name", "Napačno ime mape"),
|
||||
("Socks5 Proxy", "Socks5 posredniški strežnik"),
|
||||
("Hostname", "Ime gostitelja"),
|
||||
("Discovered", "Odkriti"),
|
||||
("install_daemon_tip", "Za samodejni zagon ob vklopu računalnika je potrebno dodati sistemsko storitev"),
|
||||
("Remote ID", "Oddaljeni ID"),
|
||||
("Paste", "Prilepi"),
|
||||
("Paste here?", "Prilepi tu?"),
|
||||
("Are you sure to close the connection?", "Ali želite prekiniti povezavo?"),
|
||||
("Download new version", "Prenesi novo različico"),
|
||||
("Touch mode", "Način dotika"),
|
||||
("Mouse mode", "Način mišle"),
|
||||
("One-Finger Tap", "Tap z enim prstom"),
|
||||
("Left Mouse", "Leva tipka miške"),
|
||||
("One-Long Tap", "Dolg tap z enim prstom"),
|
||||
("Two-Finger Tap", "Tap z dvema prstoma"),
|
||||
("Right Mouse", "Desna tipka miške"),
|
||||
("One-Finger Move", "Premik z enim prstom"),
|
||||
("Double Tap & Move", "Dvojni tap in premik"),
|
||||
("Mouse Drag", "Vlečenje z miško"),
|
||||
("Three-Finger vertically", "Triprstno navpično"),
|
||||
("Mouse Wheel", "Miškino kolesce"),
|
||||
("Two-Finger Move", "Premik z dvema prstoma"),
|
||||
("Canvas Move", "Premik platna"),
|
||||
("Pinch to Zoom", "Povečava s približevanjem prstov"),
|
||||
("Canvas Zoom", "Povečava platna"),
|
||||
("Reset canvas", "Ponastavi platno"),
|
||||
("No permission of file transfer", "Ni pravic za prenos datotek"),
|
||||
("Note", "Opomba"),
|
||||
("Connection", "Povezava"),
|
||||
("Share Screen", "Deli zaslon"),
|
||||
("CLOSE", "ZAPRI"),
|
||||
("OPEN", "ODPRI"),
|
||||
("Chat", "Pogovor"),
|
||||
("Total", "Skupaj"),
|
||||
("items", "elementi"),
|
||||
("Selected", "Izbrano"),
|
||||
("Screen Capture", "Zajem zaslona"),
|
||||
("Input Control", "Nadzor vnosa"),
|
||||
("Audio Capture", "Zajem zvoka"),
|
||||
("File Connection", "Datotečna povezava"),
|
||||
("Screen Connection", "Zaslonska povezava"),
|
||||
("Do you accept?", "Ali sprejmete?"),
|
||||
("Open System Setting", "Odpri sistemske nastavitve"),
|
||||
("How to get Android input permission?", "Kako pridobiti dovoljenje za vnos na Androidu?"),
|
||||
("android_input_permission_tip1", "Za oddaljeni nadzor vaše naprave Android, je potrebno RustDesku dodeliti pravico za dostopnost."),
|
||||
("android_input_permission_tip2", "Pojdite v sistemske nastavitve, poiščite »Nameščene storitve« in vklopite storitev »RustDesk Input«."),
|
||||
("android_new_connection_tip", "Prejeta je bila zahteva za oddaljeni nadzor vaše naprave."),
|
||||
("android_service_will_start_tip", "Z vklopom zajema zaslona se bo samodejno zagnala storitev, ki omogoča da oddaljene naprave pošljejo zahtevo za povezavo na vašo napravo."),
|
||||
("android_stop_service_tip", "Z zaustavitvijo storitve bodo samodejno prekinjene vse oddaljene povezave."),
|
||||
("android_version_audio_tip", "Trenutna različica Androida ne omogoča zajema zvoka. Za zajem zvoka nadgradite na Android 10 ali novejši."),
|
||||
("android_start_service_tip", "Tapnite »Zaženi storitev« ali »ODPRI« pri dovoljenju za zajem zaslona da zaženete storitev deljenja zaslona."),
|
||||
("Account", "Račun"),
|
||||
("Overwrite", "Prepiši"),
|
||||
("This file exists, skip or overwrite this file?", "Datoteka obstaja, izpusti ali prepiši?"),
|
||||
("Quit", "Izhod"),
|
||||
("doc_mac_permission", "https://rustdesk.com/docs/en/manual/mac/#enable-permissions"),
|
||||
("Help", "Pomoč"),
|
||||
("Failed", "Ni uspelo"),
|
||||
("Succeeded", "Uspelo"),
|
||||
("Someone turns on privacy mode, exit", "Vklopljen je zasebni način, izhod"),
|
||||
("Unsupported", "Ni podprto"),
|
||||
("Peer denied", "Odjemalec zavrnil"),
|
||||
("Please install plugins", "Namestite vključke"),
|
||||
("Peer exit", "Odjemalec se je zaprl"),
|
||||
("Failed to turn off", "Ni bilo mogoče izklopiti"),
|
||||
("Turned off", "Izklopljeno"),
|
||||
("In privacy mode", "V zasebnem načinu"),
|
||||
("Out privacy mode", "Iz zasebnega načina"),
|
||||
("Language", "Jezik"),
|
||||
("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«"),
|
||||
("Connection not allowed", "Povezava ni dovoljena"),
|
||||
("Legacy mode", "Stari način"),
|
||||
("Map mode", "Način preslikave"),
|
||||
("Translate mode", "Način prevajanja"),
|
||||
("Use permanent password", "Uporabi stalno geslo"),
|
||||
("Use both passwords", "Uporabi obe gesli"),
|
||||
("Set permanent password", "Nastavi stalno geslo"),
|
||||
("Enable Remote Restart", "Omogoči oddaljeni ponovni zagon"),
|
||||
("Allow remote restart", "Dovoli oddaljeni ponovni zagon"),
|
||||
("Restart Remote Device", "Znova zaženi oddaljeno napravo"),
|
||||
("Are you sure you want to restart", "Ali ste prepričani, da želite znova zagnati"),
|
||||
("Restarting Remote Device", "Ponovni zagon oddaljene naprave"),
|
||||
("remote_restarting_tip", "Oddaljena naprava se znova zaganja, prosim zaprite to sporočilo in se čez nekaj časa povežite s stalnim geslom."),
|
||||
("Copied", "Kopirano"),
|
||||
("Exit Fullscreen", "Izhod iz celozaslonskega načina"),
|
||||
("Fullscreen", "Celozaslonski način"),
|
||||
("Mobile Actions", "Dejanja za prenosne naprave"),
|
||||
("Select Monitor", "Izberite zaslon"),
|
||||
("Control Actions", "Dejanja za nadzor"),
|
||||
("Display Settings", "Nastavitve zaslona"),
|
||||
("Ratio", "Razmerje"),
|
||||
("Image Quality", "Kakovost slike"),
|
||||
("Scroll Style", "Način drsenja"),
|
||||
("Show Menubar", "Prikaži meni"),
|
||||
("Hide Menubar", "Skrij meni"),
|
||||
("Direct Connection", "Neposredna povezava"),
|
||||
("Relay Connection", "Posredovana povezava"),
|
||||
("Secure Connection", "Zavarovana povezava"),
|
||||
("Insecure Connection", "Nezavarovana povezava"),
|
||||
("Scale original", "Originalna velikost"),
|
||||
("Scale adaptive", "Prilagojena velikost"),
|
||||
("General", "Splošno"),
|
||||
("Security", "Varnost"),
|
||||
("Theme", "Tema"),
|
||||
("Dark Theme", "Temna tema"),
|
||||
("Dark", "Temna"),
|
||||
("Light", "Svetla"),
|
||||
("Follow System", "Sistemska"),
|
||||
("Enable hardware codec", "Omogoči strojno pospeševanje"),
|
||||
("Unlock Security Settings", "Odkleni varnostne nastavitve"),
|
||||
("Enable Audio", "Omogoči zvok"),
|
||||
("Unlock Network Settings", "Odkleni mrežne nastavitve"),
|
||||
("Server", "Strežnik"),
|
||||
("Direct IP Access", "Neposredni dostop preko IPja"),
|
||||
("Proxy", "Posredniški strežnik"),
|
||||
("Apply", "Uveljavi"),
|
||||
("Disconnect all devices?", "Odklopi vse naprave?"),
|
||||
("Clear", "Počisti"),
|
||||
("Audio Input Device", "Vhodna naprava za zvok"),
|
||||
("Deny remote access", "Onemogoči oddaljeni dostop"),
|
||||
("Use IP Whitelisting", "Omogoči seznam dovoljenih IP naslovov"),
|
||||
("Network", "Mreža"),
|
||||
("Enable RDP", "Omogoči RDP"),
|
||||
("Pin menubar", "Pripni menijsko vrstico"),
|
||||
("Unpin menubar", "Odpni menijsko vrstico"),
|
||||
("Recording", "Snemanje"),
|
||||
("Directory", "Imenik"),
|
||||
("Automatically record incoming sessions", "Samodejno snemaj vhodne seje"),
|
||||
("Change", "Spremeni"),
|
||||
("Start session recording", "Začni snemanje seje"),
|
||||
("Stop session recording", "Ustavi snemanje seje"),
|
||||
("Enable Recording Session", "Omogoči snemanje seje"),
|
||||
("Allow recording session", "Dovoli snemanje seje"),
|
||||
("Enable LAN Discovery", "Omogoči odkrivanje lokalnega omrežja"),
|
||||
("Deny LAN Discovery", "Onemogoči odkrivanje lokalnega omrežja"),
|
||||
("Write a message", "Napiši spoorčilo"),
|
||||
("Prompt", "Poziv"),
|
||||
("Please wait for confirmation of UAC...", "Počakajte za potrditev nadzora uporabniškega računa"),
|
||||
("elevated_foreground_window_tip", "Trenutno aktivno okno na oddaljenem računalniku zahteva višje pravice za upravljanje. Oddaljenega uporabnika lahko prosite, da okno minimizira, ali pa kliknite gumb za povzdig pravic v oknu za upravljanje povezave. Če se želite izogniti temu problemu, na oddaljenem računalniku RustDesk namestite."),
|
||||
("Disconnected", "Brez povezave"),
|
||||
("Other", "Drugo"),
|
||||
("Confirm before closing multiple tabs", "Zahtevajte potrditev pred zapiranjem večih zavihkov"),
|
||||
("Keyboard Settings", "Nastavitve tipkovnice"),
|
||||
("Full Access", "Poln dostop"),
|
||||
("Screen Share", "Deljenje zaslona"),
|
||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland zahteva Ubuntu 21.04 ali novejši"),
|
||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Zahtevana je novejša različica Waylanda. Posodobite vašo distribucijo ali pa uporabite X11."),
|
||||
("JumpLink", "Pogled"),
|
||||
("Please Select the screen to be shared(Operate on the peer side).", "Izberite zaslon za delitev (na oddaljeni strani)."),
|
||||
("Show RustDesk", "Prikaži RustDesk"),
|
||||
("This PC", "Ta računalnik"),
|
||||
("or", "ali"),
|
||||
("Continue with", "Nadaljuj z"),
|
||||
("Elevate", "Povzdig pravic"),
|
||||
("Zoom cursor", "Prilagodi velikost miškinega kazalca"),
|
||||
("Accept sessions via password", "Sprejmi seje z geslom"),
|
||||
("Accept sessions via click", "Sprejmi seje s potrditvijo"),
|
||||
("Accept sessions via both", "Sprejmi seje z geslom ali potrditvijo"),
|
||||
("Please wait for the remote side to accept your session request...", "Počakajte, da oddaljeni računalnik sprejme povezavo..."),
|
||||
("One-time Password", "Enkratno geslo"),
|
||||
("Use one-time password", "Uporabi enkratno geslo"),
|
||||
("One-time password length", "Dolžina enkratnega gesla"),
|
||||
("Request access to your device", "Zahtevaj dostop do svoje naprave"),
|
||||
("Hide connection management window", "Skrij okno za upravljanje povezave"),
|
||||
("hide_cm_tip", "Dovoli skrivanje samo pri sprejemanju sej z geslom"),
|
||||
("wayland_experiment_tip", "Podpora za Wayland je v preizkusni fazi. Uporabite X11, če rabite nespremljan dostop."),
|
||||
("Right click to select tabs", "Desno-kliknite za izbiro zavihkov"),
|
||||
("Skipped", "Izpuščeno"),
|
||||
("Add to Address Book", "Dodaj v adresar"),
|
||||
("Group", "Skupina"),
|
||||
("Search", "Iskanje"),
|
||||
("Closed manually by the web console", "Ročno zaprto iz spletne konzole"),
|
||||
("Local keyboard type", "Lokalna vrsta tipkovnice"),
|
||||
("Select local keyboard type", "Izberite lokalno vrsto tipkovnice"),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", "ถูกปิดโดยเว็บคอนโซล"),
|
||||
("Local keyboard type", "ประเภทคีย์บอร์ด"),
|
||||
("Select local keyboard type", "เลือกประเภทคีย์บอร์ด"),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", "被web控制台手動關閉"),
|
||||
("Local keyboard type", "本地鍵盤類型"),
|
||||
("Select local keyboard type", "請選擇本地鍵盤類型"),
|
||||
("software_render_tip", "如果你使用英偉達顯卡, 並且遠程窗口在會話建立後會立刻關閉, 那麼安裝nouveau驅動並且選擇使用軟件渲染可能會有幫助。重啟軟件後生效。"),
|
||||
("Always use software rendering", "使用軟件渲染"),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -410,5 +410,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Closed manually by the web console", ""),
|
||||
("Local keyboard type", ""),
|
||||
("Select local keyboard type", ""),
|
||||
("software_render_tip", ""),
|
||||
("Always use software rendering", ""),
|
||||
("config_input", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@ -717,3 +717,92 @@ pub fn get_double_click_time() -> u32 {
|
||||
}
|
||||
}
|
||||
|
||||
/// forever: may not work
|
||||
pub fn system_message(title: &str, msg: &str, forever: bool) -> ResultType<()> {
|
||||
if std::process::Command::new("notify-send")
|
||||
.arg(title)
|
||||
.arg(msg)
|
||||
.spawn()
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
if std::process::Command::new("zenity")
|
||||
.arg("--info")
|
||||
.arg("--timeout")
|
||||
.arg(if forever { "0" } else { "3" })
|
||||
.arg("--title")
|
||||
.arg(title)
|
||||
.arg("--text")
|
||||
.arg(msg)
|
||||
.spawn()
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
if std::process::Command::new("kdialog")
|
||||
.arg("--title")
|
||||
.arg(title)
|
||||
.arg("--msgbox")
|
||||
.arg(msg)
|
||||
.spawn()
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
if std::process::Command::new("xmessage")
|
||||
.arg("-center")
|
||||
.arg("-timeout")
|
||||
.arg(if forever { "0" } else { "3" })
|
||||
.arg(title)
|
||||
.arg(msg)
|
||||
.spawn()
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
bail!("failed to post system message");
|
||||
}
|
||||
|
||||
extern "C" fn breakdown_signal_handler(sig: i32) {
|
||||
let mut stack = vec![];
|
||||
backtrace::trace(|frame| {
|
||||
backtrace::resolve_frame(frame, |symbol| {
|
||||
if let Some(name) = symbol.name() {
|
||||
stack.push(name.to_string());
|
||||
}
|
||||
});
|
||||
true // keep going to the next frame
|
||||
});
|
||||
let mut info = String::default();
|
||||
if stack.iter().any(|s| {
|
||||
s.contains(&"nouveau_pushbuf_kick")
|
||||
|| s.to_lowercase().contains("nvidia")
|
||||
|| s.contains("gdk_window_end_draw_frame")
|
||||
}) {
|
||||
hbb_common::config::Config::set_option(
|
||||
"allow-always-software-render".to_string(),
|
||||
"Y".to_string(),
|
||||
);
|
||||
info = "Always use software rendering will be set.".to_string();
|
||||
log::info!("{}", info);
|
||||
}
|
||||
log::error!(
|
||||
"Got signal {} and exit. stack:\n{}",
|
||||
sig,
|
||||
stack.join("\n").to_string()
|
||||
);
|
||||
system_message(
|
||||
"RustDesk",
|
||||
&format!("Got signal {} and exit.{}", sig, info),
|
||||
true,
|
||||
)
|
||||
.ok();
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
pub fn register_breakdown_handler() {
|
||||
unsafe {
|
||||
libc::signal(libc::SIGSEGV, breakdown_signal_handler as _);
|
||||
}
|
||||
}
|
||||
|
||||
36
src/platform/macos.mm
Normal file
36
src/platform/macos.mm
Normal file
@ -0,0 +1,36 @@
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <IOKit/hidsystem/IOHIDLib.h>
|
||||
|
||||
// https://github.com/codebytere/node-mac-permissions/blob/main/permissions.mm
|
||||
|
||||
extern "C" bool InputMonitoringAuthStatus(bool prompt) {
|
||||
if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_15) {
|
||||
IOHIDAccessType theType = IOHIDCheckAccess(kIOHIDRequestTypeListenEvent);
|
||||
NSLog(@"IOHIDCheckAccess = %d, kIOHIDAccessTypeGranted = %d", theType, kIOHIDAccessTypeGranted);
|
||||
switch (theType) {
|
||||
case kIOHIDAccessTypeGranted:
|
||||
return true;
|
||||
break;
|
||||
case kIOHIDAccessTypeDenied: {
|
||||
if (prompt) {
|
||||
NSString *urlString = @"x-apple.systempreferences:com.apple.preference.security?Privacy_ListenEvent";
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:urlString]];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kIOHIDAccessTypeUnknown: {
|
||||
if (prompt) {
|
||||
bool result = IOHIDRequestAccess(kIOHIDRequestTypeListenEvent);
|
||||
NSLog(@"IOHIDRequestAccess result = %d", result);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -32,6 +32,7 @@ extern "C" {
|
||||
fn CGEventGetLocation(e: *const c_void) -> CGPoint;
|
||||
static kAXTrustedCheckOptionPrompt: CFStringRef;
|
||||
fn AXIsProcessTrustedWithOptions(options: CFDictionaryRef) -> BOOL;
|
||||
fn InputMonitoringAuthStatus(_: BOOL) -> BOOL;
|
||||
}
|
||||
|
||||
pub fn is_process_trusted(prompt: bool) -> bool {
|
||||
@ -47,6 +48,13 @@ pub fn is_process_trusted(prompt: bool) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_can_input_monitoring(prompt: bool) -> bool {
|
||||
unsafe {
|
||||
let value = if prompt { YES } else { NO };
|
||||
InputMonitoringAuthStatus(value) == YES
|
||||
}
|
||||
}
|
||||
|
||||
// macOS >= 10.15
|
||||
// https://stackoverflow.com/questions/56597221/detecting-screen-recording-settings-on-macos-catalina/
|
||||
// remove just one app from all the permissions: tccutil reset All com.carriez.rustdesk
|
||||
|
||||
@ -556,27 +556,39 @@ pub fn handle_mouse_(evt: &MouseEvent) {
|
||||
en.mouse_move_to(evt.x, evt.y);
|
||||
}
|
||||
1 => match buttons {
|
||||
1 => {
|
||||
0x01 => {
|
||||
allow_err!(en.mouse_down(MouseButton::Left));
|
||||
}
|
||||
2 => {
|
||||
0x02 => {
|
||||
allow_err!(en.mouse_down(MouseButton::Right));
|
||||
}
|
||||
4 => {
|
||||
0x04 => {
|
||||
allow_err!(en.mouse_down(MouseButton::Middle));
|
||||
}
|
||||
0x08 => {
|
||||
allow_err!(en.mouse_down(MouseButton::Back));
|
||||
}
|
||||
0x10 => {
|
||||
allow_err!(en.mouse_down(MouseButton::Forward));
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
2 => match buttons {
|
||||
1 => {
|
||||
0x01 => {
|
||||
en.mouse_up(MouseButton::Left);
|
||||
}
|
||||
2 => {
|
||||
0x02 => {
|
||||
en.mouse_up(MouseButton::Right);
|
||||
}
|
||||
4 => {
|
||||
0x04 => {
|
||||
en.mouse_up(MouseButton::Middle);
|
||||
}
|
||||
0x08 => {
|
||||
en.mouse_up(MouseButton::Back);
|
||||
}
|
||||
0x10 => {
|
||||
en.mouse_up(MouseButton::Forward);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
3 | 4 => {
|
||||
|
||||
@ -582,6 +582,14 @@ pub fn is_installed_daemon(_prompt: bool) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_can_input_monitoring(_prompt: bool) -> bool {
|
||||
#[cfg(target_os = "macos")]
|
||||
return crate::platform::macos::is_can_input_monitoring(_prompt);
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
return true;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_error() -> String {
|
||||
#[cfg(not(any(feature = "cli")))]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user