mirror of
https://github.com/rustdesk/rustdesk.git
synced 2025-05-10 18:06:01 +02:00
feat: take screenshot (#11591)
* feat: take screenshot Signed-off-by: fufesou <linlong1266@gmail.com> * screenshot, vram temp switch capturer Signed-off-by: fufesou <linlong1266@gmail.com> * fix: misspelling Signed-off-by: fufesou <linlong1266@gmail.com> * screenshot, taking Signed-off-by: fufesou <linlong1266@gmail.com> * screenshot, rgba stride Signed-off-by: fufesou <linlong1266@gmail.com> * Bumps 1.4.0 Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
parent
2864e1984a
commit
c626c2414d
82 changed files with 948 additions and 96 deletions
2
.github/workflows/flutter-build.yml
vendored
2
.github/workflows/flutter-build.yml
vendored
|
@ -38,7 +38,7 @@ env:
|
|||
# https://github.com/rustdesk/rustdesk/actions/runs/14414119794/job/40427970174
|
||||
# 2. Update the `VCPKG_COMMIT_ID` in `ci.yml` and `playground.yml`.
|
||||
VCPKG_COMMIT_ID: "6f29f12e82a8293156836ad81cc9bf5af41fe836"
|
||||
VERSION: "1.3.9"
|
||||
VERSION: "1.4.0"
|
||||
NDK_VERSION: "r27c"
|
||||
#signing keys env variable checks
|
||||
ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}"
|
||||
|
|
2
.github/workflows/playground.yml
vendored
2
.github/workflows/playground.yml
vendored
|
@ -17,7 +17,7 @@ env:
|
|||
TAG_NAME: "nightly"
|
||||
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
|
||||
VCPKG_COMMIT_ID: "6f29f12e82a8293156836ad81cc9bf5af41fe836"
|
||||
VERSION: "1.3.9"
|
||||
VERSION: "1.4.0"
|
||||
NDK_VERSION: "r26d"
|
||||
#signing keys env variable checks
|
||||
ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}"
|
||||
|
|
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -5857,7 +5857,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustdesk"
|
||||
version = "1.3.9"
|
||||
version = "1.4.0"
|
||||
dependencies = [
|
||||
"android-wakelock",
|
||||
"android_logger",
|
||||
|
@ -5960,7 +5960,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustdesk-portable-packer"
|
||||
version = "1.3.9"
|
||||
version = "1.4.0"
|
||||
dependencies = [
|
||||
"brotli",
|
||||
"dirs 5.0.1",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "rustdesk"
|
||||
version = "1.3.9"
|
||||
version = "1.4.0"
|
||||
authors = ["rustdesk <info@rustdesk.com>"]
|
||||
edition = "2021"
|
||||
build= "build.rs"
|
||||
|
|
|
@ -18,7 +18,7 @@ AppDir:
|
|||
id: rustdesk
|
||||
name: rustdesk
|
||||
icon: rustdesk
|
||||
version: 1.3.9
|
||||
version: 1.4.0
|
||||
exec: usr/share/rustdesk/rustdesk
|
||||
exec_args: $@
|
||||
apt:
|
||||
|
|
|
@ -18,7 +18,7 @@ AppDir:
|
|||
id: rustdesk
|
||||
name: rustdesk
|
||||
icon: rustdesk
|
||||
version: 1.3.9
|
||||
version: 1.4.0
|
||||
exec: usr/share/rustdesk/rustdesk
|
||||
exec_args: $@
|
||||
apt:
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -15,7 +16,7 @@ bool isEditOsPassword = false;
|
|||
|
||||
class TTextMenu {
|
||||
final Widget child;
|
||||
final VoidCallback onPressed;
|
||||
final VoidCallback? onPressed;
|
||||
Widget? trailingIcon;
|
||||
bool divider;
|
||||
TTextMenu(
|
||||
|
@ -294,6 +295,41 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
|
|||
),
|
||||
onPressed: () => ffi.recordingModel.toggle()));
|
||||
}
|
||||
|
||||
// to-do:
|
||||
// 1. Web desktop
|
||||
// 2. Mobile, copy the image to the clipboard
|
||||
if (isDesktop) {
|
||||
final isScreenshotSupported = bind.sessionGetCommonSync(
|
||||
sessionId: sessionId, key: 'is_screenshot_supported', param: '');
|
||||
if ('true' == isScreenshotSupported) {
|
||||
v.add(TTextMenu(
|
||||
child: Text(ffi.ffiModel.timerScreenshot != null
|
||||
? '${translate('Taking screenshot')} ...'
|
||||
: translate('Take screenshot')),
|
||||
onPressed: ffi.ffiModel.timerScreenshot != null
|
||||
? null
|
||||
: () {
|
||||
if (pi.currentDisplay == kAllDisplayValue) {
|
||||
msgBox(
|
||||
sessionId,
|
||||
'custom-nook-nocancel-hasclose-info',
|
||||
'Take screenshot',
|
||||
'screenshot-merged-screen-not-supported-tip',
|
||||
'',
|
||||
ffi.dialogManager);
|
||||
} else {
|
||||
bind.sessionTakeScreenshot(
|
||||
sessionId: sessionId, display: pi.currentDisplay);
|
||||
ffi.ffiModel.timerScreenshot =
|
||||
Timer(Duration(seconds: 30), () {
|
||||
ffi.ffiModel.timerScreenshot = null;
|
||||
});
|
||||
}
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
// fingerprint
|
||||
if (!(isDesktop || isWebDesktop)) {
|
||||
v.add(TTextMenu(
|
||||
|
|
|
@ -220,7 +220,8 @@ const double kDefaultQuality = 50;
|
|||
const double kMaxQuality = 100;
|
||||
const double kMaxMoreQuality = 2000;
|
||||
|
||||
const String kKeyPrinterIncommingJobAction = 'printer-incomming-job-action';
|
||||
// incomming (should be incoming) is kept, because change it will break the previous setting.
|
||||
const String kKeyPrinterIncomingJobAction = 'printer-incomming-job-action';
|
||||
const String kValuePrinterIncomingJobDismiss = 'dismiss';
|
||||
const String kValuePrinterIncomingJobDefault = '';
|
||||
const String kValuePrinterIncomingJobSelected = 'selected';
|
||||
|
|
|
@ -1908,7 +1908,7 @@ class __PrinterState extends State<_Printer> {
|
|||
final scrollController = ScrollController();
|
||||
return ListView(controller: scrollController, children: [
|
||||
outgoing(context),
|
||||
incomming(context),
|
||||
incoming(context),
|
||||
]).marginOnly(bottom: _kListViewBottomMargin);
|
||||
}
|
||||
|
||||
|
@ -1995,15 +1995,15 @@ class __PrinterState extends State<_Printer> {
|
|||
return _Card(title: 'Outgoing Print Jobs', children: children);
|
||||
}
|
||||
|
||||
Widget incomming(BuildContext context) {
|
||||
Widget incoming(BuildContext context) {
|
||||
onRadioChanged(String value) async {
|
||||
await bind.mainSetLocalOption(
|
||||
key: kKeyPrinterIncommingJobAction, value: value);
|
||||
key: kKeyPrinterIncomingJobAction, value: value);
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
PrinterOptions printerOptions = PrinterOptions.load();
|
||||
return _Card(title: 'Incomming Print Jobs', children: [
|
||||
return _Card(title: 'Incoming Print Jobs', children: [
|
||||
_Radio(context,
|
||||
value: kValuePrinterIncomingJobDismiss,
|
||||
groupValue: printerOptions.action,
|
||||
|
|
|
@ -695,9 +695,9 @@ class _RemotePageState extends State<RemotePage> with WidgetsBindingObserver {
|
|||
);
|
||||
if (index != null) {
|
||||
if (index < mobileActionMenus.length) {
|
||||
mobileActionMenus[index].onPressed.call();
|
||||
mobileActionMenus[index].onPressed?.call();
|
||||
} else if (index < mobileActionMenus.length + more.length) {
|
||||
menus[index - mobileActionMenus.length].onPressed.call();
|
||||
menus[index - mobileActionMenus.length].onPressed?.call();
|
||||
}
|
||||
}
|
||||
}();
|
||||
|
@ -770,7 +770,7 @@ class _RemotePageState extends State<RemotePage> with WidgetsBindingObserver {
|
|||
elevation: 8,
|
||||
);
|
||||
if (index != null && index < menus.length) {
|
||||
menus[index].onPressed.call();
|
||||
menus[index].onPressed?.call();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1267,7 +1267,7 @@ void showOptions(
|
|||
title: resolution.child,
|
||||
onTap: () {
|
||||
close();
|
||||
resolution.onPressed();
|
||||
resolution.onPressed?.call();
|
||||
},
|
||||
));
|
||||
}
|
||||
|
@ -1279,7 +1279,7 @@ void showOptions(
|
|||
title: virtualDisplayMenu.child,
|
||||
onTap: () {
|
||||
close();
|
||||
virtualDisplayMenu.onPressed();
|
||||
virtualDisplayMenu.onPressed?.call();
|
||||
},
|
||||
));
|
||||
}
|
||||
|
|
|
@ -243,7 +243,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
|||
Widget build(BuildContext context) {
|
||||
Provider.of<FfiModel>(context);
|
||||
final outgoingOnly = bind.isOutgoingOnly();
|
||||
final incommingOnly = bind.isIncomingOnly();
|
||||
final incomingOnly = bind.isIncomingOnly();
|
||||
final customClientSection = CustomSettingsSection(
|
||||
child: Column(
|
||||
children: [
|
||||
|
@ -728,7 +728,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
|||
});
|
||||
},
|
||||
),
|
||||
if (!incommingOnly)
|
||||
if (!incomingOnly)
|
||||
SettingsTile.switchTile(
|
||||
title:
|
||||
Text(translate('Automatically record outgoing sessions')),
|
||||
|
|
|
@ -478,9 +478,9 @@ class _ViewCameraPageState extends State<ViewCameraPage>
|
|||
);
|
||||
if (index != null) {
|
||||
if (index < mobileActionMenus.length) {
|
||||
mobileActionMenus[index].onPressed.call();
|
||||
mobileActionMenus[index].onPressed?.call();
|
||||
} else if (index < mobileActionMenus.length + more.length) {
|
||||
menus[index - mobileActionMenus.length].onPressed.call();
|
||||
menus[index - mobileActionMenus.length].onPressed?.call();
|
||||
}
|
||||
}
|
||||
}();
|
||||
|
@ -553,7 +553,7 @@ class _ViewCameraPageState extends State<ViewCameraPage>
|
|||
elevation: 8,
|
||||
);
|
||||
if (index != null && index < menus.length) {
|
||||
menus[index].onPressed.call();
|
||||
menus[index].onPressed?.call();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import 'package:flutter_svg/flutter_svg.dart';
|
|||
import 'package:get/get.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
|
||||
import '../common.dart';
|
||||
import '../utils/image.dart' as img;
|
||||
|
@ -119,6 +120,8 @@ class FfiModel with ChangeNotifier {
|
|||
RxBool waitForFirstImage = true.obs;
|
||||
bool isRefreshing = false;
|
||||
|
||||
Timer? timerScreenshot;
|
||||
|
||||
Rect? get rect => _rect;
|
||||
bool get isOriginalResolutionSet =>
|
||||
_pi.tryGetDisplayIfNotAllDisplay()?.isOriginalResolutionSet ?? false;
|
||||
|
@ -216,6 +219,7 @@ class FfiModel with ChangeNotifier {
|
|||
_timer = null;
|
||||
clearPermissions();
|
||||
waitForImageTimer?.cancel();
|
||||
timerScreenshot?.cancel();
|
||||
}
|
||||
|
||||
setConnectionType(String peerId, bool secure, bool direct) {
|
||||
|
@ -414,12 +418,82 @@ class FfiModel with ChangeNotifier {
|
|||
}
|
||||
} else if (name == "printer_request") {
|
||||
_handlePrinterRequest(evt, sessionId, peerId);
|
||||
} else if (name == 'screenshot') {
|
||||
_handleScreenshot(evt, sessionId, peerId);
|
||||
} else {
|
||||
debugPrint('Event is not handled in the fixed branch: $name');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_handleScreenshot(
|
||||
Map<String, dynamic> evt, SessionID sessionId, String peerId) {
|
||||
timerScreenshot?.cancel();
|
||||
timerScreenshot = null;
|
||||
final msg = evt['msg'] ?? '';
|
||||
final msgBoxType = 'custom-nook-nocancel-hasclose';
|
||||
final msgBoxTitle = 'Take screenshot';
|
||||
final dialogManager = parent.target!.dialogManager;
|
||||
if (msg.isNotEmpty) {
|
||||
msgBox(sessionId, msgBoxType, msgBoxTitle, msg, '', dialogManager);
|
||||
} else {
|
||||
final msgBoxText = 'screenshot-action-tip';
|
||||
|
||||
close() {
|
||||
dialogManager.dismissAll();
|
||||
}
|
||||
|
||||
saveAs() {
|
||||
close();
|
||||
Future.delayed(Duration.zero, () async {
|
||||
final ts = DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
||||
String? outputFile = await FilePicker.platform.saveFile(
|
||||
dialogTitle: '${translate('Save as')}...',
|
||||
fileName: 'screenshot_$ts.png',
|
||||
allowedExtensions: ['png'],
|
||||
type: FileType.custom,
|
||||
);
|
||||
if (outputFile == null) {
|
||||
bind.sessionHandleScreenshot(sessionId: sessionId, action: '2');
|
||||
} else {
|
||||
final res = await bind.sessionHandleScreenshot(
|
||||
sessionId: sessionId, action: '0:$outputFile');
|
||||
if (res.isNotEmpty) {
|
||||
msgBox(sessionId, 'custom-nook-nocancel-hasclose-error',
|
||||
'Take screenshot', res, '', dialogManager);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
copyToClipboard() {
|
||||
bind.sessionHandleScreenshot(sessionId: sessionId, action: '1');
|
||||
close();
|
||||
}
|
||||
|
||||
cancel() {
|
||||
bind.sessionHandleScreenshot(sessionId: sessionId, action: '2');
|
||||
close();
|
||||
}
|
||||
|
||||
final List<Widget> buttons = [
|
||||
dialogButton('${translate('Save as')}...', onPressed: saveAs),
|
||||
dialogButton('Copy to clipboard', onPressed: copyToClipboard),
|
||||
dialogButton('Cancel', onPressed: cancel),
|
||||
];
|
||||
dialogManager.dismissAll();
|
||||
dialogManager.show(
|
||||
(setState, close, context) => CustomAlertDialog(
|
||||
title: null,
|
||||
content: SelectionArea(
|
||||
child: msgboxContent(msgBoxType, msgBoxTitle, msgBoxText)),
|
||||
actions: buttons,
|
||||
),
|
||||
tag: '$msgBoxType-$msgBoxTitle-$msgBoxTitle',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_handlePrinterRequest(
|
||||
Map<String, dynamic> evt, SessionID sessionId, String peerId) {
|
||||
final id = evt['id'];
|
||||
|
@ -451,7 +525,7 @@ class FfiModel with ChangeNotifier {
|
|||
if (saveSettings.value || dontShowAgain.value) {
|
||||
bind.mainSetLocalOption(key: kKeyPrinterSelected, value: printerName);
|
||||
bind.mainSetLocalOption(
|
||||
key: kKeyPrinterIncommingJobAction,
|
||||
key: kKeyPrinterIncomingJobAction,
|
||||
value: defaultOrSelectedGroupValue.value);
|
||||
}
|
||||
if (dontShowAgain.value) {
|
||||
|
@ -463,7 +537,7 @@ class FfiModel with ChangeNotifier {
|
|||
onCancel() {
|
||||
if (dontShowAgain.value) {
|
||||
bind.mainSetLocalOption(
|
||||
key: kKeyPrinterIncommingJobAction,
|
||||
key: kKeyPrinterIncomingJobAction,
|
||||
value: kValuePrinterIncomingJobDismiss);
|
||||
}
|
||||
close();
|
||||
|
|
|
@ -13,7 +13,7 @@ class PrinterOptions {
|
|||
required this.printerName});
|
||||
|
||||
static PrinterOptions load() {
|
||||
var action = bind.mainGetLocalOption(key: kKeyPrinterIncommingJobAction);
|
||||
var action = bind.mainGetLocalOption(key: kKeyPrinterIncomingJobAction);
|
||||
if (![
|
||||
kValuePrinterIncomingJobDismiss,
|
||||
kValuePrinterIncomingJobDefault,
|
||||
|
@ -28,7 +28,7 @@ class PrinterOptions {
|
|||
if (action == kValuePrinterIncomingJobSelected) {
|
||||
action = kValuePrinterIncomingJobDefault;
|
||||
bind.mainSetLocalOption(
|
||||
key: kKeyPrinterIncommingJobAction,
|
||||
key: kKeyPrinterIncomingJobAction,
|
||||
value: kValuePrinterIncomingJobDefault);
|
||||
if (printerNames.isEmpty) {
|
||||
selectedPrinterName = '';
|
||||
|
|
|
@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
|||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
# 1.1.9-1 works for android, but for ios it becomes 1.1.91, need to set it to 1.1.9-a.1 for iOS, will get 1.1.9.1, but iOS store not allow 4 numbers
|
||||
version: 1.3.9+57
|
||||
version: 1.4.0+58
|
||||
|
||||
environment:
|
||||
sdk: '^3.1.0'
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 3afaf6494475ef58dcaaae6b4e6d2303cc3d632b
|
||||
Subproject commit 42aad01a517d4de7420ddcb7e99c29bd9f6d2b5a
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "rustdesk-portable-packer"
|
||||
version = "1.3.9"
|
||||
version = "1.4.0"
|
||||
edition = "2021"
|
||||
description = "RustDesk Remote Desktop"
|
||||
|
||||
|
|
|
@ -197,3 +197,40 @@ pub fn convert_to_yuv(
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "ios"))]
|
||||
pub fn convert(captured: &PixelBuffer, pixfmt: crate::Pixfmt, dst: &mut Vec<u8>) -> ResultType<()> {
|
||||
if captured.pixfmt() == pixfmt {
|
||||
dst.extend_from_slice(captured.data());
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let src = captured.data();
|
||||
let src_stride = captured.stride();
|
||||
let src_pixfmt = captured.pixfmt();
|
||||
let src_width = captured.width();
|
||||
let src_height = captured.height();
|
||||
|
||||
let unsupported = format!(
|
||||
"unsupported pixfmt conversion: {src_pixfmt:?} -> {:?}",
|
||||
pixfmt
|
||||
);
|
||||
|
||||
match (src_pixfmt, pixfmt) {
|
||||
(crate::Pixfmt::BGRA, crate::Pixfmt::RGBA) | (crate::Pixfmt::RGBA, crate::Pixfmt::BGRA) => {
|
||||
dst.resize(src.len(), 0);
|
||||
call_yuv!(ABGRToARGB(
|
||||
src.as_ptr(),
|
||||
src_stride[0] as _,
|
||||
dst.as_mut_ptr(),
|
||||
src_stride[0] as _,
|
||||
src_width as _,
|
||||
src_height as _,
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
bail!(unsupported);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@ pub enum ImageFormat {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone)]
|
||||
pub struct ImageRgb {
|
||||
pub raw: Vec<u8>,
|
||||
pub w: usize,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
pkgname=rustdesk
|
||||
pkgver=1.3.9
|
||||
pkgver=1.4.0
|
||||
pkgrel=0
|
||||
epoch=
|
||||
pkgdesc=""
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Name: rustdesk
|
||||
Version: 1.3.9
|
||||
Version: 1.4.0
|
||||
Release: 0
|
||||
Summary: RPM package
|
||||
License: GPL-3.0
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Name: rustdesk
|
||||
Version: 1.3.9
|
||||
Version: 1.4.0
|
||||
Release: 0
|
||||
Summary: RPM package
|
||||
License: GPL-3.0
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Name: rustdesk
|
||||
Version: 1.3.9
|
||||
Version: 1.4.0
|
||||
Release: 0
|
||||
Summary: RPM package
|
||||
License: GPL-3.0
|
||||
|
|
|
@ -85,6 +85,7 @@ pub use super::lang::*;
|
|||
pub mod file_trait;
|
||||
pub mod helper;
|
||||
pub mod io_loop;
|
||||
pub mod screenshot;
|
||||
|
||||
pub const MILLI1: Duration = Duration::from_millis(1);
|
||||
pub const SEC30: Duration = Duration::from_secs(30);
|
||||
|
@ -3336,6 +3337,7 @@ pub enum Data {
|
|||
CloseVoiceCall,
|
||||
ResetDecoder(Option<usize>),
|
||||
RenameFile((i32, String, String, bool)),
|
||||
TakeScreenshot((i32, String)),
|
||||
}
|
||||
|
||||
/// Keycode for key events.
|
||||
|
|
|
@ -962,6 +962,15 @@ impl<T: InvokeUiSession> Remote<T> {
|
|||
}
|
||||
}
|
||||
},
|
||||
Data::TakeScreenshot((display, sid)) => {
|
||||
let mut msg = Message::new();
|
||||
msg.set_screenshot_request(ScreenshotRequest {
|
||||
display,
|
||||
sid,
|
||||
..Default::default()
|
||||
});
|
||||
allow_err!(peer.send(&msg).await);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
true
|
||||
|
@ -1909,6 +1918,11 @@ impl<T: InvokeUiSession> Remote<T> {
|
|||
self.handler.set_displays(&pi.displays);
|
||||
self.handler.set_platform_additions(&pi.platform_additions);
|
||||
}
|
||||
Some(message::Union::ScreenshotResponse(response)) => {
|
||||
crate::client::screenshot::set_screenshot(response.data);
|
||||
self.handler
|
||||
.handle_screenshot_resp(response.sid, response.msg);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
99
src/client/screenshot.rs
Normal file
99
src/client/screenshot.rs
Normal file
|
@ -0,0 +1,99 @@
|
|||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
use crate::clipboard::{update_clipboard, ClipboardSide};
|
||||
use hbb_common::{message_proto::*, ResultType};
|
||||
use std::sync::Mutex;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref SCREENSHOT: Mutex<Screenshot> = Default::default();
|
||||
}
|
||||
|
||||
pub enum ScreenshotAction {
|
||||
SaveAs(String),
|
||||
CopyToClipboard,
|
||||
Discard,
|
||||
}
|
||||
|
||||
impl Default for ScreenshotAction {
|
||||
fn default() -> Self {
|
||||
Self::Discard
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for ScreenshotAction {
|
||||
fn from(value: &str) -> Self {
|
||||
match value.chars().next() {
|
||||
Some('0') => {
|
||||
if let Some((pos, _)) = value.char_indices().nth(2) {
|
||||
let substring = &value[pos..];
|
||||
Self::SaveAs(substring.to_string())
|
||||
} else {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
Some('1') => Self::CopyToClipboard,
|
||||
Some('2') => Self::default(),
|
||||
_ => Self::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<String> for ScreenshotAction {
|
||||
fn into(self) -> String {
|
||||
match self {
|
||||
Self::SaveAs(p) => format!("0:{p}"),
|
||||
Self::CopyToClipboard => "1".to_owned(),
|
||||
Self::Discard => "2".to_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Screenshot {
|
||||
data: Option<bytes::Bytes>,
|
||||
}
|
||||
|
||||
impl Screenshot {
|
||||
fn set_screenshot(&mut self, data: bytes::Bytes) {
|
||||
self.data.replace(data);
|
||||
}
|
||||
|
||||
fn handle_screenshot(&mut self, action: String) -> String {
|
||||
let Some(data) = self.data.take() else {
|
||||
return "No cached screenshot".to_owned();
|
||||
};
|
||||
match Self::handle_screenshot_(data, action) {
|
||||
Ok(()) => "".to_owned(),
|
||||
Err(e) => e.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_screenshot_(data: bytes::Bytes, action: String) -> ResultType<()> {
|
||||
match ScreenshotAction::from(&action as &str) {
|
||||
ScreenshotAction::SaveAs(p) => {
|
||||
std::fs::write(p, data)?;
|
||||
}
|
||||
ScreenshotAction::CopyToClipboard => {
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
{
|
||||
let clips = vec![Clipboard {
|
||||
compress: false,
|
||||
content: data,
|
||||
format: ClipboardFormat::ImagePng.into(),
|
||||
..Default::default()
|
||||
}];
|
||||
update_clipboard(clips, ClipboardSide::Client);
|
||||
}
|
||||
}
|
||||
ScreenshotAction::Discard => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_screenshot(data: bytes::Bytes) {
|
||||
SCREENSHOT.lock().unwrap().set_screenshot(data);
|
||||
}
|
||||
|
||||
pub fn handle_screenshot(action: String) -> String {
|
||||
SCREENSHOT.lock().unwrap().handle_screenshot(action)
|
||||
}
|
|
@ -147,6 +147,16 @@ pub fn is_support_file_paste_if_macos(ver: &str) -> bool {
|
|||
hbb_common::get_version_number(ver) >= hbb_common::get_version_number("1.3.9")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_support_screenshot(ver: &str) -> bool {
|
||||
is_support_multi_ui_session_num(hbb_common::get_version_number(ver))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_support_screenshot_num(ver: i64) -> bool {
|
||||
ver >= hbb_common::get_version_number("1.4.0")
|
||||
}
|
||||
|
||||
// is server process, with "--server" args
|
||||
#[inline]
|
||||
pub fn is_server() -> bool {
|
||||
|
|
|
@ -543,6 +543,25 @@ impl FlutterHandler {
|
|||
pub fn push_event<V>(&self, name: &str, event: &[(&str, V)], excludes: &[&SessionID])
|
||||
where
|
||||
V: Sized + Serialize + Clone,
|
||||
{
|
||||
self.push_event_(name, event, &[], excludes);
|
||||
}
|
||||
|
||||
pub fn push_event_to<V>(&self, name: &str, event: &[(&str, V)], include: &[&SessionID])
|
||||
where
|
||||
V: Sized + Serialize + Clone,
|
||||
{
|
||||
self.push_event_(name, event, include, &[]);
|
||||
}
|
||||
|
||||
pub fn push_event_<V>(
|
||||
&self,
|
||||
name: &str,
|
||||
event: &[(&str, V)],
|
||||
includes: &[&SessionID],
|
||||
excludes: &[&SessionID],
|
||||
) where
|
||||
V: Sized + Serialize + Clone,
|
||||
{
|
||||
let mut h: HashMap<&str, serde_json::Value> =
|
||||
event.iter().map(|(k, v)| (*k, json!(*v))).collect();
|
||||
|
@ -550,11 +569,20 @@ impl FlutterHandler {
|
|||
h.insert("name", json!(name));
|
||||
let out = serde_json::ser::to_string(&h).unwrap_or("".to_owned());
|
||||
for (sid, session) in self.session_handlers.read().unwrap().iter() {
|
||||
if excludes.contains(&sid) {
|
||||
continue;
|
||||
let mut push = false;
|
||||
if includes.is_empty() {
|
||||
if !excludes.contains(&sid) {
|
||||
push = true;
|
||||
}
|
||||
} else {
|
||||
if includes.contains(&sid) {
|
||||
push = true;
|
||||
}
|
||||
}
|
||||
if let Some(stream) = &session.event_stream {
|
||||
stream.add(EventToUI::Event(out.clone()));
|
||||
if push {
|
||||
if let Some(stream) = &session.event_stream {
|
||||
stream.add(EventToUI::Event(out.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1067,6 +1095,16 @@ impl InvokeUiSession for FlutterHandler {
|
|||
&[],
|
||||
);
|
||||
}
|
||||
|
||||
fn handle_screenshot_resp(&self, sid: String, msg: String) {
|
||||
match SessionID::from_str(&sid) {
|
||||
Ok(sid) => self.push_event_to("screenshot", &[("msg", json!(msg))], &[&sid]),
|
||||
Err(e) => {
|
||||
// Unreachable!
|
||||
log::error!("Failed to parse sid \"{}\", {}", sid, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FlutterHandler {
|
||||
|
|
|
@ -250,6 +250,16 @@ pub fn session_refresh(session_id: SessionID, display: usize) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn session_take_screenshot(session_id: SessionID, display: usize) {
|
||||
if let Some(s) = sessions::get_session_by_session_id(&session_id) {
|
||||
s.take_screenshot(display as _, session_id.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn session_handle_screenshot(session_id: SessionID, action: String) -> String {
|
||||
crate::client::screenshot::handle_screenshot(action)
|
||||
}
|
||||
|
||||
pub fn session_is_multi_ui_session(session_id: SessionID) -> SyncReturn<bool> {
|
||||
if let Some(session) = sessions::get_session_by_session_id(&session_id) {
|
||||
SyncReturn(session.is_multi_ui_session())
|
||||
|
@ -2461,6 +2471,27 @@ pub fn main_set_common(_key: String, _value: String) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn session_get_common_sync(
|
||||
session_id: SessionID,
|
||||
key: String,
|
||||
param: String,
|
||||
) -> SyncReturn<Option<String>> {
|
||||
SyncReturn(session_get_common(session_id, key, param))
|
||||
}
|
||||
|
||||
pub fn session_get_common(session_id: SessionID, key: String, param: String) -> Option<String> {
|
||||
if let Some(s) = sessions::get_session_by_session_id(&session_id) {
|
||||
let v = if key == "is_screenshot_supported" {
|
||||
s.is_screenshot_supported().to_string()
|
||||
} else {
|
||||
"".to_owned()
|
||||
};
|
||||
Some(v)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
pub mod server_side {
|
||||
use hbb_common::{config, log};
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", "الطابعة {} جاهزة"),
|
||||
("Install {} Printer", "تثبيت طابعة {}"),
|
||||
("Outgoing Print Jobs", "وظائف الطباعة الصادرة"),
|
||||
("Incomming Print Jobs", "وظائف الطباعة الواردة"),
|
||||
("Incoming Print Jobs", "وظائف الطباعة الواردة"),
|
||||
("Incoming Print Job", "وظيفة طباعة واردة"),
|
||||
("use-the-default-printer-tip", "استخدم الطابعة الافتراضية"),
|
||||
("use-the-selected-printer-tip", "استخدم الطابعة المحددة"),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", "الطباعة عن بُعد غير مسموح بها على هذا الجهاز"),
|
||||
("save-settings-tip", "حفظ الإعدادات"),
|
||||
("dont-show-again-tip", "لا تظهر هذا مرة أخرى"),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -653,7 +653,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Upload folder", "上传文件夹"),
|
||||
("Upload files", "上传文件"),
|
||||
("Clipboard is synchronized", "剪贴板已同步"),
|
||||
("Update client clipboard", "更新客户端的粘贴板"),
|
||||
("Update client clipboard", "更新客户端的剪贴板"),
|
||||
("Untagged", "无标签"),
|
||||
("new-version-of-{}-tip", "{} 版本更新"),
|
||||
("Accessible devices", "可访问的设备"),
|
||||
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", "{} 打印机已安装,您可以使用打印功能了。"),
|
||||
("Install {} Printer", "安装 {} 打印机"),
|
||||
("Outgoing Print Jobs", "传出的打印任务"),
|
||||
("Incomming Print Jobs", "传入的打印任务"),
|
||||
("Incoming Print Jobs", "传入的打印任务"),
|
||||
("Incoming Print Job", "传入的打印任务"),
|
||||
("use-the-default-printer-tip", "使用默认的打印机执行"),
|
||||
("use-the-selected-printer-tip", "使用选择的打印机执行"),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", "被控端的权限设置拒绝了远程打印。"),
|
||||
("save-settings-tip", "保存设置"),
|
||||
("dont-show-again-tip", "不再显示此信息"),
|
||||
("Take screenshot", "截屏"),
|
||||
("Taking screenshot", "正在截屏"),
|
||||
("screenshot-merged-screen-not-supported-tip", "当前不支持多个屏幕的合并截屏,请切换到单个屏幕重试。"),
|
||||
("screenshot-action-tip", "请选择如何继续截屏。"),
|
||||
("Save as", "另存为"),
|
||||
("Copy to clipboard", "复制到剪贴板"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", "Der Drucker {} ist installiert und einsatzbereit."),
|
||||
("Install {} Printer", "Drucker {} installieren"),
|
||||
("Outgoing Print Jobs", "Ausgehende Druckaufträge"),
|
||||
("Incomming Print Jobs", "Eingehende Druckaufträge"),
|
||||
("Incoming Print Jobs", "Eingehende Druckaufträge"),
|
||||
("Incoming Print Job", "Eingehender Druckauftrag"),
|
||||
("use-the-default-printer-tip", "Standarddrucker verwenden"),
|
||||
("use-the-selected-printer-tip", "Ausgewählten Drucker verwenden"),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", "Die Berechtigungseinstellungen der kontrollierten Seite verweigern den entfernten Druck."),
|
||||
("save-settings-tip", "Einstellungen speichern"),
|
||||
("dont-show-again-tip", "Nicht mehr anzeigen"),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -253,5 +253,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", "The permission settings of the controlled side deny Remote Printing."),
|
||||
("save-settings-tip", "Save settings"),
|
||||
("dont-show-again-tip", "Don't show this again"),
|
||||
("screenshot-merged-screen-not-supported-tip", "Merging screenshots of multiple displays is currently not supported. Please switch to a single display and try again."),
|
||||
("screenshot-action-tip", "Please select how to continue with the screenshot."),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", "La impresora {} está instalada y lista para usar."),
|
||||
("Install {} Printer", "Instalar la impresora {}"),
|
||||
("Outgoing Print Jobs", "Tareas salientes de impresión"),
|
||||
("Incomming Print Jobs", "Tareas entrantes de impresión"),
|
||||
("Incoming Print Jobs", "Tareas entrantes de impresión"),
|
||||
("Incoming Print Job", "Trabajo entrante de impresión"),
|
||||
("use-the-default-printer-tip", "Usar la impresora predeterminada"),
|
||||
("use-the-selected-printer-tip", "Usar la impresora seleccionada"),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", "Los ajustes de permisos del lado controlado no permiten la impresión remota."),
|
||||
("save-settings-tip", "Guardar ajustes"),
|
||||
("dont-show-again-tip", "No volver a mostrar"),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", "چاپگر {} آماده است"),
|
||||
("Install {} Printer", "نصب چاپگر {}"),
|
||||
("Outgoing Print Jobs", "وظایف چاپ خروجی"),
|
||||
("Incomming Print Jobs", "وظایف چاپ ورودی"),
|
||||
("Incoming Print Jobs", "وظایف چاپ ورودی"),
|
||||
("Incoming Print Job", "وظیفه چاپ ورودی"),
|
||||
("use-the-default-printer-tip", "از چاپگر پیشفرض استفاده کنید"),
|
||||
("use-the-selected-printer-tip", "از چاپگر انتخابشده استفاده کنید"),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", "شما مجوز لازم برای چاپ از راه دور را ندارید"),
|
||||
("save-settings-tip", "تنظیمات را ذخیره کنید"),
|
||||
("dont-show-again-tip", "دیگر نمایش داده نشود"),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", "L’imprimante {} est installée et opérationnelle."),
|
||||
("Install {} Printer", "Installer l’imprimante {}"),
|
||||
("Outgoing Print Jobs", "Impressions sortantes"),
|
||||
("Incomming Print Jobs", "Impressions entrantes"),
|
||||
("Incoming Print Jobs", "Impressions entrantes"),
|
||||
("Incoming Print Job", "Impression entrante"),
|
||||
("use-the-default-printer-tip", "Utiliser l’imprimante par défaut"),
|
||||
("use-the-selected-printer-tip", "Utiliser l’imprimante sélectionnée"),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", "Les paramètres de l’appareil contrôlé n’autorisent pas l’impression à distance."),
|
||||
("save-settings-tip", "Enregistrer les paramètres"),
|
||||
("dont-show-again-tip", "Ne plus afficher"),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -239,7 +239,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("Empty", "ცარიელი"),
|
||||
("Invalid folder name", "არასწორი საქაღალდის სახელი"),
|
||||
("Socks5 Proxy", "SOCKS5-პროქსი"),
|
||||
("Proxy", "პროქსი"),
|
||||
("Socks5/Http(s) Proxy", ""),
|
||||
("Discovered", "ნაპოვნია"),
|
||||
("install_daemon_tip", "ჩატვირთვისას გასაშვებად საჭიროა სისტემური სერვისის დაყენება"),
|
||||
("Remote ID", "დაშორებული ID"),
|
||||
|
@ -567,7 +567,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("id_input_tip", "შეგიძლიათ შეიყვანოთ იდენტიფიკატორი, პირდაპირი IP მისამართი ან დომენი პორტით (<დომენი>:<პორტი>).\nთუ გჭირდებათ წვდომა მოწყობილობაზე სხვა სერვერზე, დაამატეთ სერვერის მისამართი (<id>@<სერვერის_მისამართი>?key=<გასაღების_მნიშვნელობა>), მაგალითად:\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nთუ გჭირდებათ წვდომა მოწყობილობაზე საჯარო სერვერზე, შეიყვანეთ \"<id>@public\", გასაღები საჯარო სერვერისთვის არ არის საჭირო."),
|
||||
("privacy_mode_impl_mag_tip", "რეჟიმი 1"),
|
||||
("privacy_mode_impl_virtual_display_tip", "რეჟიმი 2"),
|
||||
("privacy_mode_impl_virtual_display_tip", "რეჟიმი 2"),
|
||||
("Enter privacy mode", "კონფიდენციალურობის რეჟიმის ჩართვა"),
|
||||
("Exit privacy mode", "კონფიდენციალურობის რეჟიმის გამორთვა"),
|
||||
("idd_not_support_under_win10_2004_tip", "არაპირდაპირი ჩვენების დრაივერი არ არის მხარდაჭერილი. საჭიროა Windows 10 ვერსია 2004 ან უფრო ახალი."),
|
||||
|
@ -659,7 +658,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("new-version-of-{}-tip", "ხელმისაწვდომია ახალი ვერსია {}"),
|
||||
("Accessible devices", "ხელმისაწვდომი მოწყობილობები"),
|
||||
("View camera", "კამერის ნახვა"),
|
||||
("upgrade_remote_rustdesk_client_to{}_tip", "განაახლეთ RustDesk კლიენტი ვერსიამდე {} ან უფრო ახალი დისტანციურ მხარეზე!"),
|
||||
("upgrade_remote_rustdesk_client_to_{}_tip", ""),
|
||||
("view_camera_unsupported_tip", "დისტანციური მოწყობილობა არ უჭერს მხარს კამერის ნახვას."),
|
||||
("Enable camera", "კამერის ჩართვა"),
|
||||
("No cameras", "კამერა არ არის"),
|
||||
|
@ -672,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", "პრინტერი {} დაინსტალირებულია და მზად არის გამოსაყენებლად."),
|
||||
("Install {} Printer", "დააინსტალირეთ პრინტერი {}"),
|
||||
("Outgoing Print Jobs", "გამავალი ბეჭდვის დავალება"),
|
||||
("Incomming Print Jobs", "შემომავალი ბეჭდვის დავალება"),
|
||||
("Incoming Print Jobs", "შემომავალი ბეჭდვის დავალება"),
|
||||
("Incoming Print Job", "შემომავალი ბეჭდვის დავალება"),
|
||||
("use-the-default-printer-tip", "ნაგულისხმევი პრინტერის გამოყენება"),
|
||||
("use-the-selected-printer-tip", "არჩეული პრინტერის გამოყენება"),
|
||||
|
@ -682,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", "მართულ მხარეზე უფლებების პარამეტრები კრძალავს დისტანციურ ბეჭდვას."),
|
||||
("save-settings-tip", "პარამეტრების შენახვა"),
|
||||
("dont-show-again-tip", "აღარ აჩვენოთ"),
|
||||
].iter().cloned().collect();
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", "A(z) {} nyomtató készen áll"),
|
||||
("Install {} Printer", "A(z) {} nyomtató nyomtató telepítése"),
|
||||
("Outgoing Print Jobs", "Kimenő nyomtatási feladatok"),
|
||||
("Incomming Print Jobs", "Bejövő nyomtatási feladatok"),
|
||||
("Incoming Print Jobs", "Bejövő nyomtatási feladatok"),
|
||||
("Incoming Print Job", "Bejövő nyomtatási feladat"),
|
||||
("use-the-default-printer-tip", "Alapértelmezett nyomtató használata"),
|
||||
("use-the-selected-printer-tip", "Kiválasztott nyomtató használata"),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", "A távoli nyomtatás nincs engedélyezve"),
|
||||
("save-settings-tip", "Beállítások mentése"),
|
||||
("dont-show-again-tip", "Ne jelenítse meg újra"),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", "La stampante {} è installata e pronta all'uso."),
|
||||
("Install {} Printer", "Installa la stampante {}"),
|
||||
("Outgoing Print Jobs", "Lavori di stampa in uscita"),
|
||||
("Incomming Print Jobs", "Lavori di stampa in entrata"),
|
||||
("Incoming Print Jobs", "Lavori di stampa in entrata"),
|
||||
("Incoming Print Job", "Lavoro di stampa in entrata"),
|
||||
("use-the-default-printer-tip", "Usa la stampante predefinita"),
|
||||
("use-the-selected-printer-tip", "Usa la stampante selezionata"),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", "Le impostazioni di autorizzazione del lato controllato negano la stampa remota."),
|
||||
("save-settings-tip", "Salva impostazioni"),
|
||||
("dont-show-again-tip", "Non visualizzare più questo messaggio"),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", "Printeris {} ir instalēts un gatavs lietošanai."),
|
||||
("Install {} Printer", "Instalēt {} printeri"),
|
||||
("Outgoing Print Jobs", "Izejošie drukas darbi"),
|
||||
("Incomming Print Jobs", "Ienākošie drukas darbi"),
|
||||
("Incoming Print Jobs", "Ienākošie drukas darbi"),
|
||||
("Incoming Print Job", "Ienākošais drukas darbs"),
|
||||
("use-the-default-printer-tip", "Izmantot noklusējuma printeri"),
|
||||
("use-the-selected-printer-tip", "Izmantot atlasīto printeri"),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", "Kontrolētās puses atļauju iestatījumi liedz attālo drukāšanu."),
|
||||
("save-settings-tip", "Saglabāt iestatījumus"),
|
||||
("dont-show-again-tip", "Nerādīt šo vēlreiz"),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", "De printer {} is geïnstalleerd en klaar voor gebruik."),
|
||||
("Install {} Printer", "Installeer {} Printer"),
|
||||
("Outgoing Print Jobs", "Uitgaande Afdruktaken"),
|
||||
("Incomming Print Jobs", "Inkomende Afdruktaken"),
|
||||
("Incoming Print Jobs", "Inkomende Afdruktaken"),
|
||||
("Incoming Print Job", "Inkomende Afdruktaak"),
|
||||
("use-the-default-printer-tip", "Gebruik de standaard printer"),
|
||||
("use-the-selected-printer-tip", "Gebruik de geselecteerde printer"),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", "Machtigingsinstellingen aan beheerde zijde verhinderen afdrukken op afstand."),
|
||||
("save-settings-tip", "Instellingen opslaan"),
|
||||
("dont-show-again-tip", "Dit bericht wordt niet meer weergegeven"),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", "Drukarka {} jest zainstalowana i gotowa do użycia."),
|
||||
("Install {} Printer", "Zainstaluj drukarkę {}"),
|
||||
("Outgoing Print Jobs", "Wychodzące zadania drukowania"),
|
||||
("Incomming Print Jobs", "Przychodzące zadania drukowania"),
|
||||
("Incoming Print Jobs", "Przychodzące zadania drukowania"),
|
||||
("Incoming Print Job", "Przychodzące zadanie drukowania"),
|
||||
("use-the-default-printer-tip", "Użyj domyślnej drukarki"),
|
||||
("use-the-selected-printer-tip", "Użyj wybranej drukarki"),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", "Ustawienia uprawnień po zdalnej stronie uniemożliwiają zdalne drukowanie."),
|
||||
("save-settings-tip", "Zapisz ustawienia"),
|
||||
("dont-show-again-tip", "Nie pokazuj więcej"),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", "A impressora {} está instalada e operacional."),
|
||||
("Install {} Printer", "Instalar impressora {}"),
|
||||
("Outgoing Print Jobs", "Trabalhos de impressão enviados"),
|
||||
("Incomming Print Jobs", "Trabalhos de impressão recebidos"),
|
||||
("Incoming Print Jobs", "Trabalhos de impressão recebidos"),
|
||||
("Incoming Print Job", "Impressão recebida"),
|
||||
("use-the-default-printer-tip", "Usar impressora padrão"),
|
||||
("use-the-selected-printer-tip", "Usar impressora selecionada"),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", "As configurações do dispositivo controlado não permitem impressão remota."),
|
||||
("save-settings-tip", "Salvar configurações"),
|
||||
("dont-show-again-tip", "Não mostrar novamente"),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", "Принтер {} установлен и готов к использованию."),
|
||||
("Install {} Printer", "Установить принтер {}"),
|
||||
("Outgoing Print Jobs", "Исходящее задание печати"),
|
||||
("Incomming Print Jobs", "Входящее задание печати"),
|
||||
("Incoming Print Jobs", "Входящее задание печати"),
|
||||
("Incoming Print Job", "Входящее задание печати"),
|
||||
("use-the-default-printer-tip", "Использовать принтер по умолчанию"),
|
||||
("use-the-selected-printer-tip", "Использовать выбранный принтер"),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", "Настройки разрешений на управляемой стороне запрещают удалённую печать."),
|
||||
("save-settings-tip", "Сохранить настройки"),
|
||||
("dont-show-again-tip", "Больше не показывать"),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", "S'imprentadora {} est installada e pronta pro s'impreu."),
|
||||
("Install {} Printer", "Installa s'imprentadora {}"),
|
||||
("Outgoing Print Jobs", "Traballos de imprenta in essida"),
|
||||
("Incomming Print Jobs", "Traballos de imprenta in intrada"),
|
||||
("Incoming Print Jobs", "Traballos de imprenta in intrada"),
|
||||
("Incoming Print Job", "Traballu de imprenta in intrada"),
|
||||
("use-the-default-printer-tip", "Imprea s'imprentadora predefinida"),
|
||||
("use-the-selected-printer-tip", "Imprea s'imprentadora seletzionada"),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", "Sas impostatziones de sos permissos de s'ala controllada negant s'imprenta remota."),
|
||||
("save-settings-tip", "Sarva sas impostatziones"),
|
||||
("dont-show-again-tip", "Non mustres prus custu messàgiu"),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", "{} 印表機已安裝,您可以使用列印功能了。"),
|
||||
("Install {} Printer", "安裝 {} 印表機"),
|
||||
("Outgoing Print Jobs", "傳出的列印任務"),
|
||||
("Incomming Print Jobs", "傳入的列印任務"),
|
||||
("Incoming Print Jobs", "傳入的列印任務"),
|
||||
("Incoming Print Job", "傳入的列印任務"),
|
||||
("use-the-default-printer-tip", "使用預設的印表機"),
|
||||
("use-the-selected-printer-tip", "使用選取的印表機"),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", "被控端的權限設置拒絕了遠端列印。"),
|
||||
("save-settings-tip", "儲存設定"),
|
||||
("dont-show-again-tip", "不再顯示此訊息"),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("printer-{}-ready-tip", ""),
|
||||
("Install {} Printer", ""),
|
||||
("Outgoing Print Jobs", ""),
|
||||
("Incomming Print Jobs", ""),
|
||||
("Incoming Print Jobs", ""),
|
||||
("Incoming Print Job", ""),
|
||||
("use-the-default-printer-tip", ""),
|
||||
("use-the-selected-printer-tip", ""),
|
||||
|
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("remote-printing-disallowed-text-tip", ""),
|
||||
("save-settings-tip", ""),
|
||||
("dont-show-again-tip", ""),
|
||||
("Take screenshot", ""),
|
||||
("Taking screenshot", ""),
|
||||
("screenshot-merged-screen-not-supported-tip", ""),
|
||||
("screenshot-action-tip", ""),
|
||||
("Save as", ""),
|
||||
("Copy to clipboard", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
|
|
@ -2819,6 +2819,16 @@ impl Connection {
|
|||
Some(message::Union::VoiceCallResponse(_response)) => {
|
||||
// TODO: Maybe we can do a voice call from cm directly.
|
||||
}
|
||||
Some(message::Union::ScreenshotRequest(request)) => {
|
||||
if let Some(tx) = self.inner.tx.clone() {
|
||||
crate::video_service::set_take_screenshot(
|
||||
request.display as _,
|
||||
request.sid.clone(),
|
||||
tx,
|
||||
);
|
||||
self.refresh_video_display(Some(request.display as usize));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ use scrap::{
|
|||
codec::{Encoder, EncoderCfg},
|
||||
record::{Recorder, RecorderContext},
|
||||
vpxcodec::{VpxEncoderConfig, VpxVideoCodecId},
|
||||
CodecFormat, Display, EncodeInput, TraitCapturer,
|
||||
CodecFormat, Display, EncodeInput, TraitCapturer, TraitPixelBuffer,
|
||||
};
|
||||
#[cfg(windows)]
|
||||
use std::sync::Once;
|
||||
|
@ -70,6 +70,13 @@ lazy_static::lazy_static! {
|
|||
pub static ref VIDEO_QOS: Arc<Mutex<VideoQoS>> = Default::default();
|
||||
pub static ref IS_UAC_RUNNING: Arc<Mutex<bool>> = Default::default();
|
||||
pub static ref IS_FOREGROUND_WINDOW_ELEVATED: Arc<Mutex<bool>> = Default::default();
|
||||
static ref SCREENSHOTS: Mutex<HashMap<usize, Screenshot>> = Default::default();
|
||||
}
|
||||
|
||||
struct Screenshot {
|
||||
sid: String,
|
||||
tx: Sender,
|
||||
restore_vram: bool,
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -457,7 +464,7 @@ fn get_capturer(
|
|||
}
|
||||
|
||||
fn run(vs: VideoService) -> ResultType<()> {
|
||||
let _raii = Raii::new(vs.sp.name());
|
||||
let mut _raii = Raii::new(vs.sp.name());
|
||||
// Wayland only support one video capturer for now. It is ok to call ensure_inited() here.
|
||||
//
|
||||
// ensure_inited() is needed because clear() may be called.
|
||||
|
@ -639,6 +646,49 @@ fn run(vs: VideoService) -> ResultType<()> {
|
|||
Ok(frame) => {
|
||||
repeat_encode_counter = 0;
|
||||
if frame.valid() {
|
||||
let screenshot = SCREENSHOTS.lock().unwrap().remove(&display_idx);
|
||||
if let Some(mut screenshot) = screenshot {
|
||||
let restore_vram = screenshot.restore_vram;
|
||||
let (msg, w, h, data) = match &frame {
|
||||
scrap::Frame::PixelBuffer(f) => match get_rgba_from_pixelbuf(f) {
|
||||
Ok(rgba) => ("".to_owned(), f.width(), f.height(), rgba),
|
||||
Err(e) => {
|
||||
let serr = e.to_string();
|
||||
log::error!(
|
||||
"Failed to convert the pix format into rgba, {}",
|
||||
&serr
|
||||
);
|
||||
(format!("Convert pixfmt: {}", serr), 0, 0, vec![])
|
||||
}
|
||||
},
|
||||
scrap::Frame::Texture(_) => {
|
||||
if restore_vram {
|
||||
// Already set one time, just ignore to break infinite loop.
|
||||
// Though it's unreachable, this branch is kept to avoid infinite loop.
|
||||
(
|
||||
"Please change codec and try again.".to_owned(),
|
||||
0,
|
||||
0,
|
||||
vec![],
|
||||
)
|
||||
} else {
|
||||
#[cfg(all(windows, feature = "vram"))]
|
||||
VRamEncoder::set_not_use(sp.name(), true);
|
||||
screenshot.restore_vram = true;
|
||||
SCREENSHOTS.lock().unwrap().insert(display_idx, screenshot);
|
||||
_raii.try_vram = false;
|
||||
bail!("SWITCH");
|
||||
}
|
||||
}
|
||||
};
|
||||
std::thread::spawn(move || {
|
||||
handle_screenshot(screenshot, msg, w, h, data);
|
||||
});
|
||||
if restore_vram {
|
||||
bail!("SWITCH");
|
||||
}
|
||||
}
|
||||
|
||||
let frame = frame.to(encoder.yuvfmt(), &mut yuv, &mut mid_data)?;
|
||||
let send_conn_ids = handle_one_frame(
|
||||
display_idx,
|
||||
|
@ -764,24 +814,32 @@ fn run(vs: VideoService) -> ResultType<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
struct Raii(String);
|
||||
struct Raii {
|
||||
name: String,
|
||||
try_vram: bool,
|
||||
}
|
||||
|
||||
impl Raii {
|
||||
fn new(name: String) -> Self {
|
||||
log::info!("new video service: {}", name);
|
||||
VIDEO_QOS.lock().unwrap().new_display(name.clone());
|
||||
Raii(name)
|
||||
Raii {
|
||||
name,
|
||||
try_vram: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Raii {
|
||||
fn drop(&mut self) {
|
||||
log::info!("stop video service: {}", self.0);
|
||||
log::info!("stop video service: {}", self.name);
|
||||
#[cfg(feature = "vram")]
|
||||
VRamEncoder::set_not_use(self.0.clone(), false);
|
||||
if self.try_vram {
|
||||
VRamEncoder::set_not_use(self.name.clone(), false);
|
||||
}
|
||||
#[cfg(feature = "vram")]
|
||||
Encoder::update(scrap::codec::EncodingUpdate::Check);
|
||||
VIDEO_QOS.lock().unwrap().remove_display(&self.0);
|
||||
VIDEO_QOS.lock().unwrap().remove_display(&self.name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1206,3 +1264,77 @@ fn check_qos(
|
|||
drop(video_qos);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_take_screenshot(display_idx: usize, sid: String, tx: Sender) {
|
||||
SCREENSHOTS.lock().unwrap().insert(
|
||||
display_idx,
|
||||
Screenshot {
|
||||
sid,
|
||||
tx,
|
||||
restore_vram: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// We need to this function, because the `stride` may be larger than `width * 4`.
|
||||
fn get_rgba_from_pixelbuf<'a>(pixbuf: &scrap::PixelBuffer<'a>) -> ResultType<Vec<u8>> {
|
||||
let w = pixbuf.width();
|
||||
let h = pixbuf.height();
|
||||
let stride = pixbuf.stride();
|
||||
let Some(s) = stride.get(0) else {
|
||||
bail!("Invalid pixel buf stride.")
|
||||
};
|
||||
|
||||
if *s == w * 4 {
|
||||
let mut rgba = vec![];
|
||||
scrap::convert(pixbuf, scrap::Pixfmt::RGBA, &mut rgba)?;
|
||||
Ok(rgba)
|
||||
} else {
|
||||
let bgra = pixbuf.data();
|
||||
let mut bit_flipped = Vec::with_capacity(w * h * 4);
|
||||
for y in 0..h {
|
||||
for x in 0..w {
|
||||
let i = s * y + 4 * x;
|
||||
bit_flipped.extend_from_slice(&[bgra[i + 2], bgra[i + 1], bgra[i], bgra[i + 3]]);
|
||||
}
|
||||
}
|
||||
Ok(bit_flipped)
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_screenshot(screenshot: Screenshot, msg: String, w: usize, h: usize, data: Vec<u8>) {
|
||||
let mut response = ScreenshotResponse::new();
|
||||
response.sid = screenshot.sid;
|
||||
if msg.is_empty() {
|
||||
if data.is_empty() {
|
||||
response.msg = "Failed to take screenshot, please try again later.".to_owned();
|
||||
} else {
|
||||
fn encode_png(width: usize, height: usize, rgba: Vec<u8>) -> ResultType<Vec<u8>> {
|
||||
let mut png = Vec::new();
|
||||
let mut encoder =
|
||||
repng::Options::smallest(width as _, height as _).build(&mut png)?;
|
||||
encoder.write(&rgba)?;
|
||||
encoder.finish()?;
|
||||
Ok(png)
|
||||
}
|
||||
match encode_png(w as _, h as _, data) {
|
||||
Ok(png) => {
|
||||
response.data = png.into();
|
||||
}
|
||||
Err(e) => {
|
||||
response.msg = format!("Error encoding png: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
response.msg = msg;
|
||||
}
|
||||
let mut msg_out = Message::new();
|
||||
msg_out.set_screenshot_response(response);
|
||||
if let Err(e) = screenshot
|
||||
.tx
|
||||
.send((hbb_common::tokio::time::Instant::now(), Arc::new(msg_out)))
|
||||
{
|
||||
log::error!("Failed to send screenshot, {}", e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -230,6 +230,7 @@ class Header: Reactor.Component {
|
|||
{restart_enabled && (pi.platform == "Linux" || pi.platform == "Windows" || pi.platform == "Mac OS") ? <li #restart_remote_device>{translate('Restart remote device')}</li> : ""}
|
||||
{keyboard_enabled ? <li #lock-screen>{translate('Insert Lock')}</li> : ""}
|
||||
{keyboard_enabled && pi.platform == "Windows" && pi.sas_enabled ? <li #block-input>{translate("Block user input")}</li> : ""}
|
||||
{handler.is_screenshot_supported() ? <li #take-screenshot>{translate('Take screenshot')}</li> : "" }
|
||||
<li #refresh>{translate('Refresh')}</li>
|
||||
</menu>
|
||||
</popup>;
|
||||
|
@ -376,6 +377,10 @@ class Header: Reactor.Component {
|
|||
event click $(#lock-screen) {
|
||||
handler.lock_screen();
|
||||
}
|
||||
|
||||
event click $(#take-screenshot) {
|
||||
handler.take_screenshot(pi.current_display, "");
|
||||
}
|
||||
|
||||
event click $(#refresh) {
|
||||
// 0 is just a dummy value. It will be ignored by the handler.
|
||||
|
@ -546,6 +551,26 @@ handler.setCurrentDisplay = function(v) {
|
|||
}
|
||||
}
|
||||
|
||||
handler.screenshot = function(msg) {
|
||||
if (msg) {
|
||||
msgbox(
|
||||
"custom-nocancel-nook-hasclose-error",
|
||||
translate("Take screenshot"),
|
||||
msg,
|
||||
"",
|
||||
function() {}
|
||||
);
|
||||
} else {
|
||||
msgbox(
|
||||
"custom-take-screenshot-nocancel-nook",
|
||||
translate("Take screenshot"),
|
||||
translate("screenshot-action-tip"),
|
||||
"",
|
||||
function() {}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function updatePrivacyMode() {
|
||||
var el = $(li#privacy-mode);
|
||||
if (el) {
|
||||
|
|
|
@ -132,6 +132,17 @@ class MsgboxComponent: Reactor.Component {
|
|||
return this.type.indexOf("skip") >= 0;
|
||||
}
|
||||
|
||||
function getScreenshotButtons() {
|
||||
var isScreenshot = this.type.indexOf("take-screenshot") >= 0;
|
||||
return isScreenshot
|
||||
? <div>
|
||||
<button .button #screenshotSaveAs .outline>{translate('Save as')}...</button>
|
||||
<button .button #screenshotCopyToClip .outline>{translate('Copy to clipboard')}</button>
|
||||
<button .button #screenshotCancel .outline>{translate('Cancel')}</button>
|
||||
</div>
|
||||
: "";
|
||||
}
|
||||
|
||||
function render() {
|
||||
this.set_outline_focus();
|
||||
var color = this.getColor();
|
||||
|
@ -170,6 +181,7 @@ class MsgboxComponent: Reactor.Component {
|
|||
{hasOk || this.hasRetry ? <button .button #submit>{translate(this.hasRetry ? "Retry" : "OK")}</button> : ""}
|
||||
{hasLink ? <button .button #jumplink .outline>{translate('JumpLink')}</button> : ""}
|
||||
{hasClose ? <button .button #cancel .outline>{translate('Close')}</button> : ""}
|
||||
{this.getScreenshotButtons()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -245,6 +257,39 @@ class MsgboxComponent: Reactor.Component {
|
|||
this.close();
|
||||
}
|
||||
}
|
||||
|
||||
event click $(button#screenshotSaveAs) {
|
||||
this.close();
|
||||
|
||||
handler.leave(handler.get_keyboard_mode());
|
||||
const filter = "Png file (*.png)";
|
||||
const defaultExt = "png";
|
||||
const initialPath = System.path(#USER_DOCUMENTS, "screenshot");
|
||||
const caption = "Save as";
|
||||
var url = view.selectFile(#save, filter, defaultExt, initialPath, caption);
|
||||
handler.enter(handler.get_keyboard_mode());
|
||||
if(url) {
|
||||
var res = handler.handle_screenshot("0:" + URL.toPath(url));
|
||||
if (res) {
|
||||
msgbox("custom-error-nocancel-nook-hasclose", "Take screenshot", res, "", function() {});
|
||||
}
|
||||
} else {
|
||||
handler.handle_screenshot("2");
|
||||
}
|
||||
}
|
||||
|
||||
event click $(button#screenshotCopyToClip) {
|
||||
this.close();
|
||||
var res = handler.handle_screenshot("1");
|
||||
if (res) {
|
||||
msgbox("custom-error-nocancel-nook-hasclose", "Take screenshot", res, "", function() {});
|
||||
}
|
||||
}
|
||||
|
||||
event click $(button#screenshotCancel) {
|
||||
this.close();
|
||||
handler.handle_screenshot("2");
|
||||
}
|
||||
|
||||
event keydown (evt) {
|
||||
if (!evt.shortcutKey) {
|
||||
|
|
|
@ -383,6 +383,10 @@ impl InvokeUiSession for SciterHandler {
|
|||
fn printer_request(&self, id: i32, path: String) {
|
||||
self.call("printerRequest", &make_args!(id, path));
|
||||
}
|
||||
|
||||
fn handle_screenshot_resp(&self, _sid: String, msg: String) {
|
||||
self.call("screenshot", &make_args!(msg));
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SciterSession(Session<SciterHandler>);
|
||||
|
@ -529,6 +533,9 @@ impl sciter::EventHandler for SciterSession {
|
|||
fn save_custom_image_quality(i32);
|
||||
fn refresh_video(i32);
|
||||
fn record_screen(bool);
|
||||
fn is_screenshot_supported();
|
||||
fn take_screenshot(i32, String);
|
||||
fn handle_screenshot(String);
|
||||
fn get_toggle_option(String);
|
||||
fn is_privacy_mode_supported();
|
||||
fn toggle_option(String);
|
||||
|
@ -866,6 +873,10 @@ impl SciterSession {
|
|||
fn on_printer_selected(&self, id: i32, path: String, printer_name: String) {
|
||||
self.printer_response(id, path, printer_name);
|
||||
}
|
||||
|
||||
fn handle_screenshot(&self, action: String) -> String {
|
||||
crate::client::screenshot::handle_screenshot(action)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_fd(id: i32, entries: &Vec<FileEntry>, only_count: bool) -> Value {
|
||||
|
|
|
@ -412,6 +412,14 @@ impl<T: InvokeUiSession> Session<T> {
|
|||
self.send(Data::RecordScreen(start));
|
||||
}
|
||||
|
||||
pub fn is_screenshot_supported(&self) -> bool {
|
||||
crate::common::is_support_screenshot_num(self.lc.read().unwrap().version)
|
||||
}
|
||||
|
||||
pub fn take_screenshot(&self, display: i32, sid: String) {
|
||||
self.send(Data::TakeScreenshot((display, sid)));
|
||||
}
|
||||
|
||||
pub fn is_recording(&self) -> bool {
|
||||
self.lc.read().unwrap().record_state
|
||||
}
|
||||
|
@ -1586,6 +1594,7 @@ pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default {
|
|||
fn update_record_status(&self, start: bool);
|
||||
fn update_empty_dirs(&self, _res: ReadEmptyDirsResponse) {}
|
||||
fn printer_request(&self, id: i32, path: String);
|
||||
fn handle_screenshot_resp(&self, sid: String, msg: String);
|
||||
}
|
||||
|
||||
impl<T: InvokeUiSession> Deref for Session<T> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue