mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-04-29 09:53:19 +03:00
Compare commits
4 Commits
copilot/fi
...
743705545a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
743705545a | ||
|
|
89a34642a3 | ||
|
|
d9e2107fb8 | ||
|
|
890282e385 |
2
.github/workflows/flutter-build.yml
vendored
2
.github/workflows/flutter-build.yml
vendored
@@ -40,7 +40,7 @@ env:
|
|||||||
VCPKG_COMMIT_ID: "120deac3062162151622ca4860575a33844ba10b"
|
VCPKG_COMMIT_ID: "120deac3062162151622ca4860575a33844ba10b"
|
||||||
ARMV7_VCPKG_COMMIT_ID: "6f29f12e82a8293156836ad81cc9bf5af41fe836" # 2025.01.13, got "/opt/artifacts/vcpkg/vcpkg: No such file or directory" with latest version
|
ARMV7_VCPKG_COMMIT_ID: "6f29f12e82a8293156836ad81cc9bf5af41fe836" # 2025.01.13, got "/opt/artifacts/vcpkg/vcpkg: No such file or directory" with latest version
|
||||||
VERSION: "1.4.6"
|
VERSION: "1.4.6"
|
||||||
NDK_VERSION: "r28c"
|
NDK_VERSION: "r27c"
|
||||||
#signing keys env variable checks
|
#signing keys env variable checks
|
||||||
ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}"
|
ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}"
|
||||||
MACOS_P12_BASE64: "${{ secrets.MACOS_P12_BASE64 }}"
|
MACOS_P12_BASE64: "${{ secrets.MACOS_P12_BASE64 }}"
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ target/release/rustdesk
|
|||||||
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: графический пользовательский интерфейс на Sciter (устаревшее)
|
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: графический пользовательский интерфейс на Sciter (устаревшее)
|
||||||
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: сервисы аудио, буфера обмена, ввода, видео и сетевых подключений
|
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: сервисы аудио, буфера обмена, ввода, видео и сетевых подключений
|
||||||
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: одноранговое соединение
|
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: одноранговое соединение
|
||||||
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: связь с [сервером RustDesk](https://github.com/rustdesk/rustdesk-server), ожидает удаленного прямого (через TCP hole punching) или ретранслируемого соединения
|
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: связь с [сервером Rustdesk](https://github.com/rustdesk/rustdesk-server), ожидает удаленного прямого (через TCP hole punching) или ретранслируемого соединения
|
||||||
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: специфичный для платформы код
|
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: специфичный для платформы код
|
||||||
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: код Flutter для ПК-версии и мобильных устройств
|
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: код Flutter для ПК-версии и мобильных устройств
|
||||||
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/v1/js)**: JavaScript для Web-клиента Flutter
|
- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/v1/js)**: JavaScript для Web-клиента Flutter
|
||||||
|
|||||||
@@ -2039,7 +2039,7 @@ class _AccountState extends State<_Account> {
|
|||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
if (avatarWidget != null) avatarWidget,
|
if (avatarWidget != null) avatarWidget,
|
||||||
const SizedBox(width: 12),
|
if (avatarWidget != null) const SizedBox(width: 12),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
|||||||
@@ -569,12 +569,11 @@ class _CmHeaderState extends State<_CmHeader>
|
|||||||
|
|
||||||
Widget _buildClientAvatar() {
|
Widget _buildClientAvatar() {
|
||||||
return buildAvatarWidget(
|
return buildAvatarWidget(
|
||||||
avatar: client.avatar,
|
avatar: client.avatar,
|
||||||
size: 70,
|
size: 70,
|
||||||
borderRadius: 15,
|
borderRadius: 15,
|
||||||
fallback: _buildInitialAvatar(),
|
fallback: _buildInitialAvatar(),
|
||||||
) ??
|
)!;
|
||||||
_buildInitialAvatar();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildInitialAvatar() {
|
Widget _buildInitialAvatar() {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:ui' as ui;
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
@@ -64,7 +65,9 @@ class _RemotePageState extends State<RemotePage> with WidgetsBindingObserver {
|
|||||||
bool _showGestureHelp = false;
|
bool _showGestureHelp = false;
|
||||||
String _value = '';
|
String _value = '';
|
||||||
Orientation? _currentOrientation;
|
Orientation? _currentOrientation;
|
||||||
|
double _viewInsetsBottom = 0;
|
||||||
final _uniqueKey = UniqueKey();
|
final _uniqueKey = UniqueKey();
|
||||||
|
Timer? _timerDidChangeMetrics;
|
||||||
Timer? _iosKeyboardWorkaroundTimer;
|
Timer? _iosKeyboardWorkaroundTimer;
|
||||||
|
|
||||||
final _blockableOverlayState = BlockableOverlayState();
|
final _blockableOverlayState = BlockableOverlayState();
|
||||||
@@ -137,6 +140,7 @@ class _RemotePageState extends State<RemotePage> with WidgetsBindingObserver {
|
|||||||
_physicalFocusNode.dispose();
|
_physicalFocusNode.dispose();
|
||||||
await gFFI.close();
|
await gFFI.close();
|
||||||
_timer?.cancel();
|
_timer?.cancel();
|
||||||
|
_timerDidChangeMetrics?.cancel();
|
||||||
_iosKeyboardWorkaroundTimer?.cancel();
|
_iosKeyboardWorkaroundTimer?.cancel();
|
||||||
gFFI.dialogManager.dismissAll();
|
gFFI.dialogManager.dismissAll();
|
||||||
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
|
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
|
||||||
@@ -163,6 +167,26 @@ class _RemotePageState extends State<RemotePage> with WidgetsBindingObserver {
|
|||||||
gFFI.invokeMethod("try_sync_clipboard");
|
gFFI.invokeMethod("try_sync_clipboard");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeMetrics() {
|
||||||
|
// If the soft keyboard is visible and the canvas has been changed(panned or scaled)
|
||||||
|
// Don't try reset the view style and focus the cursor.
|
||||||
|
if (gFFI.cursorModel.lastKeyboardIsVisible &&
|
||||||
|
gFFI.canvasModel.isMobileCanvasChanged) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final newBottom = MediaQueryData.fromView(ui.window).viewInsets.bottom;
|
||||||
|
_timerDidChangeMetrics?.cancel();
|
||||||
|
_timerDidChangeMetrics = Timer(Duration(milliseconds: 100), () async {
|
||||||
|
// We need this comparation because poping up the floating action will also trigger `didChangeMetrics()`.
|
||||||
|
if (newBottom != _viewInsetsBottom) {
|
||||||
|
gFFI.canvasModel.mobileFocusCanvasCursor();
|
||||||
|
_viewInsetsBottom = newBottom;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// to-do: It should be better to use transparent color instead of the bgColor.
|
// to-do: It should be better to use transparent color instead of the bgColor.
|
||||||
// But for now, the transparent color will cause the canvas to be white.
|
// But for now, the transparent color will cause the canvas to be white.
|
||||||
// I'm sure that the white color is caused by the Overlay widget in BlockableOverlay.
|
// I'm sure that the white color is caused by the Overlay widget in BlockableOverlay.
|
||||||
|
|||||||
@@ -857,16 +857,16 @@ class ClientInfo extends StatelessWidget {
|
|||||||
|
|
||||||
Widget _buildAvatar(BuildContext context) {
|
Widget _buildAvatar(BuildContext context) {
|
||||||
final fallback = CircleAvatar(
|
final fallback = CircleAvatar(
|
||||||
backgroundColor: str2color(client.name,
|
backgroundColor: str2color(
|
||||||
|
client.name,
|
||||||
Theme.of(context).brightness == Brightness.light ? 255 : 150),
|
Theme.of(context).brightness == Brightness.light ? 255 : 150),
|
||||||
child: Text(client.name.isNotEmpty ? client.name[0] : '?'),
|
child: Text(client.name.isNotEmpty ? client.name[0] : '?'),
|
||||||
);
|
);
|
||||||
return buildAvatarWidget(
|
return buildAvatarWidget(
|
||||||
avatar: client.avatar,
|
avatar: client.avatar,
|
||||||
size: 40,
|
size: 40,
|
||||||
fallback: fallback,
|
fallback: fallback,
|
||||||
) ??
|
)!;
|
||||||
fallback;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -617,7 +617,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
|||||||
onToggle: (bool v) async {
|
onToggle: (bool v) async {
|
||||||
await mainSetLocalBoolOption(kOptionEnableShowTerminalExtraKeys, v);
|
await mainSetLocalBoolOption(kOptionEnableShowTerminalExtraKeys, v);
|
||||||
final newValue =
|
final newValue =
|
||||||
mainGetLocalBoolOptionSync(kOptionEnableShowTerminalExtraKeys);
|
mainGetLocalBoolOptionSync(kOptionEnableShowTerminalExtraKeys);
|
||||||
setState(() {
|
setState(() {
|
||||||
_showTerminalExtraKeys = newValue;
|
_showTerminalExtraKeys = newValue;
|
||||||
});
|
});
|
||||||
@@ -694,9 +694,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
|||||||
avatar: gFFI.userModel.avatar.value);
|
avatar: gFFI.userModel.avatar.value);
|
||||||
return buildAvatarWidget(
|
return buildAvatarWidget(
|
||||||
avatar: avatar,
|
avatar: avatar,
|
||||||
size: 28,
|
size: 40,
|
||||||
borderRadius: null,
|
|
||||||
fallback: Icon(Icons.person),
|
|
||||||
) ??
|
) ??
|
||||||
Icon(Icons.person);
|
Icon(Icons.person);
|
||||||
}),
|
}),
|
||||||
@@ -839,12 +837,10 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
|||||||
),
|
),
|
||||||
if (!incomingOnly)
|
if (!incomingOnly)
|
||||||
SettingsTile.switchTile(
|
SettingsTile.switchTile(
|
||||||
title:
|
title: Text(translate('keep-awake-during-outgoing-sessions-label')),
|
||||||
Text(translate('keep-awake-during-outgoing-sessions-label')),
|
|
||||||
initialValue: _preventSleepWhileConnected,
|
initialValue: _preventSleepWhileConnected,
|
||||||
onToggle: (v) async {
|
onToggle: (v) async {
|
||||||
await mainSetLocalBoolOption(
|
await mainSetLocalBoolOption(kOptionKeepAwakeDuringOutgoingSessions, v);
|
||||||
kOptionKeepAwakeDuringOutgoingSessions, v);
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_preventSleepWhileConnected = v;
|
_preventSleepWhileConnected = v;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -348,12 +348,6 @@ class InputModel {
|
|||||||
final _trackpadAdjustPeerLinux = 0.06;
|
final _trackpadAdjustPeerLinux = 0.06;
|
||||||
// This is an experience value.
|
// This is an experience value.
|
||||||
final _trackpadAdjustMacToWin = 2.50;
|
final _trackpadAdjustMacToWin = 2.50;
|
||||||
// Ignore directional locking for very small deltas on both axes (including
|
|
||||||
// tiny single-axis movement) to avoid over-filtering near zero.
|
|
||||||
static const double _trackpadAxisNoiseThreshold = 0.2;
|
|
||||||
// Lock to dominant axis only when one axis is clearly stronger.
|
|
||||||
// 1.6 means the dominant axis must be >= 60% larger than the other.
|
|
||||||
static const double _trackpadAxisLockRatio = 1.6;
|
|
||||||
int _trackpadSpeed = kDefaultTrackpadSpeed;
|
int _trackpadSpeed = kDefaultTrackpadSpeed;
|
||||||
double _trackpadSpeedInner = kDefaultTrackpadSpeed / 100.0;
|
double _trackpadSpeedInner = kDefaultTrackpadSpeed / 100.0;
|
||||||
var _trackpadScrollUnsent = Offset.zero;
|
var _trackpadScrollUnsent = Offset.zero;
|
||||||
@@ -1178,7 +1172,6 @@ class InputModel {
|
|||||||
if (isMacOS && peerPlatform == kPeerPlatformWindows) {
|
if (isMacOS && peerPlatform == kPeerPlatformWindows) {
|
||||||
delta *= _trackpadAdjustMacToWin;
|
delta *= _trackpadAdjustMacToWin;
|
||||||
}
|
}
|
||||||
delta = _filterTrackpadDeltaAxis(delta);
|
|
||||||
_trackpadLastDelta = delta;
|
_trackpadLastDelta = delta;
|
||||||
|
|
||||||
var x = delta.dx.toInt();
|
var x = delta.dx.toInt();
|
||||||
@@ -1211,24 +1204,6 @@ class InputModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Offset _filterTrackpadDeltaAxis(Offset delta) {
|
|
||||||
final absDx = delta.dx.abs();
|
|
||||||
final absDy = delta.dy.abs();
|
|
||||||
// Keep diagonal intent when movement is tiny on both axes.
|
|
||||||
if (absDx < _trackpadAxisNoiseThreshold &&
|
|
||||||
absDy < _trackpadAxisNoiseThreshold) {
|
|
||||||
return delta;
|
|
||||||
}
|
|
||||||
// Dominant-axis lock to reduce accidental cross-axis scrolling noise.
|
|
||||||
if (absDy >= absDx * _trackpadAxisLockRatio) {
|
|
||||||
return Offset(0, delta.dy);
|
|
||||||
}
|
|
||||||
if (absDx >= absDy * _trackpadAxisLockRatio) {
|
|
||||||
return Offset(delta.dx, 0);
|
|
||||||
}
|
|
||||||
return delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _scheduleFling(double x, double y, int delay) {
|
void _scheduleFling(double x, double y, int delay) {
|
||||||
if (isViewCamera) return;
|
if (isViewCamera) return;
|
||||||
if ((x == 0 && y == 0) || _stopFling) {
|
if ((x == 0 && y == 0) || _stopFling) {
|
||||||
|
|||||||
@@ -1016,31 +1016,19 @@ class FfiModel with ChangeNotifier {
|
|||||||
showMsgBox(SessionID sessionId, String type, String title, String text,
|
showMsgBox(SessionID sessionId, String type, String title, String text,
|
||||||
String link, bool hasRetry, OverlayDialogManager dialogManager,
|
String link, bool hasRetry, OverlayDialogManager dialogManager,
|
||||||
{bool? hasCancel}) async {
|
{bool? hasCancel}) async {
|
||||||
final noteAllowed = parent.target != null &&
|
final showNoteEdit = parent.target != null &&
|
||||||
allowAskForNoteAtEndOfConnection(parent.target, false) &&
|
allowAskForNoteAtEndOfConnection(parent.target, false) &&
|
||||||
(title == "Connection Error" || type == "restarting");
|
(title == "Connection Error" || type == "restarting") &&
|
||||||
final showNoteEdit = noteAllowed && !hasRetry;
|
!hasRetry;
|
||||||
if (showNoteEdit) {
|
if (showNoteEdit) {
|
||||||
await showConnEndAuditDialogCloseCanceled(
|
await showConnEndAuditDialogCloseCanceled(
|
||||||
ffi: parent.target!, type: type, title: title, text: text);
|
ffi: parent.target!, type: type, title: title, text: text);
|
||||||
closeConnection();
|
closeConnection();
|
||||||
} else {
|
} else {
|
||||||
VoidCallback? onSubmit;
|
|
||||||
if (noteAllowed && hasRetry) {
|
|
||||||
final ffi = parent.target!;
|
|
||||||
onSubmit = () async {
|
|
||||||
_timer?.cancel();
|
|
||||||
_timer = null;
|
|
||||||
await showConnEndAuditDialogCloseCanceled(
|
|
||||||
ffi: ffi, type: type, title: title, text: text);
|
|
||||||
closeConnection();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
msgBox(sessionId, type, title, text, link, dialogManager,
|
msgBox(sessionId, type, title, text, link, dialogManager,
|
||||||
hasCancel: hasCancel,
|
hasCancel: hasCancel,
|
||||||
reconnect: hasRetry ? reconnect : null,
|
reconnect: hasRetry ? reconnect : null,
|
||||||
reconnectTimeout: hasRetry ? _reconnects : null,
|
reconnectTimeout: hasRetry ? _reconnects : null);
|
||||||
onSubmit: onSubmit);
|
|
||||||
}
|
}
|
||||||
_timer?.cancel();
|
_timer?.cancel();
|
||||||
if (hasRetry) {
|
if (hasRetry) {
|
||||||
@@ -2164,9 +2152,6 @@ class CanvasModel with ChangeNotifier {
|
|||||||
ViewStyle _lastViewStyle = ViewStyle.defaultViewStyle();
|
ViewStyle _lastViewStyle = ViewStyle.defaultViewStyle();
|
||||||
|
|
||||||
Timer? _timerMobileFocusCanvasCursor;
|
Timer? _timerMobileFocusCanvasCursor;
|
||||||
Timer? _timerMobileRestoreCanvasOffset;
|
|
||||||
Offset? _offsetBeforeMobileSoftKeyboard;
|
|
||||||
double? _scaleBeforeMobileSoftKeyboard;
|
|
||||||
|
|
||||||
// `isMobileCanvasChanged` is used to avoid canvas reset when changing the input method
|
// `isMobileCanvasChanged` is used to avoid canvas reset when changing the input method
|
||||||
// after showing the soft keyboard.
|
// after showing the soft keyboard.
|
||||||
@@ -2654,9 +2639,6 @@ class CanvasModel with ChangeNotifier {
|
|||||||
_scale = 1.0;
|
_scale = 1.0;
|
||||||
_lastViewStyle = ViewStyle.defaultViewStyle();
|
_lastViewStyle = ViewStyle.defaultViewStyle();
|
||||||
_timerMobileFocusCanvasCursor?.cancel();
|
_timerMobileFocusCanvasCursor?.cancel();
|
||||||
_timerMobileRestoreCanvasOffset?.cancel();
|
|
||||||
_offsetBeforeMobileSoftKeyboard = null;
|
|
||||||
_scaleBeforeMobileSoftKeyboard = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateScrollPercent() {
|
updateScrollPercent() {
|
||||||
@@ -2685,31 +2667,6 @@ class CanvasModel with ChangeNotifier {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveMobileOffsetBeforeSoftKeyboard() {
|
|
||||||
_timerMobileRestoreCanvasOffset?.cancel();
|
|
||||||
_offsetBeforeMobileSoftKeyboard = Offset(_x, _y);
|
|
||||||
_scaleBeforeMobileSoftKeyboard = _scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
void restoreMobileOffsetAfterSoftKeyboard() {
|
|
||||||
_timerMobileRestoreCanvasOffset?.cancel();
|
|
||||||
_timerMobileFocusCanvasCursor?.cancel();
|
|
||||||
final targetOffset = _offsetBeforeMobileSoftKeyboard;
|
|
||||||
final targetScale = _scaleBeforeMobileSoftKeyboard;
|
|
||||||
if (targetOffset == null || targetScale == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_timerMobileRestoreCanvasOffset = Timer(Duration(milliseconds: 100), () {
|
|
||||||
updateSize();
|
|
||||||
_x = targetOffset.dx;
|
|
||||||
_y = targetOffset.dy;
|
|
||||||
_scale = targetScale;
|
|
||||||
_offsetBeforeMobileSoftKeyboard = null;
|
|
||||||
_scaleBeforeMobileSoftKeyboard = null;
|
|
||||||
notifyListeners();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// mobile only
|
// mobile only
|
||||||
// Move the canvas to make the cursor visible(center) on the screen.
|
// Move the canvas to make the cursor visible(center) on the screen.
|
||||||
void _moveToCenterCursor() {
|
void _moveToCenterCursor() {
|
||||||
@@ -2962,13 +2919,8 @@ class CursorModel with ChangeNotifier {
|
|||||||
_lastIsBlocked = true;
|
_lastIsBlocked = true;
|
||||||
}
|
}
|
||||||
if (isMobile && _lastKeyboardIsVisible != keyboardIsVisible) {
|
if (isMobile && _lastKeyboardIsVisible != keyboardIsVisible) {
|
||||||
if (keyboardIsVisible) {
|
parent.target?.canvasModel.mobileFocusCanvasCursor();
|
||||||
parent.target?.canvasModel.saveMobileOffsetBeforeSoftKeyboard();
|
parent.target?.canvasModel.isMobileCanvasChanged = false;
|
||||||
parent.target?.canvasModel.mobileFocusCanvasCursor();
|
|
||||||
parent.target?.canvasModel.isMobileCanvasChanged = false;
|
|
||||||
} else {
|
|
||||||
parent.target?.canvasModel.restoreMobileOffsetAfterSoftKeyboard();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_lastKeyboardIsVisible = keyboardIsVisible;
|
_lastKeyboardIsVisible = keyboardIsVisible;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -269,7 +269,7 @@ impl KeyboardControllable for Enigo {
|
|||||||
for pos in 0..mod_len {
|
for pos in 0..mod_len {
|
||||||
let rpos = mod_len - 1 - pos;
|
let rpos = mod_len - 1 - pos;
|
||||||
if flag & (0x0001 << rpos) != 0 {
|
if flag & (0x0001 << rpos) != 0 {
|
||||||
self.key_up(modifiers[rpos]);
|
self.key_up(modifiers[pos]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,18 +298,7 @@ impl KeyboardControllable for Enigo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn key_up(&mut self, key: Key) {
|
fn key_up(&mut self, key: Key) {
|
||||||
match key {
|
keybd_event(KEYEVENTF_KEYUP, self.key_to_keycode(key), 0);
|
||||||
Key::Layout(c) => {
|
|
||||||
let code = self.get_layoutdependent_keycode(c);
|
|
||||||
if code as u16 != 0xFFFF {
|
|
||||||
let vk = code & 0x00FF;
|
|
||||||
keybd_event(KEYEVENTF_KEYUP, vk, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
keybd_event(KEYEVENTF_KEYUP, self.key_to_keycode(key), 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_key_state(&mut self, key: Key) -> bool {
|
fn get_key_state(&mut self, key: Key) -> bool {
|
||||||
|
|||||||
@@ -286,14 +286,10 @@ fn heartbeat_url() -> String {
|
|||||||
|
|
||||||
fn handle_config_options(config_options: HashMap<String, String>) {
|
fn handle_config_options(config_options: HashMap<String, String>) {
|
||||||
let mut options = Config::get_options();
|
let mut options = Config::get_options();
|
||||||
let default_settings = config::DEFAULT_SETTINGS.read().unwrap().clone();
|
|
||||||
config_options
|
config_options
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(k, v)| {
|
.map(|(k, v)| {
|
||||||
// Priority: user config > default advanced options.
|
if v.is_empty() {
|
||||||
// Only when default advanced options are also empty, remove user option (fallback to built-in default);
|
|
||||||
// otherwise insert an empty value so user config remains present.
|
|
||||||
if v.is_empty() && default_settings.get(k).map_or("", |v| v).is_empty() {
|
|
||||||
options.remove(k);
|
options.remove(k);
|
||||||
} else {
|
} else {
|
||||||
options.insert(k.to_string(), v.to_string());
|
options.insert(k.to_string(), v.to_string());
|
||||||
|
|||||||
@@ -738,7 +738,5 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Changelog", "Változáslista"),
|
("Changelog", "Változáslista"),
|
||||||
("keep-awake-during-outgoing-sessions-label", "Képernyő aktív állapotban tartása a kimenő munkamenetek során"),
|
("keep-awake-during-outgoing-sessions-label", "Képernyő aktív állapotban tartása a kimenő munkamenetek során"),
|
||||||
("keep-awake-during-incoming-sessions-label", "Képernyő aktív állapotban tartása a bejövő munkamenetek során"),
|
("keep-awake-during-incoming-sessions-label", "Képernyő aktív állapotban tartása a bejövő munkamenetek során"),
|
||||||
("Continue with {}", "Folytatás ezzel: {}"),
|
|
||||||
("Display Name", "Kijelző név"),
|
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -859,10 +859,9 @@ on run {app_name, cur_pid, app_dir, user_name}
|
|||||||
set app_dir_q to quoted form of app_dir
|
set app_dir_q to quoted form of app_dir
|
||||||
set user_name_q to quoted form of user_name
|
set user_name_q to quoted form of user_name
|
||||||
|
|
||||||
set check_source to "test -d " & app_dir_q & " || exit 1;"
|
|
||||||
set kill_others to "pids=$(pgrep -x '" & app_name & "' | grep -vx " & cur_pid & " || true); if [ -n \"$pids\" ]; then echo \"$pids\" | xargs kill -9 || true; fi;"
|
set kill_others to "pids=$(pgrep -x '" & app_name & "' | grep -vx " & cur_pid & " || true); if [ -n \"$pids\" ]; then echo \"$pids\" | xargs kill -9 || true; fi;"
|
||||||
set copy_files to "rm -rf " & app_bundle_q & " && ditto " & app_dir_q & " " & app_bundle_q & " && chown -R " & user_name_q & ":staff " & app_bundle_q & " && (xattr -r -d com.apple.quarantine " & app_bundle_q & " || true);"
|
set copy_files to "rm -rf " & app_bundle_q & " && ditto " & app_dir_q & " " & app_bundle_q & " && chown -R " & user_name_q & ":staff " & app_bundle_q & " && (xattr -r -d com.apple.quarantine " & app_bundle_q & " || true);"
|
||||||
set sh to "set -e;" & check_source & kill_others & copy_files
|
set sh to "set -e;" & kill_others & copy_files
|
||||||
|
|
||||||
do shell script sh with prompt app_name & " wants to update itself" with administrator privileges
|
do shell script sh with prompt app_name & " wants to update itself" with administrator privileges
|
||||||
end run
|
end run
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ on run {daemon_file, agent_file, user, cur_pid, source_dir}
|
|||||||
set daemon_plist to "/Library/LaunchDaemons/com.carriez.RustDesk_service.plist"
|
set daemon_plist to "/Library/LaunchDaemons/com.carriez.RustDesk_service.plist"
|
||||||
set app_bundle to "/Applications/RustDesk.app"
|
set app_bundle to "/Applications/RustDesk.app"
|
||||||
|
|
||||||
set check_source to "test -d " & quoted form of source_dir & " || exit 1;"
|
|
||||||
set resolve_uid to "uid=$(id -u " & quoted form of user & " 2>/dev/null || true);"
|
set resolve_uid to "uid=$(id -u " & quoted form of user & " 2>/dev/null || true);"
|
||||||
set unload_agent to "if [ -n \"$uid\" ]; then launchctl bootout gui/$uid " & quoted form of agent_plist & " 2>/dev/null || launchctl bootout user/$uid " & quoted form of agent_plist & " 2>/dev/null || launchctl unload -w " & quoted form of agent_plist & " || true; else launchctl unload -w " & quoted form of agent_plist & " || true; fi;"
|
set unload_agent to "if [ -n \"$uid\" ]; then launchctl bootout gui/$uid " & quoted form of agent_plist & " 2>/dev/null || launchctl bootout user/$uid " & quoted form of agent_plist & " 2>/dev/null || launchctl unload -w " & quoted form of agent_plist & " || true; else launchctl unload -w " & quoted form of agent_plist & " || true; fi;"
|
||||||
set unload_service to "launchctl unload -w " & daemon_plist & " || true;"
|
set unload_service to "launchctl unload -w " & daemon_plist & " || true;"
|
||||||
@@ -20,7 +19,7 @@ on run {daemon_file, agent_file, user, cur_pid, source_dir}
|
|||||||
set kickstart_agent to "if [ -n \"$uid\" ]; then launchctl kickstart -k gui/$uid/$agent_label 2>/dev/null || launchctl kickstart -k user/$uid/$agent_label 2>/dev/null || true; fi;"
|
set kickstart_agent to "if [ -n \"$uid\" ]; then launchctl kickstart -k gui/$uid/$agent_label 2>/dev/null || launchctl kickstart -k user/$uid/$agent_label 2>/dev/null || true; fi;"
|
||||||
set load_agent to agent_label_cmd & bootstrap_agent & kickstart_agent
|
set load_agent to agent_label_cmd & bootstrap_agent & kickstart_agent
|
||||||
|
|
||||||
set sh to "set -e;" & check_source & resolve_uid & unload_agent & unload_service & kill_others & copy_files & write_daemon_plist & write_agent_plist & load_service & load_agent
|
set sh to "set -e;" & resolve_uid & unload_agent & unload_service & kill_others & copy_files & write_daemon_plist & write_agent_plist & load_service & load_agent
|
||||||
|
|
||||||
do shell script sh with prompt "RustDesk wants to update itself" with administrator privileges
|
do shell script sh with prompt "RustDesk wants to update itself" with administrator privileges
|
||||||
end run
|
end run
|
||||||
|
|||||||
@@ -560,9 +560,7 @@ impl Connection {
|
|||||||
match data {
|
match data {
|
||||||
ipc::Data::Authorize => {
|
ipc::Data::Authorize => {
|
||||||
conn.require_2fa.take();
|
conn.require_2fa.take();
|
||||||
if !conn.send_logon_response_and_keep_alive().await {
|
conn.send_logon_response().await;
|
||||||
break;
|
|
||||||
}
|
|
||||||
if conn.port_forward_socket.is_some() {
|
if conn.port_forward_socket.is_some() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1340,66 +1338,9 @@ impl Connection {
|
|||||||
crate::post_request(url, v.to_string(), "").await
|
crate::post_request(url, v.to_string(), "").await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn normalize_port_forward_target(pf: &mut PortForward) -> (String, bool) {
|
async fn send_logon_response(&mut self) {
|
||||||
let mut is_rdp = false;
|
|
||||||
if pf.host == "RDP" && pf.port == 0 {
|
|
||||||
pf.host = "localhost".to_owned();
|
|
||||||
pf.port = 3389;
|
|
||||||
is_rdp = true;
|
|
||||||
}
|
|
||||||
if pf.host.is_empty() {
|
|
||||||
pf.host = "localhost".to_owned();
|
|
||||||
}
|
|
||||||
(format!("{}:{}", pf.host, pf.port), is_rdp)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn connect_port_forward_if_needed(&mut self) -> bool {
|
|
||||||
if self.port_forward_socket.is_some() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
let Some(login_request::Union::PortForward(pf)) = self.lr.union.as_ref() else {
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
let mut pf = pf.clone();
|
|
||||||
let (mut addr, is_rdp) = Self::normalize_port_forward_target(&mut pf);
|
|
||||||
self.port_forward_address = addr.clone();
|
|
||||||
match timeout(3000, TcpStream::connect(&addr)).await {
|
|
||||||
Ok(Ok(sock)) => {
|
|
||||||
self.port_forward_socket = Some(Framed::new(sock, BytesCodec::new()));
|
|
||||||
true
|
|
||||||
}
|
|
||||||
Ok(Err(e)) => {
|
|
||||||
log::warn!("Port forward connect failed for {}: {}", addr, e);
|
|
||||||
if is_rdp {
|
|
||||||
addr = "RDP".to_owned();
|
|
||||||
}
|
|
||||||
self.send_login_error(format!(
|
|
||||||
"Failed to access remote {}. Please make sure it is reachable/open.",
|
|
||||||
addr
|
|
||||||
))
|
|
||||||
.await;
|
|
||||||
false
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
log::warn!("Port forward connect timed out for {}: {}", addr, e);
|
|
||||||
if is_rdp {
|
|
||||||
addr = "RDP".to_owned();
|
|
||||||
}
|
|
||||||
self.send_login_error(format!(
|
|
||||||
"Failed to access remote {}. Please make sure it is reachable/open.",
|
|
||||||
addr
|
|
||||||
))
|
|
||||||
.await;
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns whether this connection should be kept alive.
|
|
||||||
// `true` does not necessarily mean authorization succeeded (e.g. REQUIRE_2FA case).
|
|
||||||
async fn send_logon_response_and_keep_alive(&mut self) -> bool {
|
|
||||||
if self.authorized {
|
if self.authorized {
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
if self.require_2fa.is_some() && !self.is_recent_session(true) && !self.from_switch {
|
if self.require_2fa.is_some() && !self.is_recent_session(true) && !self.from_switch {
|
||||||
self.require_2fa.as_ref().map(|totp| {
|
self.require_2fa.as_ref().map(|totp| {
|
||||||
@@ -1430,11 +1371,7 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
self.send_login_error(crate::client::REQUIRE_2FA).await;
|
self.send_login_error(crate::client::REQUIRE_2FA).await;
|
||||||
// Keep the connection alive so the client can continue with 2FA.
|
return;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if !self.connect_port_forward_if_needed().await {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
self.authorized = true;
|
self.authorized = true;
|
||||||
let (conn_type, auth_conn_type) = if self.file_transfer.is_some() {
|
let (conn_type, auth_conn_type) = if self.file_transfer.is_some() {
|
||||||
@@ -1557,7 +1494,7 @@ impl Connection {
|
|||||||
res.set_peer_info(pi);
|
res.set_peer_info(pi);
|
||||||
msg_out.set_login_response(res);
|
msg_out.set_login_response(res);
|
||||||
self.send(msg_out).await;
|
self.send(msg_out).await;
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
if self.is_remote() {
|
if self.is_remote() {
|
||||||
@@ -1580,7 +1517,7 @@ impl Connection {
|
|||||||
let mut msg_out = Message::new();
|
let mut msg_out = Message::new();
|
||||||
msg_out.set_login_response(res);
|
msg_out.set_login_response(res);
|
||||||
self.send(msg_out).await;
|
self.send(msg_out).await;
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
@@ -1734,7 +1671,6 @@ impl Connection {
|
|||||||
self.try_sub_monitor_services();
|
self.try_sub_monitor_services();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_sub_camera_displays(&mut self) {
|
fn try_sub_camera_displays(&mut self) {
|
||||||
@@ -2243,8 +2179,33 @@ impl Connection {
|
|||||||
sleep(1.).await;
|
sleep(1.).await;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let (addr, _is_rdp) = Self::normalize_port_forward_target(&mut pf);
|
let mut is_rdp = false;
|
||||||
self.port_forward_address = addr;
|
if pf.host == "RDP" && pf.port == 0 {
|
||||||
|
pf.host = "localhost".to_owned();
|
||||||
|
pf.port = 3389;
|
||||||
|
is_rdp = true;
|
||||||
|
}
|
||||||
|
if pf.host.is_empty() {
|
||||||
|
pf.host = "localhost".to_owned();
|
||||||
|
}
|
||||||
|
let mut addr = format!("{}:{}", pf.host, pf.port);
|
||||||
|
self.port_forward_address = addr.clone();
|
||||||
|
match timeout(3000, TcpStream::connect(&addr)).await {
|
||||||
|
Ok(Ok(sock)) => {
|
||||||
|
self.port_forward_socket = Some(Framed::new(sock, BytesCodec::new()));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if is_rdp {
|
||||||
|
addr = "RDP".to_owned();
|
||||||
|
}
|
||||||
|
self.send_login_error(format!(
|
||||||
|
"Failed to access remote {}, please make sure if it is open",
|
||||||
|
addr
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if !self.check_privacy_mode_on().await {
|
if !self.check_privacy_mode_on().await {
|
||||||
@@ -2275,7 +2236,9 @@ impl Connection {
|
|||||||
// `is_logon_ui()` is a fallback for logon UI detection on Windows.
|
// `is_logon_ui()` is a fallback for logon UI detection on Windows.
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
let is_logon = || {
|
let is_logon = || {
|
||||||
crate::platform::is_prelogin() || crate::platform::is_locked() || {
|
crate::platform::is_prelogin()
|
||||||
|
|| crate::platform::is_locked()
|
||||||
|
|| {
|
||||||
match crate::platform::is_logon_ui() {
|
match crate::platform::is_logon_ui() {
|
||||||
Ok(result) => result,
|
Ok(result) => result,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -2314,9 +2277,7 @@ impl Connection {
|
|||||||
if err_msg.is_empty() {
|
if err_msg.is_empty() {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
self.linux_headless_handle.wait_desktop_cm_ready().await;
|
self.linux_headless_handle.wait_desktop_cm_ready().await;
|
||||||
if !self.send_logon_response_and_keep_alive().await {
|
self.send_logon_response().await;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
self.try_start_cm(lr.my_id.clone(), lr.my_name.clone(), self.authorized);
|
self.try_start_cm(lr.my_id.clone(), lr.my_name.clone(), self.authorized);
|
||||||
} else {
|
} else {
|
||||||
self.send_login_error(err_msg).await;
|
self.send_login_error(err_msg).await;
|
||||||
@@ -2352,9 +2313,7 @@ impl Connection {
|
|||||||
if err_msg.is_empty() {
|
if err_msg.is_empty() {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
self.linux_headless_handle.wait_desktop_cm_ready().await;
|
self.linux_headless_handle.wait_desktop_cm_ready().await;
|
||||||
if !self.send_logon_response_and_keep_alive().await {
|
self.send_logon_response().await;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
self.try_start_cm(lr.my_id, lr.my_name, self.authorized);
|
self.try_start_cm(lr.my_id, lr.my_name, self.authorized);
|
||||||
} else {
|
} else {
|
||||||
self.send_login_error(err_msg).await;
|
self.send_login_error(err_msg).await;
|
||||||
@@ -2372,9 +2331,7 @@ impl Connection {
|
|||||||
self.update_failure(failure, true, 1);
|
self.update_failure(failure, true, 1);
|
||||||
self.require_2fa.take();
|
self.require_2fa.take();
|
||||||
raii::AuthedConnID::set_session_2fa(self.session_key());
|
raii::AuthedConnID::set_session_2fa(self.session_key());
|
||||||
if !self.send_logon_response_and_keep_alive().await {
|
self.send_logon_response().await;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
self.try_start_cm(
|
self.try_start_cm(
|
||||||
self.lr.my_id.to_owned(),
|
self.lr.my_id.to_owned(),
|
||||||
self.lr.my_name.to_owned(),
|
self.lr.my_name.to_owned(),
|
||||||
@@ -2425,9 +2382,7 @@ impl Connection {
|
|||||||
if let Some((_instant, uuid_old)) = uuid_old {
|
if let Some((_instant, uuid_old)) = uuid_old {
|
||||||
if uuid == uuid_old {
|
if uuid == uuid_old {
|
||||||
self.from_switch = true;
|
self.from_switch = true;
|
||||||
if !self.send_logon_response_and_keep_alive().await {
|
self.send_logon_response().await;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
self.try_start_cm(
|
self.try_start_cm(
|
||||||
lr.my_id.clone(),
|
lr.my_id.clone(),
|
||||||
lr.my_name.clone(),
|
lr.my_name.clone(),
|
||||||
@@ -5393,8 +5348,9 @@ mod raii {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_wake_lock_on_setting_changed() {
|
pub fn check_wake_lock_on_setting_changed() {
|
||||||
let current =
|
let current = config::Config::get_bool_option(
|
||||||
config::Config::get_bool_option(keys::OPTION_KEEP_AWAKE_DURING_INCOMING_SESSIONS);
|
keys::OPTION_KEEP_AWAKE_DURING_INCOMING_SESSIONS,
|
||||||
|
);
|
||||||
let cached = *WAKELOCK_KEEP_AWAKE_OPTION.lock().unwrap();
|
let cached = *WAKELOCK_KEEP_AWAKE_OPTION.lock().unwrap();
|
||||||
if cached != Some(current) {
|
if cached != Some(current) {
|
||||||
Self::check_wake_lock();
|
Self::check_wake_lock();
|
||||||
|
|||||||
@@ -809,7 +809,7 @@ fn record_key_is_control_key(record_key: u64) -> bool {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn record_key_is_chr(record_key: u64) -> bool {
|
fn record_key_is_chr(record_key: u64) -> bool {
|
||||||
record_key >= KEY_CHAR_START
|
record_key < KEY_CHAR_START
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -1513,27 +1513,6 @@ fn get_control_key_value(key_event: &KeyEvent) -> i32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn has_hotkey_modifiers(key_event: &KeyEvent) -> bool {
|
|
||||||
key_event.modifiers.iter().any(|ck| {
|
|
||||||
let v = ck.value();
|
|
||||||
v == ControlKey::Control.value()
|
|
||||||
|| v == ControlKey::RControl.value()
|
|
||||||
|| v == ControlKey::Meta.value()
|
|
||||||
|| v == ControlKey::RWin.value()
|
|
||||||
|| {
|
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux"))]
|
|
||||||
{
|
|
||||||
v == ControlKey::Alt.value() || v == ControlKey::RAlt.value()
|
|
||||||
}
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
{
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn release_unpressed_modifiers(en: &mut Enigo, key_event: &KeyEvent) {
|
fn release_unpressed_modifiers(en: &mut Enigo, key_event: &KeyEvent) {
|
||||||
let ck_value = get_control_key_value(key_event);
|
let ck_value = get_control_key_value(key_event);
|
||||||
fix_modifiers(&key_event.modifiers[..], en, ck_value);
|
fix_modifiers(&key_event.modifiers[..], en, ck_value);
|
||||||
@@ -1593,7 +1572,7 @@ fn need_to_uppercase(en: &mut Enigo) -> bool {
|
|||||||
get_modifier_state(Key::Shift, en) || get_modifier_state(Key::CapsLock, en)
|
get_modifier_state(Key::Shift, en) || get_modifier_state(Key::CapsLock, en)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_chr(en: &mut Enigo, chr: u32, down: bool, _hotkey: bool) {
|
fn process_chr(en: &mut Enigo, chr: u32, down: bool) {
|
||||||
// On Wayland with uinput mode, use clipboard for character input
|
// On Wayland with uinput mode, use clipboard for character input
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
if !crate::platform::linux::is_x11() && wayland_use_uinput() {
|
if !crate::platform::linux::is_x11() && wayland_use_uinput() {
|
||||||
@@ -1608,16 +1587,6 @@ fn process_chr(en: &mut Enigo, chr: u32, down: bool, _hotkey: bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "macos", target_os = "windows"))]
|
|
||||||
if !_hotkey {
|
|
||||||
if down {
|
|
||||||
if let Ok(chr) = char::try_from(chr) {
|
|
||||||
en.key_sequence(&chr.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let key = char_value_to_key(chr);
|
let key = char_value_to_key(chr);
|
||||||
|
|
||||||
if down {
|
if down {
|
||||||
@@ -1887,7 +1856,7 @@ fn legacy_keyboard_mode(evt: &KeyEvent) {
|
|||||||
|
|
||||||
let record_key = chr as u64 + KEY_CHAR_START;
|
let record_key = chr as u64 + KEY_CHAR_START;
|
||||||
record_pressed_key(KeysDown::EnigoKey(record_key), down);
|
record_pressed_key(KeysDown::EnigoKey(record_key), down);
|
||||||
process_chr(&mut en, chr, down, has_hotkey_modifiers(evt))
|
process_chr(&mut en, chr, down)
|
||||||
}
|
}
|
||||||
Some(key_event::Union::Unicode(chr)) => {
|
Some(key_event::Union::Unicode(chr)) => {
|
||||||
// Same as Chr: release Shift for Unicode input
|
// Same as Chr: release Shift for Unicode input
|
||||||
|
|||||||
@@ -1289,7 +1289,8 @@ impl<T: InvokeUiSession> Session<T> {
|
|||||||
drop(connection_round_state_lock);
|
drop(connection_round_state_lock);
|
||||||
|
|
||||||
let cloned = self.clone();
|
let cloned = self.clone();
|
||||||
|
*cloned.audit_guid.lock().unwrap() = String::new();
|
||||||
|
*cloned.last_audit_note.lock().unwrap() = String::new();
|
||||||
// override only if true
|
// override only if true
|
||||||
if true == force_relay {
|
if true == force_relay {
|
||||||
self.lc.write().unwrap().force_relay = true;
|
self.lc.write().unwrap().force_relay = true;
|
||||||
@@ -1812,9 +1813,6 @@ impl<T: InvokeUiSession> Interface for Session<T> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
self.update_privacy_mode();
|
self.update_privacy_mode();
|
||||||
// Clear audit_guid when connection is established successfully
|
|
||||||
*self.audit_guid.lock().unwrap() = String::new();
|
|
||||||
*self.last_audit_note.lock().unwrap() = String::new();
|
|
||||||
// Save recent peers, then push event to flutter. So flutter can refresh peer page.
|
// Save recent peers, then push event to flutter. So flutter can refresh peer page.
|
||||||
self.lc.write().unwrap().handle_peer_info(&pi);
|
self.lc.write().unwrap().handle_peer_info(&pi);
|
||||||
self.set_peer_info(&pi);
|
self.set_peer_info(&pi);
|
||||||
|
|||||||
Reference in New Issue
Block a user