mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-06-30 12:24:58 +03:00
Compare commits
10 Commits
1.4.7
...
screenlock
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3bd9fa933 | ||
|
|
bf206dc309 | ||
|
|
6d116cf1c9 | ||
|
|
1fc33218dc | ||
|
|
b73e5bbfa0 | ||
|
|
78533e428e | ||
|
|
cc7fe4efdc | ||
|
|
84af60c07e | ||
|
|
6426269d41 | ||
|
|
7c41f993fe |
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -292,7 +292,7 @@ checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "arboard"
|
name = "arboard"
|
||||||
version = "3.4.0"
|
version = "3.4.0"
|
||||||
source = "git+https://github.com/rustdesk-org/arboard#85be1218668ff218a7b170c9d424fde73e069914"
|
source = "git+https://github.com/rustdesk-org/arboard#c7d5781f563176df9efd8df6287e823fb1b9bed5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clipboard-win",
|
"clipboard-win",
|
||||||
"core-graphics 0.23.2",
|
"core-graphics 0.23.2",
|
||||||
|
|||||||
@@ -3713,14 +3713,54 @@ Widget loadPowered(BuildContext context) {
|
|||||||
).marginOnly(top: 6);
|
).marginOnly(top: 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
// max 300 x 60
|
const _kDefaultLogoAsset = 'assets/logo.png';
|
||||||
Widget loadLogo() {
|
const _kLightLogoAsset = 'assets/logo_light.png';
|
||||||
return FutureBuilder<ByteData>(
|
const _kDarkLogoAsset = 'assets/logo_dark.png';
|
||||||
future: rootBundle.load('assets/logo.png'),
|
|
||||||
builder: (BuildContext context, AsyncSnapshot<ByteData> snapshot) {
|
List<String> _logoAssetCandidatesForBrightness(Brightness brightness) {
|
||||||
if (snapshot.hasData) {
|
return brightness == Brightness.dark
|
||||||
|
? [_kDarkLogoAsset, _kDefaultLogoAsset]
|
||||||
|
: [_kLightLogoAsset, _kDefaultLogoAsset];
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String?> _resolveLogoAsset(Brightness brightness) async {
|
||||||
|
for (final asset in _logoAssetCandidatesForBrightness(brightness)) {
|
||||||
|
try {
|
||||||
|
await rootBundle.load(asset);
|
||||||
|
return asset;
|
||||||
|
} on FlutterError {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _Logo extends StatefulWidget {
|
||||||
|
const _Logo();
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_Logo> createState() => _LogoState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LogoState extends State<_Logo> {
|
||||||
|
final Map<Brightness, Future<String?>> _logoFutures = {};
|
||||||
|
|
||||||
|
Future<String?> _logoFutureFor(Brightness brightness) {
|
||||||
|
return _logoFutures.putIfAbsent(
|
||||||
|
brightness,
|
||||||
|
() => _resolveLogoAsset(brightness),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return FutureBuilder<String?>(
|
||||||
|
future: _logoFutureFor(Theme.of(context).brightness),
|
||||||
|
builder: (BuildContext context, AsyncSnapshot<String?> snapshot) {
|
||||||
|
final asset = snapshot.data;
|
||||||
|
if (asset != null) {
|
||||||
final image = Image.asset(
|
final image = Image.asset(
|
||||||
'assets/logo.png',
|
asset,
|
||||||
fit: BoxFit.contain,
|
fit: BoxFit.contain,
|
||||||
errorBuilder: (ctx, error, stackTrace) {
|
errorBuilder: (ctx, error, stackTrace) {
|
||||||
return Container();
|
return Container();
|
||||||
@@ -3732,9 +3772,14 @@ Widget loadLogo() {
|
|||||||
).marginOnly(left: 12, right: 12, top: 12);
|
).marginOnly(left: 12, right: 12, top: 12);
|
||||||
}
|
}
|
||||||
return const Offstage();
|
return const Offstage();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// max 300 x 60
|
||||||
|
Widget loadLogo() => const _Logo();
|
||||||
|
|
||||||
Widget loadIcon(double size) {
|
Widget loadIcon(double size) {
|
||||||
return Image.asset('assets/icon.png',
|
return Image.asset('assets/icon.png',
|
||||||
width: size,
|
width: size,
|
||||||
|
|||||||
@@ -532,9 +532,7 @@ class _RawTouchGestureDetectorRegionState
|
|||||||
// Official
|
// Official
|
||||||
TapGestureRecognizer:
|
TapGestureRecognizer:
|
||||||
GestureRecognizerFactoryWithHandlers<TapGestureRecognizer>(
|
GestureRecognizerFactoryWithHandlers<TapGestureRecognizer>(
|
||||||
() => TapGestureRecognizer(
|
() => TapGestureRecognizer(), (instance) {
|
||||||
supportedDevices: kTouchBasedDeviceKinds,
|
|
||||||
), (instance) {
|
|
||||||
instance
|
instance
|
||||||
..onTapDown = onTapDown
|
..onTapDown = onTapDown
|
||||||
..onTapUp = onTapUp
|
..onTapUp = onTapUp
|
||||||
@@ -542,18 +540,14 @@ class _RawTouchGestureDetectorRegionState
|
|||||||
}),
|
}),
|
||||||
DoubleTapGestureRecognizer:
|
DoubleTapGestureRecognizer:
|
||||||
GestureRecognizerFactoryWithHandlers<DoubleTapGestureRecognizer>(
|
GestureRecognizerFactoryWithHandlers<DoubleTapGestureRecognizer>(
|
||||||
() => DoubleTapGestureRecognizer(
|
() => DoubleTapGestureRecognizer(), (instance) {
|
||||||
supportedDevices: kTouchBasedDeviceKinds,
|
|
||||||
), (instance) {
|
|
||||||
instance
|
instance
|
||||||
..onDoubleTapDown = onDoubleTapDown
|
..onDoubleTapDown = onDoubleTapDown
|
||||||
..onDoubleTap = onDoubleTap;
|
..onDoubleTap = onDoubleTap;
|
||||||
}),
|
}),
|
||||||
LongPressGestureRecognizer:
|
LongPressGestureRecognizer:
|
||||||
GestureRecognizerFactoryWithHandlers<LongPressGestureRecognizer>(
|
GestureRecognizerFactoryWithHandlers<LongPressGestureRecognizer>(
|
||||||
() => LongPressGestureRecognizer(
|
() => LongPressGestureRecognizer(), (instance) {
|
||||||
supportedDevices: kTouchBasedDeviceKinds,
|
|
||||||
), (instance) {
|
|
||||||
instance
|
instance
|
||||||
..onLongPressDown = onLongPressDown
|
..onLongPressDown = onLongPressDown
|
||||||
..onLongPressUp = onLongPressUp
|
..onLongPressUp = onLongPressUp
|
||||||
@@ -563,9 +557,7 @@ class _RawTouchGestureDetectorRegionState
|
|||||||
// Customized
|
// Customized
|
||||||
HoldTapMoveGestureRecognizer:
|
HoldTapMoveGestureRecognizer:
|
||||||
GestureRecognizerFactoryWithHandlers<HoldTapMoveGestureRecognizer>(
|
GestureRecognizerFactoryWithHandlers<HoldTapMoveGestureRecognizer>(
|
||||||
() => HoldTapMoveGestureRecognizer(
|
() => HoldTapMoveGestureRecognizer(),
|
||||||
supportedDevices: kTouchBasedDeviceKinds,
|
|
||||||
),
|
|
||||||
(instance) => instance
|
(instance) => instance
|
||||||
..onHoldDragStart = onHoldDragStart
|
..onHoldDragStart = onHoldDragStart
|
||||||
..onHoldDragUpdate = onHoldDragUpdate
|
..onHoldDragUpdate = onHoldDragUpdate
|
||||||
@@ -573,18 +565,14 @@ class _RawTouchGestureDetectorRegionState
|
|||||||
..onHoldDragEnd = onHoldDragEnd),
|
..onHoldDragEnd = onHoldDragEnd),
|
||||||
DoubleFinerTapGestureRecognizer:
|
DoubleFinerTapGestureRecognizer:
|
||||||
GestureRecognizerFactoryWithHandlers<DoubleFinerTapGestureRecognizer>(
|
GestureRecognizerFactoryWithHandlers<DoubleFinerTapGestureRecognizer>(
|
||||||
() => DoubleFinerTapGestureRecognizer(
|
() => DoubleFinerTapGestureRecognizer(), (instance) {
|
||||||
supportedDevices: kTouchBasedDeviceKinds,
|
|
||||||
), (instance) {
|
|
||||||
instance
|
instance
|
||||||
..onDoubleFinerTap = onDoubleFinerTap
|
..onDoubleFinerTap = onDoubleFinerTap
|
||||||
..onDoubleFinerTapDown = onDoubleFinerTapDown;
|
..onDoubleFinerTapDown = onDoubleFinerTapDown;
|
||||||
}),
|
}),
|
||||||
CustomTouchGestureRecognizer:
|
CustomTouchGestureRecognizer:
|
||||||
GestureRecognizerFactoryWithHandlers<CustomTouchGestureRecognizer>(
|
GestureRecognizerFactoryWithHandlers<CustomTouchGestureRecognizer>(
|
||||||
() => CustomTouchGestureRecognizer(
|
() => CustomTouchGestureRecognizer(), (instance) {
|
||||||
supportedDevices: kTouchBasedDeviceKinds,
|
|
||||||
), (instance) {
|
|
||||||
instance.onOneFingerPanStart =
|
instance.onOneFingerPanStart =
|
||||||
(DragStartDetails d) => onOneFingerPanStart(context, d);
|
(DragStartDetails d) => onOneFingerPanStart(context, d);
|
||||||
instance
|
instance
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class _InstallPageBodyState extends State<_InstallPageBody>
|
|||||||
late final TextEditingController controller;
|
late final TextEditingController controller;
|
||||||
final RxBool startmenu = true.obs;
|
final RxBool startmenu = true.obs;
|
||||||
final RxBool desktopicon = true.obs;
|
final RxBool desktopicon = true.obs;
|
||||||
final RxBool printer = true.obs;
|
final RxBool printer = false.obs;
|
||||||
final RxBool showProgress = false.obs;
|
final RxBool showProgress = false.obs;
|
||||||
final RxBool btnEnabled = true.obs;
|
final RxBool btnEnabled = true.obs;
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ class _InstallPageBodyState extends State<_InstallPageBody>
|
|||||||
final installOptions = jsonDecode(bind.installInstallOptions());
|
final installOptions = jsonDecode(bind.installInstallOptions());
|
||||||
startmenu.value = installOptions['STARTMENUSHORTCUTS'] != '0';
|
startmenu.value = installOptions['STARTMENUSHORTCUTS'] != '0';
|
||||||
desktopicon.value = installOptions['DESKTOPSHORTCUTS'] != '0';
|
desktopicon.value = installOptions['DESKTOPSHORTCUTS'] != '0';
|
||||||
printer.value = installOptions['PRINTER'] != '0';
|
printer.value = installOptions['PRINTER'] == '1';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -517,10 +517,12 @@ class _RemotePageState extends State<RemotePage> with WidgetsBindingObserver {
|
|||||||
}
|
}
|
||||||
return Container(
|
return Container(
|
||||||
color: MyTheme.canvasColor,
|
color: MyTheme.canvasColor,
|
||||||
child: RawTouchGestureDetectorRegion(
|
child: inputModel.isPhysicalMouse.value
|
||||||
child: getBodyForMobile(),
|
? getBodyForMobile()
|
||||||
ffi: gFFI,
|
: RawTouchGestureDetectorRegion(
|
||||||
),
|
child: getBodyForMobile(),
|
||||||
|
ffi: gFFI,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -259,11 +259,13 @@ class _ViewCameraPageState extends State<ViewCameraPage>
|
|||||||
}
|
}
|
||||||
return Container(
|
return Container(
|
||||||
color: MyTheme.canvasColor,
|
color: MyTheme.canvasColor,
|
||||||
child: RawTouchGestureDetectorRegion(
|
child: inputModel.isPhysicalMouse.value
|
||||||
child: getBodyForMobile(),
|
? getBodyForMobile()
|
||||||
ffi: gFFI,
|
: RawTouchGestureDetectorRegion(
|
||||||
isCamera: true,
|
child: getBodyForMobile(),
|
||||||
),
|
ffi: gFFI,
|
||||||
|
isCamera: true,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -117,13 +117,13 @@ void showServerSettingsWithValue(
|
|||||||
),
|
),
|
||||||
SizedBox(width: 8),
|
SizedBox(width: 8),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: TextFormField(
|
child: serverSettingsTextFormField(
|
||||||
|
label: label,
|
||||||
controller: controller,
|
controller: controller,
|
||||||
decoration: InputDecoration(
|
errorMsg: errorMsg,
|
||||||
errorText: errorMsg.isEmpty ? null : errorMsg,
|
contentPadding:
|
||||||
contentPadding:
|
EdgeInsets.symmetric(horizontal: 8, vertical: 12),
|
||||||
EdgeInsets.symmetric(horizontal: 8, vertical: 12),
|
showLabelText: false,
|
||||||
),
|
|
||||||
validator: validator,
|
validator: validator,
|
||||||
autofocus: autofocus,
|
autofocus: autofocus,
|
||||||
).workaroundFreezeLinuxMint(),
|
).workaroundFreezeLinuxMint(),
|
||||||
@@ -132,12 +132,10 @@ void showServerSettingsWithValue(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TextFormField(
|
return serverSettingsTextFormField(
|
||||||
|
label: label,
|
||||||
controller: controller,
|
controller: controller,
|
||||||
decoration: InputDecoration(
|
errorMsg: errorMsg,
|
||||||
labelText: label,
|
|
||||||
errorText: errorMsg.isEmpty ? null : errorMsg,
|
|
||||||
),
|
|
||||||
validator: validator,
|
validator: validator,
|
||||||
).workaroundFreezeLinuxMint();
|
).workaroundFreezeLinuxMint();
|
||||||
}
|
}
|
||||||
@@ -209,6 +207,35 @@ void showServerSettingsWithValue(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextFormField serverSettingsTextFormField({
|
||||||
|
required String label,
|
||||||
|
required TextEditingController controller,
|
||||||
|
required String errorMsg,
|
||||||
|
String? Function(String?)? validator,
|
||||||
|
bool autofocus = false,
|
||||||
|
bool showLabelText = true,
|
||||||
|
EdgeInsetsGeometry? contentPadding,
|
||||||
|
}) {
|
||||||
|
return TextFormField(
|
||||||
|
controller: controller,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: showLabelText ? label : null,
|
||||||
|
errorText: errorMsg.isEmpty ? null : errorMsg,
|
||||||
|
contentPadding: contentPadding,
|
||||||
|
),
|
||||||
|
validator: validator,
|
||||||
|
autofocus: autofocus,
|
||||||
|
keyboardType: TextInputType.visiblePassword,
|
||||||
|
textCapitalization: TextCapitalization.none,
|
||||||
|
autocorrect: false,
|
||||||
|
enableSuggestions: false,
|
||||||
|
smartDashesType: SmartDashesType.disabled,
|
||||||
|
smartQuotesType: SmartQuotesType.disabled,
|
||||||
|
enableIMEPersonalizedLearning: false,
|
||||||
|
spellCheckConfiguration: const SpellCheckConfiguration.disabled(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void setPrivacyModeDialog(
|
void setPrivacyModeDialog(
|
||||||
OverlayDialogManager dialogManager,
|
OverlayDialogManager dialogManager,
|
||||||
List<TToggleMenu> privacyModeList,
|
List<TToggleMenu> privacyModeList,
|
||||||
|
|||||||
Submodule libs/hbb_common updated: df6badca5b...387603f47c
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import optparse
|
import optparse
|
||||||
|
import subprocess
|
||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
import brotli
|
import brotli
|
||||||
import datetime
|
import datetime
|
||||||
@@ -65,11 +66,15 @@ def write_app_metadata(output_folder: str):
|
|||||||
print(f"App metadata has been written to {output_path}")
|
print(f"App metadata has been written to {output_path}")
|
||||||
|
|
||||||
def build_portable(output_folder: str, target: str):
|
def build_portable(output_folder: str, target: str):
|
||||||
os.chdir(output_folder)
|
current_dir = os.getcwd()
|
||||||
if target:
|
try:
|
||||||
os.system("cargo build --locked --release --target " + target)
|
os.chdir(output_folder)
|
||||||
else:
|
cmd = ["cargo", "build", "--locked", "--release"]
|
||||||
os.system("cargo build --locked --release")
|
if target:
|
||||||
|
cmd.extend(["--target", target])
|
||||||
|
subprocess.run(cmd, check=True)
|
||||||
|
finally:
|
||||||
|
os.chdir(current_dir)
|
||||||
|
|
||||||
# Linux: python3 generate.py -f ../rustdesk-portable-packer/test -o . -e ./test/main.py
|
# Linux: python3 generate.py -f ../rustdesk-portable-packer/test -o . -e ./test/main.py
|
||||||
# Windows: python3 .\generate.py -f ..\rustdesk\flutter\build\windows\runner\Debug\ -o . -e ..\rustdesk\flutter\build\windows\runner\Debug\rustdesk.exe
|
# Windows: python3 .\generate.py -f ..\rustdesk\flutter\build\windows\runner\Debug\ -o . -e ..\rustdesk\flutter\build\windows\runner\Debug\rustdesk.exe
|
||||||
|
|||||||
@@ -67,7 +67,7 @@
|
|||||||
Some msi packages reset the `VersionNT` value to 1000 on Windows 10.
|
Some msi packages reset the `VersionNT` value to 1000 on Windows 10.
|
||||||
https://www.advancedinstaller.com/user-guide/qa-OS-dependent-install.html -->
|
https://www.advancedinstaller.com/user-guide/qa-OS-dependent-install.html -->
|
||||||
<!-- Remote printer also works on Win8.1 in my test. -->
|
<!-- Remote printer also works on Win8.1 in my test. -->
|
||||||
<Custom Action="InstallPrinter" Before="InstallFinalize" Condition="VersionNT >= 603 AND PRINTER = 1 OR PRINTER = "Y" OR PRINTER = "y"" />
|
<Custom Action="InstallPrinter" Before="InstallFinalize" Condition="VersionNT >= 603 AND (PRINTER = 1 OR PRINTER = "Y" OR PRINTER = "y")" />
|
||||||
<Custom Action="InstallPrinter.SetParam" Before="InstallPrinter" Condition="VersionNT >= 603" />
|
<Custom Action="InstallPrinter.SetParam" Before="InstallPrinter" Condition="VersionNT >= 603" />
|
||||||
|
|
||||||
<!--Workaround of "fire:FirewallException". If Outbound="Yes" or Outbound="true", the following error occurs.-->
|
<!--Workaround of "fire:FirewallException". If Outbound="Yes" or Outbound="true", the following error occurs.-->
|
||||||
|
|||||||
@@ -4,17 +4,17 @@
|
|||||||
<?include ..\Includes.wxi?>
|
<?include ..\Includes.wxi?>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Properties and related actions for specifying whether to install start menu/desktop shortcuts.
|
Properties and related actions for specifying whether to install shortcuts and the printer.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!-- These are the actual properties that get used in conditions to determine whether to
|
<!-- These are the actual properties that get used in conditions to determine whether to
|
||||||
install start menu shortcuts, they are initialized with a default value to install shortcuts.
|
install start menu shortcuts or the printer. Shortcut properties default to install;
|
||||||
They should not be set directly from the command line or registry, instead the CREATE* properties
|
PRINTER defaults to not install. The CREATE* properties below update shortcut
|
||||||
below should be set, then they will update these properties with their values only if set. -->
|
properties from command line, bundle, or registry values. -->
|
||||||
<Property Id="STARTMENUSHORTCUTS" Value="1" Secure="yes"></Property>
|
<Property Id="STARTMENUSHORTCUTS" Value="1" Secure="yes"></Property>
|
||||||
<Property Id="DESKTOPSHORTCUTS" Value="1" Secure="yes"></Property>
|
<Property Id="DESKTOPSHORTCUTS" Value="1" Secure="yes"></Property>
|
||||||
<Property Id="STARTUPSHORTCUTS" Value="1" Secure="yes"></Property>
|
<Property Id="STARTUPSHORTCUTS" Value="1" Secure="yes"></Property>
|
||||||
<Property Id="PRINTER" Value="1" Secure="yes"></Property>
|
<Property Id="PRINTER" Secure="yes"></Property>
|
||||||
|
|
||||||
<!-- These properties get set from either the command line, bundle or registry value,
|
<!-- These properties get set from either the command line, bundle or registry value,
|
||||||
if set they update the properties above with their value. -->
|
if set they update the properties above with their value. -->
|
||||||
@@ -77,7 +77,11 @@
|
|||||||
<!-- If a command line value or registry value was set, update the main properties with the value -->
|
<!-- If a command line value or registry value was set, update the main properties with the value -->
|
||||||
<SetProperty Id="STARTMENUSHORTCUTS" Value="" After="RestoreSavedStartMenuShortcutsValue" Sequence="first" Condition="CREATESTARTMENUSHORTCUTS AND NOT (CREATESTARTMENUSHORTCUTS = 1 OR CREATESTARTMENUSHORTCUTS = "Y" OR CREATESTARTMENUSHORTCUTS = "y")" />
|
<SetProperty Id="STARTMENUSHORTCUTS" Value="" After="RestoreSavedStartMenuShortcutsValue" Sequence="first" Condition="CREATESTARTMENUSHORTCUTS AND NOT (CREATESTARTMENUSHORTCUTS = 1 OR CREATESTARTMENUSHORTCUTS = "Y" OR CREATESTARTMENUSHORTCUTS = "y")" />
|
||||||
<SetProperty Id="DESKTOPSHORTCUTS" Value="" After="RestoreSavedDesktopShortcutsValue" Sequence="first" Condition="CREATEDESKTOPSHORTCUTS AND NOT (CREATEDESKTOPSHORTCUTS = 1 OR CREATEDESKTOPSHORTCUTS = "Y" OR CREATEDESKTOPSHORTCUTS = "y")" />
|
<SetProperty Id="DESKTOPSHORTCUTS" Value="" After="RestoreSavedDesktopShortcutsValue" Sequence="first" Condition="CREATEDESKTOPSHORTCUTS AND NOT (CREATEDESKTOPSHORTCUTS = 1 OR CREATEDESKTOPSHORTCUTS = "Y" OR CREATEDESKTOPSHORTCUTS = "y")" />
|
||||||
<SetProperty Id="PRINTER" Value="" After="RestoreSavedPrinterValue" Sequence="first" Condition="INSTALLPRINTER AND NOT (INSTALLPRINTER = 1 OR INSTALLPRINTER = "Y" OR INSTALLPRINTER = "y")" />
|
<!-- PRINTER defaults to empty now, so a saved or command-line INSTALLPRINTER=1
|
||||||
|
must explicitly enable the main PRINTER property. Non-truthy INSTALLPRINTER
|
||||||
|
values still clear PRINTER so upgrades preserve an explicit disabled choice. -->
|
||||||
|
<SetProperty Action="SetPrinterValueEnabled" Id="PRINTER" Value="1" After="RestoreSavedPrinterValue" Sequence="first" Condition="INSTALLPRINTER = 1 OR INSTALLPRINTER = "Y" OR INSTALLPRINTER = "y"" />
|
||||||
|
<SetProperty Action="SetPrinterValueDisabled" Id="PRINTER" Value="" After="SetPrinterValueEnabled" Sequence="first" Condition="INSTALLPRINTER AND NOT (INSTALLPRINTER = 1 OR INSTALLPRINTER = "Y" OR INSTALLPRINTER = "y")" />
|
||||||
|
|
||||||
</Fragment>
|
</Fragment>
|
||||||
</Wix>
|
</Wix>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ use uuid::Uuid;
|
|||||||
use crate::{
|
use crate::{
|
||||||
check_port,
|
check_port,
|
||||||
common::input::{MOUSE_BUTTON_LEFT, MOUSE_BUTTON_RIGHT, MOUSE_TYPE_DOWN, MOUSE_TYPE_UP},
|
common::input::{MOUSE_BUTTON_LEFT, MOUSE_BUTTON_RIGHT, MOUSE_TYPE_DOWN, MOUSE_TYPE_UP},
|
||||||
|
common::PLATFORM_ADDITION_IS_LOGIN_SCREEN,
|
||||||
create_symmetric_key_msg, decode_id_pk, get_rs_pk, is_keyboard_mode_supported,
|
create_symmetric_key_msg, decode_id_pk, get_rs_pk, is_keyboard_mode_supported,
|
||||||
kcp_stream::KcpStream,
|
kcp_stream::KcpStream,
|
||||||
secure_tcp,
|
secure_tcp,
|
||||||
@@ -1901,11 +1902,11 @@ impl LoginConfigHandler {
|
|||||||
|
|
||||||
/// Check if the client should auto login.
|
/// Check if the client should auto login.
|
||||||
/// Return password if the client should auto login, otherwise return empty string.
|
/// Return password if the client should auto login, otherwise return empty string.
|
||||||
pub fn should_auto_login(&self) -> String {
|
pub fn should_auto_login(&self, pi: &PeerInfo) -> String {
|
||||||
let l = self.lock_after_session_end.v;
|
let l = self.lock_after_session_end.v;
|
||||||
let a = !self.get_option("auto-login").is_empty();
|
let a = !self.get_option("auto-login").is_empty();
|
||||||
let p = self.get_option("os-password");
|
let p = self.get_option("os-password");
|
||||||
if !p.is_empty() && l && a {
|
if !p.is_empty() && l && a && !peer_reports_unlocked_desktop(pi) {
|
||||||
p
|
p
|
||||||
} else {
|
} else {
|
||||||
"".to_owned()
|
"".to_owned()
|
||||||
@@ -2804,6 +2805,67 @@ impl LoginConfigHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn peer_reports_unlocked_desktop(pi: &PeerInfo) -> bool {
|
||||||
|
serde_json::from_str::<HashMap<String, serde_json::Value>>(&pi.platform_additions)
|
||||||
|
.ok()
|
||||||
|
.and_then(|platform_additions| {
|
||||||
|
platform_additions
|
||||||
|
.get(PLATFORM_ADDITION_IS_LOGIN_SCREEN)
|
||||||
|
.and_then(|value| value.as_bool())
|
||||||
|
})
|
||||||
|
== Some(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use hbb_common::message_proto::PeerInfo;
|
||||||
|
|
||||||
|
fn login_config_handler() -> super::LoginConfigHandler {
|
||||||
|
let mut handler = super::LoginConfigHandler::default();
|
||||||
|
handler.config.lock_after_session_end.v = true;
|
||||||
|
handler
|
||||||
|
.config
|
||||||
|
.options
|
||||||
|
.insert("auto-login".to_owned(), "Y".to_owned());
|
||||||
|
handler
|
||||||
|
.config
|
||||||
|
.options
|
||||||
|
.insert("os-password".to_owned(), "secret".to_owned());
|
||||||
|
handler
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peer_info(platform_additions: &str) -> PeerInfo {
|
||||||
|
PeerInfo {
|
||||||
|
platform_additions: platform_additions.to_owned(),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_auto_login_skips_unlocked_peer() {
|
||||||
|
let handler = login_config_handler();
|
||||||
|
let pi = peer_info(r#"{"is_login_screen":false}"#);
|
||||||
|
|
||||||
|
assert_eq!("", handler.should_auto_login(&pi));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_auto_login_keeps_peer_on_login_screen() {
|
||||||
|
let handler = login_config_handler();
|
||||||
|
let pi = peer_info(r#"{"is_login_screen":true}"#);
|
||||||
|
|
||||||
|
assert_eq!("secret", handler.should_auto_login(&pi));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_auto_login_keeps_legacy_peer_without_login_screen_state() {
|
||||||
|
let handler = login_config_handler();
|
||||||
|
let pi = peer_info("");
|
||||||
|
|
||||||
|
assert_eq!("secret", handler.should_auto_login(&pi));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Media data.
|
/// Media data.
|
||||||
pub enum MediaData {
|
pub enum MediaData {
|
||||||
VideoQueue,
|
VideoQueue,
|
||||||
|
|||||||
@@ -1426,7 +1426,11 @@ impl<T: InvokeUiSession> Remote<T> {
|
|||||||
self.handler.set_cursor_position(cp);
|
self.handler.set_cursor_position(cp);
|
||||||
}
|
}
|
||||||
Some(message::Union::Clipboard(cb)) => {
|
Some(message::Union::Clipboard(cb)) => {
|
||||||
if !self.handler.lc.read().unwrap().disable_clipboard.v {
|
let clipboard_allowed = {
|
||||||
|
let lc = self.handler.lc.read().unwrap();
|
||||||
|
!lc.disable_clipboard.v && !lc.view_only.v
|
||||||
|
};
|
||||||
|
if clipboard_allowed {
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
update_clipboard(vec![cb], ClipboardSide::Client);
|
update_clipboard(vec![cb], ClipboardSide::Client);
|
||||||
#[cfg(target_os = "ios")]
|
#[cfg(target_os = "ios")]
|
||||||
@@ -1445,7 +1449,11 @@ impl<T: InvokeUiSession> Remote<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(message::Union::MultiClipboards(_mcb)) => {
|
Some(message::Union::MultiClipboards(_mcb)) => {
|
||||||
if !self.handler.lc.read().unwrap().disable_clipboard.v {
|
let clipboard_allowed = {
|
||||||
|
let lc = self.handler.lc.read().unwrap();
|
||||||
|
!lc.disable_clipboard.v && !lc.view_only.v
|
||||||
|
};
|
||||||
|
if clipboard_allowed {
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
update_clipboard(_mcb.clipboards, ClipboardSide::Client);
|
update_clipboard(_mcb.clipboards, ClipboardSide::Client);
|
||||||
#[cfg(target_os = "ios")]
|
#[cfg(target_os = "ios")]
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ pub const PLATFORM_WINDOWS: &str = "Windows";
|
|||||||
pub const PLATFORM_LINUX: &str = "Linux";
|
pub const PLATFORM_LINUX: &str = "Linux";
|
||||||
pub const PLATFORM_MACOS: &str = "Mac OS";
|
pub const PLATFORM_MACOS: &str = "Mac OS";
|
||||||
pub const PLATFORM_ANDROID: &str = "Android";
|
pub const PLATFORM_ANDROID: &str = "Android";
|
||||||
|
pub const PLATFORM_ADDITION_IS_LOGIN_SCREEN: &str = "is_login_screen";
|
||||||
|
|
||||||
pub const TIMER_OUT: Duration = Duration::from_secs(1);
|
pub const TIMER_OUT: Duration = Duration::from_secs(1);
|
||||||
pub const DEFAULT_KEEP_ALIVE: i32 = 60_000;
|
pub const DEFAULT_KEEP_ALIVE: i32 = 60_000;
|
||||||
|
|||||||
@@ -262,11 +262,9 @@ pub fn core_main() -> Option<Vec<String>> {
|
|||||||
if config::is_disable_installation() {
|
if config::is_disable_installation() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
#[cfg(not(windows))]
|
let (printer_override, debug) = parse_silent_install_args(&args);
|
||||||
let options = "desktopicon startmenu";
|
let options = platform::get_silent_install_options(printer_override);
|
||||||
#[cfg(windows)]
|
let res = platform::install_me(options, "".to_owned(), true, debug);
|
||||||
let options = "desktopicon startmenu printer";
|
|
||||||
let res = platform::install_me(options, "".to_owned(), true, args.len() > 1);
|
|
||||||
let text = match res {
|
let text = match res {
|
||||||
Ok(_) => translate("Installation Successful!".to_string()),
|
Ok(_) => translate("Installation Successful!".to_string()),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -933,6 +931,23 @@ fn is_cli_setting_change_disabled() -> bool {
|
|||||||
config::is_disable_settings() && !allow_command_line_settings
|
config::is_disable_settings() && !allow_command_line_settings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn parse_silent_install_args(args: &[String]) -> (Option<bool>, bool) {
|
||||||
|
let mut printer_override = None;
|
||||||
|
let mut debug = false;
|
||||||
|
|
||||||
|
for arg in args.iter().skip(1) {
|
||||||
|
match arg.as_str() {
|
||||||
|
"printer=1" => printer_override = Some(true),
|
||||||
|
"printer=0" => printer_override = Some(false),
|
||||||
|
"debug" => debug = true,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(printer_override, debug)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -326,12 +326,14 @@ pub fn session_toggle_option(session_id: SessionID, value: String) {
|
|||||||
try_sync_peer_option(&session, &session_id, &value, None);
|
try_sync_peer_option(&session, &session_id, &value, None);
|
||||||
}
|
}
|
||||||
#[cfg(not(target_os = "ios"))]
|
#[cfg(not(target_os = "ios"))]
|
||||||
if sessions::get_session_by_session_id(&session_id).is_some() && value == "disable-clipboard" {
|
if sessions::get_session_by_session_id(&session_id).is_some()
|
||||||
|
&& (value == "disable-clipboard" || value == "view-only")
|
||||||
|
{
|
||||||
crate::flutter::update_text_clipboard_required();
|
crate::flutter::update_text_clipboard_required();
|
||||||
}
|
}
|
||||||
#[cfg(feature = "unix-file-copy-paste")]
|
#[cfg(feature = "unix-file-copy-paste")]
|
||||||
if sessions::get_session_by_session_id(&session_id).is_some()
|
if sessions::get_session_by_session_id(&session_id).is_some()
|
||||||
&& value == config::keys::OPTION_ENABLE_FILE_COPY_PASTE
|
&& (value == config::keys::OPTION_ENABLE_FILE_COPY_PASTE || value == "view-only")
|
||||||
{
|
{
|
||||||
crate::flutter::update_file_clipboard_required();
|
crate::flutter::update_file_clipboard_required();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1324,6 +1324,23 @@ pub fn get_install_options() -> String {
|
|||||||
serde_json::to_string(&opts).unwrap_or("{}".to_owned())
|
serde_json::to_string(&opts).unwrap_or("{}".to_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_silent_install_options(printer_override: Option<bool>) -> &'static str {
|
||||||
|
let install_printer = match printer_override {
|
||||||
|
Some(override_value) => override_value,
|
||||||
|
None => {
|
||||||
|
let app_name = crate::get_app_name();
|
||||||
|
let subkey = format!(".{}", app_name.to_lowercase());
|
||||||
|
let printer = get_reg_of_hkcr(&subkey, REG_NAME_INSTALL_PRINTER);
|
||||||
|
printer.as_deref() == Some("1")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if install_printer && is_win_10_or_greater() {
|
||||||
|
"desktopicon startmenu printer"
|
||||||
|
} else {
|
||||||
|
"desktopicon startmenu"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This function return Option<String>, because some registry value may be empty.
|
// This function return Option<String>, because some registry value may be empty.
|
||||||
fn get_reg_of_hkcr(subkey: &str, name: &str) -> Option<String> {
|
fn get_reg_of_hkcr(subkey: &str, name: &str) -> Option<String> {
|
||||||
let hkcr = RegKey::predef(HKEY_CLASSES_ROOT);
|
let hkcr = RegKey::predef(HKEY_CLASSES_ROOT);
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ fn run_rdp(port: u16) {
|
|||||||
if !password.is_empty() {
|
if !password.is_empty() {
|
||||||
args.push(format!("/pass:{}", password));
|
args.push(format!("/pass:{}", password));
|
||||||
}
|
}
|
||||||
println!("{:?}", args);
|
|
||||||
std::process::Command::new("cmdkey")
|
std::process::Command::new("cmdkey")
|
||||||
.args(&args)
|
.args(&args)
|
||||||
.output()
|
.output()
|
||||||
|
|||||||
@@ -1623,6 +1623,10 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
{
|
{
|
||||||
|
platform_additions.insert(
|
||||||
|
crate::common::PLATFORM_ADDITION_IS_LOGIN_SCREEN.into(),
|
||||||
|
json!(crate::platform::is_prelogin() || crate::platform::is_locked()),
|
||||||
|
);
|
||||||
platform_additions.insert(
|
platform_additions.insert(
|
||||||
"supported_privacy_mode_impl".into(),
|
"supported_privacy_mode_impl".into(),
|
||||||
json!(privacy_mode::get_supported_privacy_mode_impl()),
|
json!(privacy_mode::get_supported_privacy_mode_impl()),
|
||||||
@@ -2891,7 +2895,7 @@ impl Connection {
|
|||||||
self.update_auto_disconnect_timer();
|
self.update_auto_disconnect_timer();
|
||||||
}
|
}
|
||||||
Some(message::Union::Clipboard(cb)) => {
|
Some(message::Union::Clipboard(cb)) => {
|
||||||
if self.clipboard {
|
if self.clipboard_enabled() {
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
update_clipboard(vec![cb], ClipboardSide::Host);
|
update_clipboard(vec![cb], ClipboardSide::Host);
|
||||||
// ios as the controlled side is actually not supported for now.
|
// ios as the controlled side is actually not supported for now.
|
||||||
@@ -2919,12 +2923,12 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(message::Union::MultiClipboards(_mcb)) => {
|
Some(message::Union::MultiClipboards(_mcb)) => {
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
if self.clipboard_enabled() {
|
||||||
if self.clipboard {
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
update_clipboard(_mcb.clipboards, ClipboardSide::Host);
|
update_clipboard(_mcb.clipboards, ClipboardSide::Host);
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
crate::clipboard::handle_msg_multi_clipboards(_mcb);
|
||||||
}
|
}
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
crate::clipboard::handle_msg_multi_clipboards(_mcb);
|
|
||||||
}
|
}
|
||||||
#[cfg(any(target_os = "windows", feature = "unix-file-copy-paste"))]
|
#[cfg(any(target_os = "windows", feature = "unix-file-copy-paste"))]
|
||||||
Some(message::Union::Cliprdr(clip)) => {
|
Some(message::Union::Cliprdr(clip)) => {
|
||||||
|
|||||||
@@ -175,13 +175,16 @@ impl SessionPermissionConfig {
|
|||||||
*self.server_clipboard_enabled.read().unwrap()
|
*self.server_clipboard_enabled.read().unwrap()
|
||||||
&& *self.server_keyboard_enabled.read().unwrap()
|
&& *self.server_keyboard_enabled.read().unwrap()
|
||||||
&& !self.lc.read().unwrap().disable_clipboard.v
|
&& !self.lc.read().unwrap().disable_clipboard.v
|
||||||
|
&& !self.lc.read().unwrap().view_only.v
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "unix-file-copy-paste")]
|
#[cfg(feature = "unix-file-copy-paste")]
|
||||||
pub fn is_file_clipboard_required(&self) -> bool {
|
pub fn is_file_clipboard_required(&self) -> bool {
|
||||||
|
let lc = self.lc.read().unwrap();
|
||||||
*self.server_keyboard_enabled.read().unwrap()
|
*self.server_keyboard_enabled.read().unwrap()
|
||||||
&& *self.server_file_transfer_enabled.read().unwrap()
|
&& *self.server_file_transfer_enabled.read().unwrap()
|
||||||
&& self.lc.read().unwrap().enable_file_copy_paste.v
|
&& lc.enable_file_copy_paste.v
|
||||||
|
&& !lc.view_only.v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -411,13 +414,16 @@ impl<T: InvokeUiSession> Session<T> {
|
|||||||
*self.server_clipboard_enabled.read().unwrap()
|
*self.server_clipboard_enabled.read().unwrap()
|
||||||
&& *self.server_keyboard_enabled.read().unwrap()
|
&& *self.server_keyboard_enabled.read().unwrap()
|
||||||
&& !self.lc.read().unwrap().disable_clipboard.v
|
&& !self.lc.read().unwrap().disable_clipboard.v
|
||||||
|
&& !self.lc.read().unwrap().view_only.v
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "windows", feature = "unix-file-copy-paste"))]
|
#[cfg(any(target_os = "windows", feature = "unix-file-copy-paste"))]
|
||||||
pub fn is_file_clipboard_required(&self) -> bool {
|
pub fn is_file_clipboard_required(&self) -> bool {
|
||||||
|
let lc = self.lc.read().unwrap();
|
||||||
*self.server_keyboard_enabled.read().unwrap()
|
*self.server_keyboard_enabled.read().unwrap()
|
||||||
&& *self.server_file_transfer_enabled.read().unwrap()
|
&& *self.server_file_transfer_enabled.read().unwrap()
|
||||||
&& self.lc.read().unwrap().enable_file_copy_paste.v
|
&& lc.enable_file_copy_paste.v
|
||||||
|
&& !lc.view_only.v
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "flutter")]
|
#[cfg(feature = "flutter")]
|
||||||
@@ -1800,7 +1806,7 @@ impl<T: InvokeUiSession> Interface for Session<T> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.try_change_init_resolution(pi.current_display);
|
self.try_change_init_resolution(pi.current_display);
|
||||||
let p = self.lc.read().unwrap().should_auto_login();
|
let p = self.lc.read().unwrap().should_auto_login(&pi);
|
||||||
if !p.is_empty() {
|
if !p.is_empty() {
|
||||||
input_os_password(p, true, self.clone());
|
input_os_password(p, true, self.clone());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user