mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-02-25 20:18:47 +08:00
Compare commits
5 Commits
master
...
display_na
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
590e344ff5 | ||
|
|
76b0f69618 | ||
|
|
22e72cea69 | ||
|
|
5fc0367abd | ||
|
|
9111bfc1de |
56
.claude/commands/reflection.md
Normal file
56
.claude/commands/reflection.md
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
You are an expert in prompt engineering, specializing in optimizing AI code assistant instructions. Your task is to analyze and improve the instructions for Claude Code.
|
||||||
|
Follow these steps carefully:
|
||||||
|
|
||||||
|
1. Analysis Phase:
|
||||||
|
Review the chat history in your context window.
|
||||||
|
|
||||||
|
Then, examine the current Claude instructions, commands and config
|
||||||
|
<claude_instructions>
|
||||||
|
/CLAUDE.md
|
||||||
|
/.claude/commands/*
|
||||||
|
**/CLAUDE.md
|
||||||
|
.claude/settings.json
|
||||||
|
.claude/settings.local.json
|
||||||
|
</claude_instructions>
|
||||||
|
|
||||||
|
Analyze the chat history, instructions, commands and config to identify areas that could be improved. Look for:
|
||||||
|
- Inconsistencies in Claude's responses
|
||||||
|
- Misunderstandings of user requests
|
||||||
|
- Areas where Claude could provide more detailed or accurate information
|
||||||
|
- Opportunities to enhance Claude's ability to handle specific types of queries or tasks
|
||||||
|
- New commands or improvements to a commands name, function or response
|
||||||
|
- Permissions and MCPs we've approved locally that we should add to the config, especially if we've added new tools or require them for the command to work
|
||||||
|
|
||||||
|
2. Interaction Phase:
|
||||||
|
Present your findings and improvement ideas to the human. For each suggestion:
|
||||||
|
a) Explain the current issue you've identified
|
||||||
|
b) Propose a specific change or addition to the instructions
|
||||||
|
c) Describe how this change would improve Claude's performance
|
||||||
|
|
||||||
|
Wait for feedback from the human on each suggestion before proceeding. If the human approves a change, move it to the implementation phase. If not, refine your suggestion or move on to the next idea.
|
||||||
|
|
||||||
|
3. Implementation Phase:
|
||||||
|
For each approved change:
|
||||||
|
a) Clearly state the section of the instructions you're modifying
|
||||||
|
b) Present the new or modified text for that section
|
||||||
|
c) Explain how this change addresses the issue identified in the analysis phase
|
||||||
|
|
||||||
|
4. Output Format:
|
||||||
|
Present your final output in the following structure:
|
||||||
|
|
||||||
|
<analysis>
|
||||||
|
[List the issues identified and potential improvements]
|
||||||
|
</analysis>
|
||||||
|
|
||||||
|
<improvements>
|
||||||
|
[For each approved improvement:
|
||||||
|
1. Section being modified
|
||||||
|
2. New or modified instruction text
|
||||||
|
3. Explanation of how this addresses the identified issue]
|
||||||
|
</improvements>
|
||||||
|
|
||||||
|
<final_instructions>
|
||||||
|
[Present the complete, updated set of instructions for Claude, incorporating all approved changes]
|
||||||
|
</final_instructions>
|
||||||
|
|
||||||
|
Remember, your goal is to enhance Claude's performance and consistency while maintaining the core functionality and purpose of the AI assistant. Be thorough in your analysis, clear in your explanations, and precise in your implementations.
|
||||||
@@ -3063,11 +3063,6 @@ Future<void> start_service(bool is_start) async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> canBeBlocked() async {
|
Future<bool> canBeBlocked() async {
|
||||||
if (isWeb) {
|
|
||||||
// Web can only act as a controller, never as a controlled side,
|
|
||||||
// so it should never be blocked by a remote session.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// First check control permission
|
// First check control permission
|
||||||
final controlPermission = await bind.mainGetCommon(
|
final controlPermission = await bind.mainGetCommon(
|
||||||
key: "is-remote-modify-enabled-by-control-permissions");
|
key: "is-remote-modify-enabled-by-control-permissions");
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import 'dart:async';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_hbb/common.dart';
|
import 'package:flutter_hbb/common.dart';
|
||||||
@@ -16,7 +15,6 @@ class TerminalPage extends StatefulWidget {
|
|||||||
required this.tabController,
|
required this.tabController,
|
||||||
required this.isSharedPassword,
|
required this.isSharedPassword,
|
||||||
required this.terminalId,
|
required this.terminalId,
|
||||||
required this.tabKey,
|
|
||||||
this.forceRelay,
|
this.forceRelay,
|
||||||
this.connToken,
|
this.connToken,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
@@ -27,8 +25,6 @@ class TerminalPage extends StatefulWidget {
|
|||||||
final bool? isSharedPassword;
|
final bool? isSharedPassword;
|
||||||
final String? connToken;
|
final String? connToken;
|
||||||
final int terminalId;
|
final int terminalId;
|
||||||
/// Tab key for focus management, passed from parent to avoid duplicate construction
|
|
||||||
final String tabKey;
|
|
||||||
final SimpleWrapper<State<TerminalPage>?> _lastState = SimpleWrapper(null);
|
final SimpleWrapper<State<TerminalPage>?> _lastState = SimpleWrapper(null);
|
||||||
|
|
||||||
FFI get ffi => (_lastState.value! as _TerminalPageState)._ffi;
|
FFI get ffi => (_lastState.value! as _TerminalPageState)._ffi;
|
||||||
@@ -46,16 +42,11 @@ class _TerminalPageState extends State<TerminalPage>
|
|||||||
late FFI _ffi;
|
late FFI _ffi;
|
||||||
late TerminalModel _terminalModel;
|
late TerminalModel _terminalModel;
|
||||||
double? _cellHeight;
|
double? _cellHeight;
|
||||||
final FocusNode _terminalFocusNode = FocusNode(canRequestFocus: false);
|
|
||||||
StreamSubscription<DesktopTabState>? _tabStateSubscription;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
// Listen for tab selection changes to request focus
|
|
||||||
_tabStateSubscription = widget.tabController.state.listen(_onTabStateChanged);
|
|
||||||
|
|
||||||
// Use shared FFI instance from connection manager
|
// Use shared FFI instance from connection manager
|
||||||
_ffi = TerminalConnectionManager.getConnection(
|
_ffi = TerminalConnectionManager.getConnection(
|
||||||
peerId: widget.id,
|
peerId: widget.id,
|
||||||
@@ -73,13 +64,6 @@ class _TerminalPageState extends State<TerminalPage>
|
|||||||
_terminalModel.onResizeExternal = (w, h, pw, ph) {
|
_terminalModel.onResizeExternal = (w, h, pw, ph) {
|
||||||
_cellHeight = ph * 1.0;
|
_cellHeight = ph * 1.0;
|
||||||
|
|
||||||
// Enable focus once terminal has valid dimensions (first valid resize)
|
|
||||||
if (!_terminalFocusNode.canRequestFocus && w > 0 && h > 0) {
|
|
||||||
_terminalFocusNode.canRequestFocus = true;
|
|
||||||
// Auto-focus if this tab is currently selected
|
|
||||||
_requestFocusIfSelected();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Schedule the setState for the next frame
|
// Schedule the setState for the next frame
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
@@ -115,42 +99,14 @@ class _TerminalPageState extends State<TerminalPage>
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
// Cancel tab state subscription to prevent memory leak
|
|
||||||
_tabStateSubscription?.cancel();
|
|
||||||
// Unregister terminal model from FFI
|
// Unregister terminal model from FFI
|
||||||
_ffi.unregisterTerminalModel(widget.terminalId);
|
_ffi.unregisterTerminalModel(widget.terminalId);
|
||||||
_terminalModel.dispose();
|
_terminalModel.dispose();
|
||||||
_terminalFocusNode.dispose();
|
|
||||||
// Release connection reference instead of closing directly
|
// Release connection reference instead of closing directly
|
||||||
TerminalConnectionManager.releaseConnection(widget.id);
|
TerminalConnectionManager.releaseConnection(widget.id);
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onTabStateChanged(DesktopTabState state) {
|
|
||||||
// Check if this tab is now selected and request focus
|
|
||||||
if (state.selected >= 0 && state.selected < state.tabs.length) {
|
|
||||||
final selectedTab = state.tabs[state.selected];
|
|
||||||
if (selectedTab.key == widget.tabKey && mounted) {
|
|
||||||
_requestFocusIfSelected();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _requestFocusIfSelected() {
|
|
||||||
if (!mounted || !_terminalFocusNode.canRequestFocus) return;
|
|
||||||
// Use post-frame callback to ensure widget is fully laid out in focus tree
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
||||||
// Re-check conditions after frame: mounted, focusable, still selected, not already focused
|
|
||||||
if (!mounted || !_terminalFocusNode.canRequestFocus || _terminalFocusNode.hasFocus) return;
|
|
||||||
final state = widget.tabController.state.value;
|
|
||||||
if (state.selected >= 0 && state.selected < state.tabs.length) {
|
|
||||||
if (state.tabs[state.selected].key == widget.tabKey) {
|
|
||||||
_terminalFocusNode.requestFocus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method ensures that the number of visible rows is an integer by computing the
|
// This method ensures that the number of visible rows is an integer by computing the
|
||||||
// extra space left after dividing the available height by the height of a single
|
// extra space left after dividing the available height by the height of a single
|
||||||
// terminal row (`_cellHeight`) and distributing it evenly as top and bottom padding.
|
// terminal row (`_cellHeight`) and distributing it evenly as top and bottom padding.
|
||||||
@@ -175,9 +131,7 @@ class _TerminalPageState extends State<TerminalPage>
|
|||||||
return TerminalView(
|
return TerminalView(
|
||||||
_terminalModel.terminal,
|
_terminalModel.terminal,
|
||||||
controller: _terminalModel.terminalController,
|
controller: _terminalModel.terminalController,
|
||||||
focusNode: _terminalFocusNode,
|
autofocus: true,
|
||||||
// Note: autofocus is not used here because focus is managed manually
|
|
||||||
// via _onTabStateChanged() to handle tab switching properly.
|
|
||||||
backgroundOpacity: 0.7,
|
backgroundOpacity: 0.7,
|
||||||
padding: _calculatePadding(heightPx),
|
padding: _calculatePadding(heightPx),
|
||||||
onSecondaryTapDown: (details, offset) async {
|
onSecondaryTapDown: (details, offset) async {
|
||||||
|
|||||||
@@ -34,10 +34,6 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
|
|||||||
static const IconData selectedIcon = Icons.terminal;
|
static const IconData selectedIcon = Icons.terminal;
|
||||||
static const IconData unselectedIcon = Icons.terminal_outlined;
|
static const IconData unselectedIcon = Icons.terminal_outlined;
|
||||||
int _nextTerminalId = 1;
|
int _nextTerminalId = 1;
|
||||||
// Lightweight idempotency guard for async close operations
|
|
||||||
final Set<String> _closingTabs = {};
|
|
||||||
// When true, all session cleanup should persist (window-level close in progress)
|
|
||||||
bool _windowClosing = false;
|
|
||||||
|
|
||||||
_TerminalTabPageState(Map<String, dynamic> params) {
|
_TerminalTabPageState(Map<String, dynamic> params) {
|
||||||
Get.put(DesktopTabController(tabType: DesktopTabType.terminal));
|
Get.put(DesktopTabController(tabType: DesktopTabType.terminal));
|
||||||
@@ -74,12 +70,28 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
|
|||||||
label: tabLabel,
|
label: tabLabel,
|
||||||
selectedIcon: selectedIcon,
|
selectedIcon: selectedIcon,
|
||||||
unselectedIcon: unselectedIcon,
|
unselectedIcon: unselectedIcon,
|
||||||
onTabCloseButton: () => _closeTab(tabKey),
|
onTabCloseButton: () async {
|
||||||
|
if (await desktopTryShowTabAuditDialogCloseCancelled(
|
||||||
|
id: tabKey,
|
||||||
|
tabController: tabController,
|
||||||
|
)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Close the terminal session first
|
||||||
|
final ffi = TerminalConnectionManager.getExistingConnection(peerId);
|
||||||
|
if (ffi != null) {
|
||||||
|
final terminalModel = ffi.terminalModels[terminalId];
|
||||||
|
if (terminalModel != null) {
|
||||||
|
await terminalModel.closeTerminal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Then close the tab
|
||||||
|
tabController.closeBy(tabKey);
|
||||||
|
},
|
||||||
page: TerminalPage(
|
page: TerminalPage(
|
||||||
key: ValueKey(tabKey),
|
key: ValueKey(tabKey),
|
||||||
id: peerId,
|
id: peerId,
|
||||||
terminalId: terminalId,
|
terminalId: terminalId,
|
||||||
tabKey: tabKey,
|
|
||||||
password: password,
|
password: password,
|
||||||
isSharedPassword: isSharedPassword,
|
isSharedPassword: isSharedPassword,
|
||||||
tabController: tabController,
|
tabController: tabController,
|
||||||
@@ -89,159 +101,6 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unified tab close handler for all close paths (button, shortcut, programmatic).
|
|
||||||
/// Shows audit dialog, cleans up session if not persistent, then removes the UI tab.
|
|
||||||
Future<void> _closeTab(String tabKey) async {
|
|
||||||
// Idempotency guard: skip if already closing this tab
|
|
||||||
if (_closingTabs.contains(tabKey)) return;
|
|
||||||
_closingTabs.add(tabKey);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Snapshot peerTabCount BEFORE any await to avoid race with concurrent
|
|
||||||
// _closeAllTabs clearing tabController (which would make the live count
|
|
||||||
// drop to 0 and incorrectly trigger session persistence).
|
|
||||||
// Note: the snapshot may become stale if other individual tabs are closed
|
|
||||||
// during the audit dialog, but this is an acceptable trade-off.
|
|
||||||
int? snapshotPeerTabCount;
|
|
||||||
final parsed = _parseTabKey(tabKey);
|
|
||||||
if (parsed != null) {
|
|
||||||
final (peerId, _) = parsed;
|
|
||||||
snapshotPeerTabCount = tabController.state.value.tabs.where((t) {
|
|
||||||
final p = _parseTabKey(t.key);
|
|
||||||
return p != null && p.$1 == peerId;
|
|
||||||
}).length;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await desktopTryShowTabAuditDialogCloseCancelled(
|
|
||||||
id: tabKey,
|
|
||||||
tabController: tabController,
|
|
||||||
)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close terminal session if not in persistent mode.
|
|
||||||
// Wrapped separately so session cleanup failure never blocks UI tab removal.
|
|
||||||
try {
|
|
||||||
await _closeTerminalSessionIfNeeded(tabKey,
|
|
||||||
peerTabCount: snapshotPeerTabCount);
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('[TerminalTabPage] Session cleanup failed for $tabKey: $e');
|
|
||||||
}
|
|
||||||
// Always close the tab from UI, regardless of session cleanup result
|
|
||||||
tabController.closeBy(tabKey);
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('[TerminalTabPage] Error closing tab $tabKey: $e');
|
|
||||||
} finally {
|
|
||||||
_closingTabs.remove(tabKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Close all tabs with session cleanup.
|
|
||||||
/// Used for window-level close operations (onDestroy, handleWindowCloseButton).
|
|
||||||
/// UI tabs are removed immediately; session cleanup runs in parallel with a
|
|
||||||
/// bounded timeout so window close is not blocked indefinitely.
|
|
||||||
Future<void> _closeAllTabs() async {
|
|
||||||
_windowClosing = true;
|
|
||||||
final tabKeys = tabController.state.value.tabs.map((t) => t.key).toList();
|
|
||||||
// Remove all UI tabs immediately (same instant behavior as the old tabController.clear())
|
|
||||||
tabController.clear();
|
|
||||||
// Run session cleanup in parallel with bounded timeout (closeTerminal() has internal 3s timeout).
|
|
||||||
// Skip tabs already being closed by a concurrent _closeTab() to avoid duplicate FFI calls.
|
|
||||||
final futures = tabKeys
|
|
||||||
.where((tabKey) => !_closingTabs.contains(tabKey))
|
|
||||||
.map((tabKey) async {
|
|
||||||
try {
|
|
||||||
await _closeTerminalSessionIfNeeded(tabKey, persistAll: true);
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('[TerminalTabPage] Session cleanup failed for $tabKey: $e');
|
|
||||||
}
|
|
||||||
}).toList();
|
|
||||||
if (futures.isNotEmpty) {
|
|
||||||
await Future.wait(futures).timeout(
|
|
||||||
const Duration(seconds: 4),
|
|
||||||
onTimeout: () {
|
|
||||||
debugPrint(
|
|
||||||
'[TerminalTabPage] Session cleanup timed out for batch close');
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Close the terminal session on server side based on persistent mode.
|
|
||||||
///
|
|
||||||
/// [persistAll] controls behavior when persistent mode is enabled:
|
|
||||||
/// - `true` (window close): persist all sessions, don't close any.
|
|
||||||
/// - `false` (tab close): only persist the last session for the peer,
|
|
||||||
/// close others so only the most recent disconnected session survives.
|
|
||||||
///
|
|
||||||
/// Note: if [_windowClosing] is true, persistAll is forced to true so that
|
|
||||||
/// in-flight _closeTab() calls don't accidentally close sessions that the
|
|
||||||
/// window-close flow intends to preserve.
|
|
||||||
Future<void> _closeTerminalSessionIfNeeded(String tabKey,
|
|
||||||
{bool persistAll = false, int? peerTabCount}) async {
|
|
||||||
// If window close is in progress, override to persist all sessions
|
|
||||||
// even if this call originated from an individual tab close.
|
|
||||||
if (_windowClosing) {
|
|
||||||
persistAll = true;
|
|
||||||
}
|
|
||||||
final parsed = _parseTabKey(tabKey);
|
|
||||||
if (parsed == null) return;
|
|
||||||
final (peerId, terminalId) = parsed;
|
|
||||||
|
|
||||||
final ffi = TerminalConnectionManager.getExistingConnection(peerId);
|
|
||||||
if (ffi == null) return;
|
|
||||||
|
|
||||||
final isPersistent = bind.sessionGetToggleOptionSync(
|
|
||||||
sessionId: ffi.sessionId,
|
|
||||||
arg: kOptionTerminalPersistent,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isPersistent) {
|
|
||||||
if (persistAll) {
|
|
||||||
// Window close: persist all sessions
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Tab close: only persist if this is the last tab for this peer.
|
|
||||||
// Use the snapshot value if provided (avoids race with concurrent tab removal).
|
|
||||||
final effectivePeerTabCount = peerTabCount ??
|
|
||||||
tabController.state.value.tabs.where((t) {
|
|
||||||
final p = _parseTabKey(t.key);
|
|
||||||
return p != null && p.$1 == peerId;
|
|
||||||
}).length;
|
|
||||||
if (effectivePeerTabCount <= 1) {
|
|
||||||
// Last tab for this peer — persist the session
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Not the last tab — fall through to close the session
|
|
||||||
}
|
|
||||||
|
|
||||||
final terminalModel = ffi.terminalModels[terminalId];
|
|
||||||
if (terminalModel != null) {
|
|
||||||
// closeTerminal() has internal 3s timeout, no need for external timeout
|
|
||||||
await terminalModel.closeTerminal();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse tabKey (format: "peerId_terminalId") into its components.
|
|
||||||
/// Note: peerId may contain underscores, so we use lastIndexOf('_').
|
|
||||||
/// Returns null if tabKey format is invalid.
|
|
||||||
(String peerId, int terminalId)? _parseTabKey(String tabKey) {
|
|
||||||
final lastUnderscore = tabKey.lastIndexOf('_');
|
|
||||||
if (lastUnderscore <= 0) {
|
|
||||||
debugPrint('[TerminalTabPage] Invalid tabKey format: $tabKey');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final terminalIdStr = tabKey.substring(lastUnderscore + 1);
|
|
||||||
final terminalId = int.tryParse(terminalIdStr);
|
|
||||||
if (terminalId == null) {
|
|
||||||
debugPrint('[TerminalTabPage] Invalid terminalId in tabKey: $tabKey');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final peerId = tabKey.substring(0, lastUnderscore);
|
|
||||||
return (peerId, terminalId);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _tabMenuBuilder(String peerId, CancelFunc cancelFunc) {
|
Widget _tabMenuBuilder(String peerId, CancelFunc cancelFunc) {
|
||||||
final List<MenuEntryBase<String>> menu = [];
|
final List<MenuEntryBase<String>> menu = [];
|
||||||
const EdgeInsets padding = EdgeInsets.only(left: 8.0, right: 5.0);
|
const EdgeInsets padding = EdgeInsets.only(left: 8.0, right: 5.0);
|
||||||
@@ -325,8 +184,7 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
|
|||||||
} else if (call.method == kWindowEventRestoreTerminalSessions) {
|
} else if (call.method == kWindowEventRestoreTerminalSessions) {
|
||||||
_restoreSessions(call.arguments);
|
_restoreSessions(call.arguments);
|
||||||
} else if (call.method == "onDestroy") {
|
} else if (call.method == "onDestroy") {
|
||||||
// Clean up sessions before window destruction (bounded wait)
|
tabController.clear();
|
||||||
await _closeAllTabs();
|
|
||||||
} else if (call.method == kWindowActionRebuild) {
|
} else if (call.method == kWindowActionRebuild) {
|
||||||
reloadCurrentWindow();
|
reloadCurrentWindow();
|
||||||
} else if (call.method == kWindowEventActiveSession) {
|
} else if (call.method == kWindowEventActiveSession) {
|
||||||
@@ -336,10 +194,7 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
|
|||||||
final currentTab = tabController.state.value.selectedTabInfo;
|
final currentTab = tabController.state.value.selectedTabInfo;
|
||||||
assert(call.arguments is String,
|
assert(call.arguments is String,
|
||||||
"Expected String arguments for kWindowEventActiveSession, got ${call.arguments.runtimeType}");
|
"Expected String arguments for kWindowEventActiveSession, got ${call.arguments.runtimeType}");
|
||||||
// Use lastIndexOf to handle peerIds containing underscores
|
if (currentTab.key.startsWith(call.arguments)) {
|
||||||
final lastUnderscore = currentTab.key.lastIndexOf('_');
|
|
||||||
if (lastUnderscore > 0 &&
|
|
||||||
currentTab.key.substring(0, lastUnderscore) == call.arguments) {
|
|
||||||
windowOnTop(windowId());
|
windowOnTop(windowId());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -410,7 +265,7 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
|
|||||||
// macOS: Cmd+W (standard for close tab)
|
// macOS: Cmd+W (standard for close tab)
|
||||||
final currentTab = tabController.state.value.selectedTabInfo;
|
final currentTab = tabController.state.value.selectedTabInfo;
|
||||||
if (tabController.state.value.tabs.length > 1) {
|
if (tabController.state.value.tabs.length > 1) {
|
||||||
_closeTab(currentTab.key);
|
tabController.closeBy(currentTab.key);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (!isMacOS &&
|
} else if (!isMacOS &&
|
||||||
@@ -419,7 +274,7 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
|
|||||||
// Other platforms: Ctrl+Shift+W (to avoid conflict with Ctrl+W word delete)
|
// Other platforms: Ctrl+Shift+W (to avoid conflict with Ctrl+W word delete)
|
||||||
final currentTab = tabController.state.value.selectedTabInfo;
|
final currentTab = tabController.state.value.selectedTabInfo;
|
||||||
if (tabController.state.value.tabs.length > 1) {
|
if (tabController.state.value.tabs.length > 1) {
|
||||||
_closeTab(currentTab.key);
|
tabController.closeBy(currentTab.key);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -474,10 +329,7 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
|
|||||||
void _addNewTerminal(String peerId, {int? terminalId}) {
|
void _addNewTerminal(String peerId, {int? terminalId}) {
|
||||||
// Find first tab for this peer to get connection parameters
|
// Find first tab for this peer to get connection parameters
|
||||||
final firstTab = tabController.state.value.tabs.firstWhere(
|
final firstTab = tabController.state.value.tabs.firstWhere(
|
||||||
(tab) {
|
(tab) => tab.key.startsWith('$peerId\_'),
|
||||||
final last = tab.key.lastIndexOf('_');
|
|
||||||
return last > 0 && tab.key.substring(0, last) == peerId;
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
if (firstTab.page is TerminalPage) {
|
if (firstTab.page is TerminalPage) {
|
||||||
final page = firstTab.page as TerminalPage;
|
final page = firstTab.page as TerminalPage;
|
||||||
@@ -498,10 +350,11 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
|
|||||||
|
|
||||||
void _addNewTerminalForCurrentPeer({int? terminalId}) {
|
void _addNewTerminalForCurrentPeer({int? terminalId}) {
|
||||||
final currentTab = tabController.state.value.selectedTabInfo;
|
final currentTab = tabController.state.value.selectedTabInfo;
|
||||||
final parsed = _parseTabKey(currentTab.key);
|
final parts = currentTab.key.split('_');
|
||||||
if (parsed == null) return;
|
if (parts.isNotEmpty) {
|
||||||
final (peerId, _) = parsed;
|
final peerId = parts[0];
|
||||||
_addNewTerminal(peerId, terminalId: terminalId);
|
_addNewTerminal(peerId, terminalId: terminalId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -515,9 +368,10 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
|
|||||||
selectedBorderColor: MyTheme.accent,
|
selectedBorderColor: MyTheme.accent,
|
||||||
labelGetter: DesktopTab.tablabelGetter,
|
labelGetter: DesktopTab.tablabelGetter,
|
||||||
tabMenuBuilder: (key) {
|
tabMenuBuilder: (key) {
|
||||||
final parsed = _parseTabKey(key);
|
// Extract peerId from tab key (format: "peerId_terminalId")
|
||||||
if (parsed == null) return Container();
|
final parts = key.split('_');
|
||||||
final (peerId, _) = parsed;
|
if (parts.isEmpty) return Container();
|
||||||
|
final peerId = parts[0];
|
||||||
return _tabMenuBuilder(peerId, () {});
|
return _tabMenuBuilder(peerId, () {});
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
@@ -572,7 +426,7 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (connLength <= 1) {
|
if (connLength <= 1) {
|
||||||
await _closeAllTabs();
|
tabController.clear();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
final bool res;
|
final bool res;
|
||||||
@@ -583,7 +437,7 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
|
|||||||
res = await closeConfirmDialog();
|
res = await closeConfirmDialog();
|
||||||
}
|
}
|
||||||
if (res) {
|
if (res) {
|
||||||
await _closeAllTabs();
|
tabController.clear();
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,10 +83,7 @@ class _TerminalPageState extends State<TerminalPage>
|
|||||||
// Register this terminal model with FFI for event routing
|
// Register this terminal model with FFI for event routing
|
||||||
_ffi.registerTerminalModel(widget.terminalId, _terminalModel);
|
_ffi.registerTerminalModel(widget.terminalId, _terminalModel);
|
||||||
|
|
||||||
// Web desktop users have full hardware keyboard access, so the on-screen
|
_showTerminalExtraKeys = mainGetLocalBoolOptionSync(kOptionEnableShowTerminalExtraKeys);
|
||||||
// terminal extra keys bar is unnecessary and disabled.
|
|
||||||
_showTerminalExtraKeys = !isWebDesktop &&
|
|
||||||
mainGetLocalBoolOptionSync(kOptionEnableShowTerminalExtraKeys);
|
|
||||||
// Initialize terminal connection
|
// Initialize terminal connection
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
_ffi.dialogManager
|
_ffi.dialogManager
|
||||||
|
|||||||
@@ -24,13 +24,6 @@ class TerminalModel with ChangeNotifier {
|
|||||||
bool _disposed = false;
|
bool _disposed = false;
|
||||||
|
|
||||||
final _inputBuffer = <String>[];
|
final _inputBuffer = <String>[];
|
||||||
// Buffer for output data received before terminal view has valid dimensions.
|
|
||||||
// This prevents NaN errors when writing to terminal before layout is complete.
|
|
||||||
final _pendingOutputChunks = <String>[];
|
|
||||||
int _pendingOutputSize = 0;
|
|
||||||
static const int _kMaxOutputBufferChars = 8 * 1024;
|
|
||||||
// View ready state: true when terminal has valid dimensions, safe to write
|
|
||||||
bool _terminalViewReady = false;
|
|
||||||
|
|
||||||
bool get isPeerWindows => parent.ffiModel.pi.platform == kPeerPlatformWindows;
|
bool get isPeerWindows => parent.ffiModel.pi.platform == kPeerPlatformWindows;
|
||||||
|
|
||||||
@@ -81,12 +74,6 @@ class TerminalModel with ChangeNotifier {
|
|||||||
// This piece of code must be placed before the conditional check in order to initialize properly.
|
// This piece of code must be placed before the conditional check in order to initialize properly.
|
||||||
onResizeExternal?.call(w, h, pw, ph);
|
onResizeExternal?.call(w, h, pw, ph);
|
||||||
|
|
||||||
// Mark terminal view as ready and flush any buffered output on first valid resize.
|
|
||||||
// Must be after onResizeExternal so the view layer has valid dimensions before flushing.
|
|
||||||
if (!_terminalViewReady) {
|
|
||||||
_markViewReady();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_terminalOpened) {
|
if (_terminalOpened) {
|
||||||
// Notify remote terminal of resize
|
// Notify remote terminal of resize
|
||||||
try {
|
try {
|
||||||
@@ -154,7 +141,7 @@ class TerminalModel with ChangeNotifier {
|
|||||||
debugPrint('[TerminalModel] Error calling sessionOpenTerminal: $e');
|
debugPrint('[TerminalModel] Error calling sessionOpenTerminal: $e');
|
||||||
// Optionally show error to user
|
// Optionally show error to user
|
||||||
if (e is TimeoutException) {
|
if (e is TimeoutException) {
|
||||||
_writeToTerminal('Failed to open terminal: Connection timeout\r\n');
|
terminal.write('Failed to open terminal: Connection timeout\r\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -266,8 +253,8 @@ class TerminalModel with ChangeNotifier {
|
|||||||
|
|
||||||
void _handleTerminalOpened(Map<String, dynamic> evt) {
|
void _handleTerminalOpened(Map<String, dynamic> evt) {
|
||||||
final bool success = getSuccessFromEvt(evt);
|
final bool success = getSuccessFromEvt(evt);
|
||||||
final String message = evt['message']?.toString() ?? '';
|
final String message = evt['message'] ?? '';
|
||||||
final String? serviceId = evt['service_id']?.toString();
|
final String? serviceId = evt['service_id'];
|
||||||
|
|
||||||
debugPrint(
|
debugPrint(
|
||||||
'[TerminalModel] Terminal opened response: success=$success, message=$message, service_id=$serviceId');
|
'[TerminalModel] Terminal opened response: success=$success, message=$message, service_id=$serviceId');
|
||||||
@@ -275,18 +262,7 @@ class TerminalModel with ChangeNotifier {
|
|||||||
if (success) {
|
if (success) {
|
||||||
_terminalOpened = true;
|
_terminalOpened = true;
|
||||||
|
|
||||||
// On reconnect ("Reconnected to existing terminal"), server may replay recent output.
|
// Service ID is now saved on the Rust side in handle_terminal_response
|
||||||
// If this TerminalView instance is reused (not rebuilt), duplicate lines can appear.
|
|
||||||
// We intentionally accept this tradeoff for now to keep logic simple.
|
|
||||||
|
|
||||||
// Fallback: if terminal view is not yet ready but already has valid
|
|
||||||
// dimensions (e.g. layout completed before open response arrived),
|
|
||||||
// mark view ready now to avoid output stuck in buffer indefinitely.
|
|
||||||
if (!_terminalViewReady &&
|
|
||||||
terminal.viewWidth > 0 &&
|
|
||||||
terminal.viewHeight > 0) {
|
|
||||||
_markViewReady();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process any buffered input
|
// Process any buffered input
|
||||||
_processBufferedInputAsync().then((_) {
|
_processBufferedInputAsync().then((_) {
|
||||||
@@ -307,7 +283,7 @@ class TerminalModel with ChangeNotifier {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_writeToTerminal('Failed to open terminal: $message\r\n');
|
terminal.write('Failed to open terminal: $message\r\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,82 +327,29 @@ class TerminalModel with ChangeNotifier {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_writeToTerminal(text);
|
terminal.write(text);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('[TerminalModel] Failed to process terminal data: $e');
|
debugPrint('[TerminalModel] Failed to process terminal data: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write text to terminal, buffering if the view is not yet ready.
|
|
||||||
/// All terminal output should go through this method to avoid NaN errors
|
|
||||||
/// from writing before the terminal view has valid layout dimensions.
|
|
||||||
void _writeToTerminal(String text) {
|
|
||||||
if (!_terminalViewReady) {
|
|
||||||
// If a single chunk exceeds the cap, keep only its tail.
|
|
||||||
// Note: truncation may split a multi-byte ANSI escape sequence,
|
|
||||||
// which can cause a brief visual glitch on flush. This is acceptable
|
|
||||||
// because it only affects the pre-layout buffering window and the
|
|
||||||
// terminal will self-correct on subsequent output.
|
|
||||||
if (text.length >= _kMaxOutputBufferChars) {
|
|
||||||
final truncated = text.substring(text.length - _kMaxOutputBufferChars);
|
|
||||||
_pendingOutputChunks
|
|
||||||
..clear()
|
|
||||||
..add(truncated);
|
|
||||||
_pendingOutputSize = truncated.length;
|
|
||||||
} else {
|
|
||||||
_pendingOutputChunks.add(text);
|
|
||||||
_pendingOutputSize += text.length;
|
|
||||||
// Drop oldest chunks if exceeds limit (whole chunks to preserve ANSI sequences)
|
|
||||||
while (_pendingOutputSize > _kMaxOutputBufferChars &&
|
|
||||||
_pendingOutputChunks.length > 1) {
|
|
||||||
final removed = _pendingOutputChunks.removeAt(0);
|
|
||||||
_pendingOutputSize -= removed.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
terminal.write(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _flushOutputBuffer() {
|
|
||||||
if (_pendingOutputChunks.isEmpty) return;
|
|
||||||
debugPrint(
|
|
||||||
'[TerminalModel] Flushing $_pendingOutputSize buffered chars (${_pendingOutputChunks.length} chunks)');
|
|
||||||
for (final chunk in _pendingOutputChunks) {
|
|
||||||
terminal.write(chunk);
|
|
||||||
}
|
|
||||||
_pendingOutputChunks.clear();
|
|
||||||
_pendingOutputSize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Mark terminal view as ready and flush buffered output.
|
|
||||||
void _markViewReady() {
|
|
||||||
if (_terminalViewReady) return;
|
|
||||||
_terminalViewReady = true;
|
|
||||||
_flushOutputBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleTerminalClosed(Map<String, dynamic> evt) {
|
void _handleTerminalClosed(Map<String, dynamic> evt) {
|
||||||
final int exitCode = evt['exit_code'] ?? 0;
|
final int exitCode = evt['exit_code'] ?? 0;
|
||||||
_writeToTerminal('\r\nTerminal closed with exit code: $exitCode\r\n');
|
terminal.write('\r\nTerminal closed with exit code: $exitCode\r\n');
|
||||||
_terminalOpened = false;
|
_terminalOpened = false;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleTerminalError(Map<String, dynamic> evt) {
|
void _handleTerminalError(Map<String, dynamic> evt) {
|
||||||
final String message = evt['message'] ?? 'Unknown error';
|
final String message = evt['message'] ?? 'Unknown error';
|
||||||
_writeToTerminal('\r\nTerminal error: $message\r\n');
|
terminal.write('\r\nTerminal error: $message\r\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
if (_disposed) return;
|
if (_disposed) return;
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
// Clear buffers to free memory
|
|
||||||
_inputBuffer.clear();
|
|
||||||
_pendingOutputChunks.clear();
|
|
||||||
_pendingOutputSize = 0;
|
|
||||||
// Terminal cleanup is handled server-side when service closes
|
// Terminal cleanup is handled server-side when service closes
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|||||||
440
src/lang/el.rs
440
src/lang/el.rs
@@ -3,7 +3,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
[
|
[
|
||||||
("Status", "Κατάσταση"),
|
("Status", "Κατάσταση"),
|
||||||
("Your Desktop", "Ο σταθμός εργασίας σας"),
|
("Your Desktop", "Ο σταθμός εργασίας σας"),
|
||||||
("desk_tip", "Η πρόσβαση στον σταθμό εργασίας σας είναι δυνατή με αυτό το ID και τον κωδικό πρόσβασης."),
|
("desk_tip", "Η πρόσβαση στον σταθμό εργασίας σας είναι δυνατή με αυτό το αναγνωριστικό και τον κωδικό πρόσβασης."),
|
||||||
("Password", "Κωδικός πρόσβασης"),
|
("Password", "Κωδικός πρόσβασης"),
|
||||||
("Ready", "Έτοιμο"),
|
("Ready", "Έτοιμο"),
|
||||||
("Established", "Συνδέθηκε"),
|
("Established", "Συνδέθηκε"),
|
||||||
@@ -19,16 +19,16 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Recent sessions", "Πρόσφατες συνεδρίες"),
|
("Recent sessions", "Πρόσφατες συνεδρίες"),
|
||||||
("Address book", "Βιβλίο διευθύνσεων"),
|
("Address book", "Βιβλίο διευθύνσεων"),
|
||||||
("Confirmation", "Επιβεβαίωση"),
|
("Confirmation", "Επιβεβαίωση"),
|
||||||
("TCP tunneling", "Σήραγγα TCP"),
|
("TCP tunneling", "TCP tunneling"),
|
||||||
("Remove", "Κατάργηση"),
|
("Remove", "Κατάργηση"),
|
||||||
("Refresh random password", "Ανανέωση τυχαίου κωδικού πρόσβασης"),
|
("Refresh random password", "Νέος τυχαίος κωδικός πρόσβασης"),
|
||||||
("Set your own password", "Ορίστε τον δικό σας κωδικό πρόσβασης"),
|
("Set your own password", "Ορίστε τον δικό σας κωδικό πρόσβασης"),
|
||||||
("Enable keyboard/mouse", "Ενεργοποίηση πληκτρολογίου/ποντικιού"),
|
("Enable keyboard/mouse", "Ενεργοποίηση πληκτρολογίου/ποντικιού"),
|
||||||
("Enable clipboard", "Ενεργοποίηση προχείρου"),
|
("Enable clipboard", "Ενεργοποίηση προχείρου"),
|
||||||
("Enable file transfer", "Ενεργοποίηση μεταφοράς αρχείων"),
|
("Enable file transfer", "Ενεργοποίηση μεταφοράς αρχείων"),
|
||||||
("Enable TCP tunneling", "Ενεργοποίηση σήραγγας TCP"),
|
("Enable TCP tunneling", "Ενεργοποίηση TCP tunneling"),
|
||||||
("IP Whitelisting", "Λίστα επιτρεπόμενων IP"),
|
("IP Whitelisting", "Λίστα επιτρεπόμενων IP"),
|
||||||
("ID/Relay Server", "ID/Διακομιστής Αναμετάδοσης"),
|
("ID/Relay Server", "Διακομιστής ID/Αναμετάδοσης"),
|
||||||
("Import server config", "Εισαγωγή διαμόρφωσης διακομιστή"),
|
("Import server config", "Εισαγωγή διαμόρφωσης διακομιστή"),
|
||||||
("Export Server Config", "Εξαγωγή διαμόρφωσης διακομιστή"),
|
("Export Server Config", "Εξαγωγή διαμόρφωσης διακομιστή"),
|
||||||
("Import server configuration successfully", "Επιτυχής εισαγωγή διαμόρφωσης διακομιστή"),
|
("Import server configuration successfully", "Επιτυχής εισαγωγή διαμόρφωσης διακομιστή"),
|
||||||
@@ -36,14 +36,14 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Invalid server configuration", "Μη έγκυρη διαμόρφωση διακομιστή"),
|
("Invalid server configuration", "Μη έγκυρη διαμόρφωση διακομιστή"),
|
||||||
("Clipboard is empty", "Το πρόχειρο είναι κενό"),
|
("Clipboard is empty", "Το πρόχειρο είναι κενό"),
|
||||||
("Stop service", "Διακοπή υπηρεσίας"),
|
("Stop service", "Διακοπή υπηρεσίας"),
|
||||||
("Change ID", "Αλλαγή του ID σας"),
|
("Change ID", "Αλλαγή αναγνωριστικού ID"),
|
||||||
("Your new ID", "Το νέο σας ID"),
|
("Your new ID", "Το νέο σας ID"),
|
||||||
("length %min% to %max%", "μέγεθος από %min% έως %max%"),
|
("length %min% to %max%", "μέγεθος από %min% έως %max%"),
|
||||||
("starts with a letter", "ξεκινά με γράμμα"),
|
("starts with a letter", "ξεκινά με γράμμα"),
|
||||||
("allowed characters", "επιτρεπόμενοι χαρακτήρες"),
|
("allowed characters", "επιτρεπόμενοι χαρακτήρες"),
|
||||||
("id_change_tip", "Επιτρέπονται μόνο οι χαρακτήρες a-z, A-Z, 0-9, - (παύλα) και _ (κάτω παύλα). Το πρώτο γράμμα πρέπει να είναι a-z, A-Z και το μήκος πρέπει να είναι μεταξύ 6 και 16 χαρακτήρων."),
|
("id_change_tip", "Επιτρέπονται μόνο οι χαρακτήρες a-z, A-Z, 0-9, - (παύλα) και _ (κάτω παύλα). Το πρώτο γράμμα πρέπει να είναι a-z, A-Z και το μήκος πρέπει να είναι μεταξύ 6 και 16 χαρακτήρων."),
|
||||||
("Website", "Ιστότοπος"),
|
("Website", "Ιστότοπος"),
|
||||||
("About", "Σχετικά"),
|
("About", "Πληροφορίες"),
|
||||||
("Slogan_tip", "Φτιαγμένο με πάθος - σε έναν κόσμο που βυθίζεται στο χάος!"),
|
("Slogan_tip", "Φτιαγμένο με πάθος - σε έναν κόσμο που βυθίζεται στο χάος!"),
|
||||||
("Privacy Statement", "Πολιτική απορρήτου"),
|
("Privacy Statement", "Πολιτική απορρήτου"),
|
||||||
("Mute", "Σίγαση"),
|
("Mute", "Σίγαση"),
|
||||||
@@ -53,7 +53,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Audio Input", "Είσοδος ήχου"),
|
("Audio Input", "Είσοδος ήχου"),
|
||||||
("Enhancements", "Βελτιώσεις"),
|
("Enhancements", "Βελτιώσεις"),
|
||||||
("Hardware Codec", "Κωδικοποιητής υλικού"),
|
("Hardware Codec", "Κωδικοποιητής υλικού"),
|
||||||
("Adaptive bitrate", "Προσαρμοστικός ρυθμός μετάδοσης bit"),
|
("Adaptive bitrate", "Adaptive bitrate"),
|
||||||
("ID Server", "Διακομιστής ID"),
|
("ID Server", "Διακομιστής ID"),
|
||||||
("Relay Server", "Διακομιστής αναμετάδοσης"),
|
("Relay Server", "Διακομιστής αναμετάδοσης"),
|
||||||
("API Server", "Διακομιστής API"),
|
("API Server", "Διακομιστής API"),
|
||||||
@@ -67,18 +67,18 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Skip", "Παράλειψη"),
|
("Skip", "Παράλειψη"),
|
||||||
("Close", "Κλείσιμο"),
|
("Close", "Κλείσιμο"),
|
||||||
("Retry", "Δοκίμασε ξανά"),
|
("Retry", "Δοκίμασε ξανά"),
|
||||||
("OK", "Εντάξει"),
|
("OK", "ΟΚ"),
|
||||||
("Password Required", "Απαιτείται κωδικός πρόσβασης"),
|
("Password Required", "Απαιτείται κωδικός πρόσβασης"),
|
||||||
("Please enter your password", "Παρακαλώ εισάγετε τον κωδικό πρόσβασης"),
|
("Please enter your password", "Παρακαλώ εισάγετε τον κωδικό πρόσβασης"),
|
||||||
("Remember password", "Απομνημόνευση κωδικού πρόσβασης"),
|
("Remember password", "Απομνημόνευση κωδικού πρόσβασης"),
|
||||||
("Wrong Password", "Λάθος κωδικός πρόσβασης"),
|
("Wrong Password", "Λάθος κωδικός πρόσβασης"),
|
||||||
("Do you want to enter again?", "Θέλετε να γίνει επανασύνδεση;"),
|
("Do you want to enter again?", "Επανασύνδεση;"),
|
||||||
("Connection Error", "Σφάλμα σύνδεσης"),
|
("Connection Error", "Σφάλμα σύνδεσης"),
|
||||||
("Error", "Σφάλμα"),
|
("Error", "Σφάλμα"),
|
||||||
("Reset by the peer", "Η σύνδεση επαναφέρθηκε από τον απομακρυσμένο σταθμό"),
|
("Reset by the peer", "Η σύνδεση επαναφέρθηκε από τον απομακρυσμένο σταθμό"),
|
||||||
("Connecting...", "Σύνδεση..."),
|
("Connecting...", "Σύνδεση..."),
|
||||||
("Connection in progress. Please wait.", "Σύνδεση σε εξέλιξη. Παρακαλώ περιμένετε."),
|
("Connection in progress. Please wait.", "Σύνδεση σε εξέλιξη. Παρακαλώ περιμένετε."),
|
||||||
("Please try 1 minute later", "Παρακαλώ δοκιμάστε ξανά σε 1 λεπτό"),
|
("Please try 1 minute later", "Παρακαλώ ξαναδοκιμάστε σε 1 λεπτό"),
|
||||||
("Login Error", "Σφάλμα εισόδου"),
|
("Login Error", "Σφάλμα εισόδου"),
|
||||||
("Successful", "Επιτυχής"),
|
("Successful", "Επιτυχής"),
|
||||||
("Connected, waiting for image...", "Συνδέθηκε, αναμονή για εικόνα..."),
|
("Connected, waiting for image...", "Συνδέθηκε, αναμονή για εικόνα..."),
|
||||||
@@ -101,10 +101,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Select All", "Επιλογή όλων"),
|
("Select All", "Επιλογή όλων"),
|
||||||
("Unselect All", "Κατάργηση επιλογής όλων"),
|
("Unselect All", "Κατάργηση επιλογής όλων"),
|
||||||
("Empty Directory", "Κενός φάκελος"),
|
("Empty Directory", "Κενός φάκελος"),
|
||||||
("Not an empty directory", "Η διαδρομή δεν είναι κενή"),
|
("Not an empty directory", "Ο φάκελος δεν είναι κενός"),
|
||||||
("Are you sure you want to delete this file?", "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτό το αρχείο;"),
|
("Are you sure you want to delete this file?", "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτό το αρχείο;"),
|
||||||
("Are you sure you want to delete this empty directory?", "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτήν την κενή διαδρομή;"),
|
("Are you sure you want to delete this empty directory?", "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτόν τον κενό φάκελο;"),
|
||||||
("Are you sure you want to delete the file of this directory?", "Είστε βέβαιοι ότι θέλετε να διαγράψετε το αρχείο αυτής της διαδρομής;"),
|
("Are you sure you want to delete the file of this directory?", "Είστε βέβαιοι ότι θέλετε να διαγράψετε το αρχείο αυτού του φακέλου;"),
|
||||||
("Do this for all conflicts", "Κάνε αυτό για όλες τις διενέξεις"),
|
("Do this for all conflicts", "Κάνε αυτό για όλες τις διενέξεις"),
|
||||||
("This is irreversible!", "Αυτό είναι μη αναστρέψιμο!"),
|
("This is irreversible!", "Αυτό είναι μη αναστρέψιμο!"),
|
||||||
("Deleting", "Διαγραφή"),
|
("Deleting", "Διαγραφή"),
|
||||||
@@ -133,8 +133,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Insert Ctrl + Alt + Del", "Εισαγωγή Ctrl + Alt + Del"),
|
("Insert Ctrl + Alt + Del", "Εισαγωγή Ctrl + Alt + Del"),
|
||||||
("Insert Lock", "Κλείδωμα απομακρυσμένου σταθμού"),
|
("Insert Lock", "Κλείδωμα απομακρυσμένου σταθμού"),
|
||||||
("Refresh", "Ανανέωση"),
|
("Refresh", "Ανανέωση"),
|
||||||
("ID does not exist", "Το ID αυτό δεν υπάρχει"),
|
("ID does not exist", "Το αναγνωριστικό ID δεν υπάρχει"),
|
||||||
("Failed to connect to rendezvous server", "Αποτυχία σύνδεσης με τον διακομιστή"),
|
("Failed to connect to rendezvous server", "Αποτυχία σύνδεσης με διακομιστή"),
|
||||||
("Please try later", "Παρακαλώ δοκιμάστε αργότερα"),
|
("Please try later", "Παρακαλώ δοκιμάστε αργότερα"),
|
||||||
("Remote desktop is offline", "Ο απομακρυσμένος σταθμός εργασίας είναι εκτός σύνδεσης"),
|
("Remote desktop is offline", "Ο απομακρυσμένος σταθμός εργασίας είναι εκτός σύνδεσης"),
|
||||||
("Key mismatch", "Μη έγκυρο κλειδί"),
|
("Key mismatch", "Μη έγκυρο κλειδί"),
|
||||||
@@ -146,17 +146,17 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Set Password", "Ορίστε κωδικό πρόσβασης"),
|
("Set Password", "Ορίστε κωδικό πρόσβασης"),
|
||||||
("OS Password", "Κωδικός πρόσβασης λειτουργικού συστήματος"),
|
("OS Password", "Κωδικός πρόσβασης λειτουργικού συστήματος"),
|
||||||
("install_tip", "Λόγω UAC, το RustDesk ενδέχεται να μην λειτουργεί σωστά σε ορισμένες περιπτώσεις. Για να αποφύγετε το UAC, κάντε κλικ στο κουμπί παρακάτω για να εγκαταστήσετε το RustDesk στο σύστημα"),
|
("install_tip", "Λόγω UAC, το RustDesk ενδέχεται να μην λειτουργεί σωστά σε ορισμένες περιπτώσεις. Για να αποφύγετε το UAC, κάντε κλικ στο κουμπί παρακάτω για να εγκαταστήσετε το RustDesk στο σύστημα"),
|
||||||
("Click to upgrade", "Κάντε κλίκ για αναβάθμιση τώρα"),
|
("Click to upgrade", "Αναβάθμιση τώρα"),
|
||||||
("Configure", "Διαμόρφωση"),
|
("Configure", "Διαμόρφωση"),
|
||||||
("config_acc", "Για να ελέγξετε την επιφάνεια εργασίας σας από απόσταση, πρέπει να παραχωρήσετε στο RustDesk το δικαίωμα της \"Προσβασιμότητας\"."),
|
("config_acc", "Για τον απομακρυσμένο έλεγχο του υπολογιστή σας, πρέπει να εκχωρήσετε δικαιώματα πρόσβασης στο RustDesk."),
|
||||||
("config_screen", "Για να αποκτήσετε απομακρυσμένη πρόσβαση στην επιφάνεια εργασίας σας, πρέπει να παραχωρήσετε στο RustDesk το δικαίωμα της \"Εγγραφή οθόνης\"."),
|
("config_screen", "Για να αποκτήσετε απομακρυσμένη πρόσβαση στον υπολογιστή σας, πρέπει να εκχωρήσετε το δικαίωμα RustDesk \"Screen Capture\"."),
|
||||||
("Installing ...", "Γίνεται εγκατάσταση ..."),
|
("Installing ...", "Γίνεται εγκατάσταση ..."),
|
||||||
("Install", "Εγκατάσταση"),
|
("Install", "Εγκατάσταση"),
|
||||||
("Installation", "Η εγκατάσταση"),
|
("Installation", "Η εγκατάσταση"),
|
||||||
("Installation Path", "Διαδρομή εγκατάστασης"),
|
("Installation Path", "Διαδρομή εγκατάστασης"),
|
||||||
("Create start menu shortcuts", "Δημιουργία συντομεύσεων μενού έναρξης"),
|
("Create start menu shortcuts", "Δημιουργία συντομεύσεων μενού έναρξης"),
|
||||||
("Create desktop icon", "Δημιουργία εικονιδίου επιφάνειας εργασίας"),
|
("Create desktop icon", "Δημιουργία εικονιδίου επιφάνειας εργασίας"),
|
||||||
("agreement_tip", "Με την εγκατάσταση, αποδέχεστε την άδεια χρήσης"),
|
("agreement_tip", "Με την εγκατάσταση αποδέχεστε την άδεια χρήσης"),
|
||||||
("Accept and Install", "Αποδοχή και εγκατάσταση"),
|
("Accept and Install", "Αποδοχή και εγκατάσταση"),
|
||||||
("End-user license agreement", "Σύμβαση άδειας χρήσης τελικού χρήστη"),
|
("End-user license agreement", "Σύμβαση άδειας χρήσης τελικού χρήστη"),
|
||||||
("Generating ...", "Δημιουργία ..."),
|
("Generating ...", "Δημιουργία ..."),
|
||||||
@@ -170,8 +170,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Local Port", "Τοπική θύρα"),
|
("Local Port", "Τοπική θύρα"),
|
||||||
("Local Address", "Τοπική διεύθυνση"),
|
("Local Address", "Τοπική διεύθυνση"),
|
||||||
("Change Local Port", "Αλλαγή τοπικής θύρας"),
|
("Change Local Port", "Αλλαγή τοπικής θύρας"),
|
||||||
("setup_server_tip", "Για πιο γρήγορη σύνδεση, παρακαλούμε να ρυθμίστε τον δικό σας διακομιστή σύνδεσης"),
|
("setup_server_tip", "Για πιο γρήγορη σύνδεση, ρυθμίστε τον δικό σας διακομιστή σύνδεσης"),
|
||||||
("Too short, at least 6 characters.", "Πολύ μικρό, χρειάζεται τουλάχιστον 6 χαρακτήρες."),
|
("Too short, at least 6 characters.", "Πολύ μικρό, τουλάχιστον 6 χαρακτήρες."),
|
||||||
("The confirmation is not identical.", "Η επιβεβαίωση δεν είναι πανομοιότυπη."),
|
("The confirmation is not identical.", "Η επιβεβαίωση δεν είναι πανομοιότυπη."),
|
||||||
("Permissions", "Άδειες"),
|
("Permissions", "Άδειες"),
|
||||||
("Accept", "Αποδοχή"),
|
("Accept", "Αποδοχή"),
|
||||||
@@ -183,7 +183,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Relayed and encrypted connection", "Κρυπτογραφημένη σύνδεση με αναμετάδοση"),
|
("Relayed and encrypted connection", "Κρυπτογραφημένη σύνδεση με αναμετάδοση"),
|
||||||
("Direct and unencrypted connection", "Άμεση και μη κρυπτογραφημένη σύνδεση"),
|
("Direct and unencrypted connection", "Άμεση και μη κρυπτογραφημένη σύνδεση"),
|
||||||
("Relayed and unencrypted connection", "Μη κρυπτογραφημένη σύνδεση με αναμετάδοση"),
|
("Relayed and unencrypted connection", "Μη κρυπτογραφημένη σύνδεση με αναμετάδοση"),
|
||||||
("Enter Remote ID", "Εισαγωγή του απομακρυσμένου ID"),
|
("Enter Remote ID", "Εισαγωγή απομακρυσμένου ID"),
|
||||||
("Enter your password", "Εισάγετε τον κωδικό σας"),
|
("Enter your password", "Εισάγετε τον κωδικό σας"),
|
||||||
("Logging in...", "Γίνεται σύνδεση..."),
|
("Logging in...", "Γίνεται σύνδεση..."),
|
||||||
("Enable RDP session sharing", "Ενεργοποίηση κοινής χρήσης RDP"),
|
("Enable RDP session sharing", "Ενεργοποίηση κοινής χρήσης RDP"),
|
||||||
@@ -200,35 +200,35 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Login screen using Wayland is not supported", "Η οθόνη εισόδου με χρήση του Wayland δεν υποστηρίζεται"),
|
("Login screen using Wayland is not supported", "Η οθόνη εισόδου με χρήση του Wayland δεν υποστηρίζεται"),
|
||||||
("Reboot required", "Απαιτείται επανεκκίνηση"),
|
("Reboot required", "Απαιτείται επανεκκίνηση"),
|
||||||
("Unsupported display server", "Μη υποστηριζόμενος διακομιστής εμφάνισης "),
|
("Unsupported display server", "Μη υποστηριζόμενος διακομιστής εμφάνισης "),
|
||||||
("x11 expected", "αναμένεται X11"),
|
("x11 expected", "απαιτείται X11"),
|
||||||
("Port", "Θύρα"),
|
("Port", "Θύρα"),
|
||||||
("Settings", "Ρυθμίσεις"),
|
("Settings", "Ρυθμίσεις"),
|
||||||
("Username", "Όνομα χρήστη"),
|
("Username", "Όνομα χρήστη"),
|
||||||
("Invalid port", "Μη έγκυρη θύρα"),
|
("Invalid port", "Μη έγκυρη θύρα"),
|
||||||
("Closed manually by the peer", "Τερματίστηκε από τον απομακρυσμένο σταθμό"),
|
("Closed manually by the peer", "Έκλεισε από τον απομακρυσμένο σταθμό"),
|
||||||
("Enable remote configuration modification", "Ενεργοποίηση απομακρυσμένης τροποποίησης διαμόρφωσης"),
|
("Enable remote configuration modification", "Ενεργοποίηση απομακρυσμένης τροποποίησης ρυθμίσεων"),
|
||||||
("Run without install", "Εκτέλεση χωρίς εγκατάσταση"),
|
("Run without install", "Εκτέλεση χωρίς εγκατάσταση"),
|
||||||
("Connect via relay", "Σύνδεση μέσω αναμεταδότη"),
|
("Connect via relay", "Πραγματοποίηση σύνδεση μέσω αναμεταδότη"),
|
||||||
("Always connect via relay", "Να γίνεται σύνδεση πάντα μέσω αναμεταδότη"),
|
("Always connect via relay", "Σύνδεση πάντα μέσω αναμεταδότη"),
|
||||||
("whitelist_tip", "Μόνο οι IP της λίστας επιτρεπόμενων να έχουν πρόσβαση σε εμένα"),
|
("whitelist_tip", "Μόνο οι IP της λίστας επιτρεπόμενων έχουν πρόσβαση"),
|
||||||
("Login", "Σύνδεση"),
|
("Login", "Σύνδεση"),
|
||||||
("Verify", "Επαλήθευση"),
|
("Verify", "Επαλήθευση"),
|
||||||
("Remember me", "Να με θυμάσαι"),
|
("Remember me", "Να με θυμάσαι"),
|
||||||
("Trust this device", "Να εμπιστεύομαι αυτή την συσκευή"),
|
("Trust this device", "Εμπιστεύομαι αυτή την συσκευή"),
|
||||||
("Verification code", "Κωδικός επαλήθευσης"),
|
("Verification code", "Κωδικός επαλήθευσης"),
|
||||||
("verification_tip", "Ένας κωδικός επαλήθευσης έχει σταλεί στην καταχωρημένη διεύθυνση email. Εισαγάγετε τον κωδικό επαλήθευσης για να συνεχίσετε τη σύνδεση."),
|
("verification_tip", "Εντοπίστηκε νέα συσκευή και εστάλη ένας κωδικός επαλήθευσης στην καταχωρισμένη διεύθυνση email. Εισαγάγετε τον κωδικό επαλήθευσης για να συνδεθείτε ξανά."),
|
||||||
("Logout", "Αποσύνδεση"),
|
("Logout", "Αποσύνδεση"),
|
||||||
("Tags", "Ετικέτες"),
|
("Tags", "Ετικέτες"),
|
||||||
("Search ID", "Αναζήτηση ID"),
|
("Search ID", "Αναζήτηση ID"),
|
||||||
("whitelist_sep", "Διαχωρίζονται με κόμμα, ερωτηματικό, κενό ή νέα γραμμή"),
|
("whitelist_sep", "Διαχωρίζονται με κόμμα, ερωτηματικό, διάστημα ή νέα γραμμή"),
|
||||||
("Add ID", "Προσθήκη ID"),
|
("Add ID", "Προσθήκη αναγνωριστικού ID"),
|
||||||
("Add Tag", "Προσθήκη ετικέτας"),
|
("Add Tag", "Προσθήκη ετικέτας"),
|
||||||
("Unselect all tags", "Αποεπιλογή όλων των ετικετών"),
|
("Unselect all tags", "Κατάργηση επιλογής όλων των ετικετών"),
|
||||||
("Network error", "Σφάλμα δικτύου"),
|
("Network error", "Σφάλμα δικτύου"),
|
||||||
("Username missed", "Δεν συμπληρώσατε το όνομα χρήστη"),
|
("Username missed", "Δεν συμπληρώσατε το όνομα χρήστη"),
|
||||||
("Password missed", "Δεν συμπληρώσατε τον κωδικό πρόσβασης"),
|
("Password missed", "Δεν συμπληρώσατε τον κωδικό πρόσβασης"),
|
||||||
("Wrong credentials", "Λάθος διαπιστευτήρια"),
|
("Wrong credentials", "Λάθος διαπιστευτήρια"),
|
||||||
("The verification code is incorrect or has expired", "Ο κωδικός επαλήθευσης είναι λανθασμένος ή έχει λήξει"),
|
("The verification code is incorrect or has expired", ""),
|
||||||
("Edit Tag", "Επεξεργασία ετικέτας"),
|
("Edit Tag", "Επεξεργασία ετικέτας"),
|
||||||
("Forget Password", "Διαγραφή απομνημονευμένου κωδικού"),
|
("Forget Password", "Διαγραφή απομνημονευμένου κωδικού"),
|
||||||
("Favorites", "Αγαπημένα"),
|
("Favorites", "Αγαπημένα"),
|
||||||
@@ -239,7 +239,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Socks5 Proxy", "Διαμεσολαβητής Socks5"),
|
("Socks5 Proxy", "Διαμεσολαβητής Socks5"),
|
||||||
("Socks5/Http(s) Proxy", "Διαμεσολαβητής Socks5/Http(s)"),
|
("Socks5/Http(s) Proxy", "Διαμεσολαβητής Socks5/Http(s)"),
|
||||||
("Discovered", "Ανακαλύφθηκαν"),
|
("Discovered", "Ανακαλύφθηκαν"),
|
||||||
("install_daemon_tip", "Για να ξεκινά με την εκκίνηση του υπολογιστή, πρέπει να εγκαταστήσετε την υπηρεσία συστήματος."),
|
("install_daemon_tip", "Για να ξεκινά με την εκκίνηση του υπολογιστή, πρέπει να εγκαταστήσετε την υπηρεσία συστήματος"),
|
||||||
("Remote ID", "Απομακρυσμένο ID"),
|
("Remote ID", "Απομακρυσμένο ID"),
|
||||||
("Paste", "Επικόλληση"),
|
("Paste", "Επικόλληση"),
|
||||||
("Paste here?", "Επικόλληση εδώ;"),
|
("Paste here?", "Επικόλληση εδώ;"),
|
||||||
@@ -262,28 +262,28 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Pinch to Zoom", "Τσίμπημα για ζουμ"),
|
("Pinch to Zoom", "Τσίμπημα για ζουμ"),
|
||||||
("Canvas Zoom", "Ζουμ σε καμβά"),
|
("Canvas Zoom", "Ζουμ σε καμβά"),
|
||||||
("Reset canvas", "Επαναφορά καμβά"),
|
("Reset canvas", "Επαναφορά καμβά"),
|
||||||
("No permission of file transfer", "Δεν υπάρχει άδεια για την μεταφορά αρχείων"),
|
("No permission of file transfer", "Δεν υπάρχει άδεια για μεταφορά αρχείων"),
|
||||||
("Note", "Σημείωση"),
|
("Note", "Σημείωση"),
|
||||||
("Connection", "Σύνδεση"),
|
("Connection", "Σύνδεση"),
|
||||||
("Share screen", "Κοινή χρήση οθόνης"),
|
("Share screen", "Κοινή χρήση οθόνης"),
|
||||||
("Chat", "Κουβέντα"),
|
("Chat", "Κουβέντα"),
|
||||||
("Total", "Σύνολο"),
|
("Total", "Σύνολο"),
|
||||||
("items", "στοιχεία"),
|
("items", "στοιχεία"),
|
||||||
("Selected", "Επιλεγμένα"),
|
("Selected", "Επιλεγμένο"),
|
||||||
("Screen Capture", "Καταγραφή οθόνης"),
|
("Screen Capture", "Αποτύπωση οθόνης"),
|
||||||
("Input Control", "Έλεγχος εισόδου"),
|
("Input Control", "Έλεγχος εισόδου"),
|
||||||
("Audio Capture", "Εγγραφή ήχου"),
|
("Audio Capture", "Εγγραφή ήχου"),
|
||||||
("Do you accept?", "Δέχεσαι;"),
|
("Do you accept?", "Δέχεσαι;"),
|
||||||
("Open System Setting", "Άνοιγμα ρυθμίσεων συστήματος"),
|
("Open System Setting", "Άνοιγμα ρυθμίσεων συστήματος"),
|
||||||
("How to get Android input permission?", "Πώς να αποκτήσω άδεια εισόδου για Android;"),
|
("How to get Android input permission?", "Πώς να αποκτήσω άδεια εισαγωγής Android;"),
|
||||||
("android_input_permission_tip1", "Για να μπορεί μία απομακρυσμένη συσκευή να ελέγχει τη συσκευή σας Android, πρέπει να επιτρέψετε στο RustDesk να χρησιμοποιεί την υπηρεσία \"Προσβασιμότητα\"."),
|
("android_input_permission_tip1", "Για να μπορεί μία απομακρυσμένη συσκευή να ελέγχει τη συσκευή σας Android, πρέπει να επιτρέψετε στο RustDesk να χρησιμοποιεί την υπηρεσία \"Προσβασιμότητα\"."),
|
||||||
("android_input_permission_tip2", "Παρακαλούμε να μεταβείτε στην επόμενη σελίδα ρυθμίσεων συστήματος, βρείτε και πληκτρολογήστε [Εγκατεστημένες υπηρεσίες], ενεργοποιήστε την υπηρεσία [Είσοδος RustDesk]."),
|
("android_input_permission_tip2", "Παρακαλώ μεταβείτε στην επόμενη σελίδα ρυθμίσεων συστήματος, βρείτε και πληκτρολογήστε [Εγκατεστημένες υπηρεσίες], ενεργοποιήστε την υπηρεσία [Είσοδος RustDesk]."),
|
||||||
("android_new_connection_tip", "Έχει ληφθεί νέο αίτημα ελέγχου, το οποίο θέλει να ελέγξει την τρέχουσα συσκευή σας."),
|
("android_new_connection_tip", "θέλω να ελέγξω τη συσκευή σου."),
|
||||||
("android_service_will_start_tip", "Η ενεργοποίηση της \"Καταγραφής οθόνης\" θα ξεκινήσει αυτόματα την υπηρεσία, επιτρέποντας σε άλλες συσκευές να ζητήσουν σύνδεση με τη συσκευή σας."),
|
("android_service_will_start_tip", "Η ενεργοποίηση της κοινής χρήσης οθόνης θα ξεκινήσει αυτόματα την υπηρεσία, ώστε άλλες συσκευές να μπορούν να ελέγχουν αυτήν τη συσκευή Android."),
|
||||||
("android_stop_service_tip", "Το κλείσιμο της υπηρεσίας αυτής θα κλείσει αυτόματα όλες τις υπάρχουσες συνδέσεις."),
|
("android_stop_service_tip", "Η απενεργοποίηση της υπηρεσίας θα αποσυνδέσει αυτόματα όλες τις εγκατεστημένες συνδέσεις."),
|
||||||
("android_version_audio_tip", "Η τρέχουσα έκδοση Android δεν υποστηρίζει εγγραφή ήχου, αναβαθμίστε σε Android 10 ή νεότερη έκδοση."),
|
("android_version_audio_tip", "Η έκδοση Android που διαθέτετε δεν υποστηρίζει εγγραφή ήχου, ενημερώστε το σε Android 10 ή νεότερη έκδοση, εάν είναι δυνατόν."),
|
||||||
("android_start_service_tip", "Πατήστε [Έναρξη υπηρεσίας] ή ενεργοποιήστε την άδεια [Καταγραφή οθόνης] για να ξεκινήσετε την υπηρεσία κοινής χρήσης οθόνης."),
|
("android_start_service_tip", ""),
|
||||||
("android_permission_may_not_change_tip", "Τα δικαιώματα για τις καθιερωμένες συνδέσεις δεν μπορούν να αλλάξουν άμεσα μέχρι να επανασυνδεθούν."),
|
("android_permission_may_not_change_tip", ""),
|
||||||
("Account", "Λογαριασμός"),
|
("Account", "Λογαριασμός"),
|
||||||
("Overwrite", "Αντικατάσταση"),
|
("Overwrite", "Αντικατάσταση"),
|
||||||
("This file exists, skip or overwrite this file?", "Αυτό το αρχείο υπάρχει, παράβλεψη ή αντικατάσταση αυτού του αρχείου;"),
|
("This file exists, skip or overwrite this file?", "Αυτό το αρχείο υπάρχει, παράβλεψη ή αντικατάσταση αυτού του αρχείου;"),
|
||||||
@@ -293,14 +293,14 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Succeeded", "Επιτυχής"),
|
("Succeeded", "Επιτυχής"),
|
||||||
("Someone turns on privacy mode, exit", "Κάποιος ενεργοποιεί τη λειτουργία απορρήτου, έξοδος"),
|
("Someone turns on privacy mode, exit", "Κάποιος ενεργοποιεί τη λειτουργία απορρήτου, έξοδος"),
|
||||||
("Unsupported", "Δεν υποστηρίζεται"),
|
("Unsupported", "Δεν υποστηρίζεται"),
|
||||||
("Peer denied", "Ο απομακρυσμένος σταθμός έχει απορριφθεί"),
|
("Peer denied", "Ο απομακρυσμένος σταθμός απέρριψε τη σύνδεση"),
|
||||||
("Please install plugins", "Παρακαλώ εγκαταστήστε τα πρόσθετα"),
|
("Please install plugins", "Παρακαλώ εγκαταστήστε τα πρόσθετα"),
|
||||||
("Peer exit", "Ο απομακρυσμένος σταθμός έχει αποσυνδεθεί"),
|
("Peer exit", "Ο απομακρυσμένος σταθμός έχει αποσυνδεθεί"),
|
||||||
("Failed to turn off", "Αποτυχία απενεργοποίησης"),
|
("Failed to turn off", "Αποτυχία απενεργοποίησης"),
|
||||||
("Turned off", "Απενεργοποιημένο"),
|
("Turned off", "Απενεργοποιημένο"),
|
||||||
("Language", "Γλώσσα"),
|
("Language", "Γλώσσα"),
|
||||||
("Keep RustDesk background service", "Διατήρηση της υπηρεσίας παρασκηνίου του RustDesk"),
|
("Keep RustDesk background service", "Εκτέλεση του RustDesk στο παρασκήνιο"),
|
||||||
("Ignore Battery Optimizations", "Αγνόηση βελτιστοποιήσεων μπαταρίας"),
|
("Ignore Battery Optimizations", "Παράβλεψη βελτιστοποιήσεων μπαταρίας"),
|
||||||
("android_open_battery_optimizations_tip", "Θέλετε να ανοίξετε τις ρυθμίσεις βελτιστοποίησης μπαταρίας;"),
|
("android_open_battery_optimizations_tip", "Θέλετε να ανοίξετε τις ρυθμίσεις βελτιστοποίησης μπαταρίας;"),
|
||||||
("Start on boot", "Έναρξη κατά την εκκίνηση"),
|
("Start on boot", "Έναρξη κατά την εκκίνηση"),
|
||||||
("Start the screen sharing service on boot, requires special permissions", "Η έναρξη της υπηρεσίας κοινής χρήσης οθόνης κατά την εκκίνηση, απαιτεί ειδικά δικαιώματα"),
|
("Start the screen sharing service on boot, requires special permissions", "Η έναρξη της υπηρεσίας κοινής χρήσης οθόνης κατά την εκκίνηση, απαιτεί ειδικά δικαιώματα"),
|
||||||
@@ -315,11 +315,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Restart remote device", "Επανεκκίνηση απομακρυσμένης συσκευής"),
|
("Restart remote device", "Επανεκκίνηση απομακρυσμένης συσκευής"),
|
||||||
("Are you sure you want to restart", "Είστε βέβαιοι ότι θέλετε να κάνετε επανεκκίνηση"),
|
("Are you sure you want to restart", "Είστε βέβαιοι ότι θέλετε να κάνετε επανεκκίνηση"),
|
||||||
("Restarting remote device", "Γίνεται επανεκκίνηση της απομακρυσμένης συσκευής"),
|
("Restarting remote device", "Γίνεται επανεκκίνηση της απομακρυσμένης συσκευής"),
|
||||||
("remote_restarting_tip", "Γίνεται επανεκκίνηση της απομακρυσμένης συσκευής. Κλείστε αυτό το πλαίσιο μηνύματος και επανασυνδεθείτε με τον μόνιμο κωδικό πρόσβασης μετά από λίγο."),
|
("remote_restarting_tip", "Η απομακρυσμένη συσκευή επανεκκινείται, κλείστε αυτό το μήνυμα και επανασυνδεθείτε χρησιμοποιώντας τον μόνιμο κωδικό πρόσβασης."),
|
||||||
("Copied", "Αντιγράφηκε"),
|
("Copied", "Αντιγράφηκε"),
|
||||||
("Exit Fullscreen", "Έξοδος από πλήρη οθόνη"),
|
("Exit Fullscreen", "Έξοδος από πλήρη οθόνη"),
|
||||||
("Fullscreen", "Πλήρης οθόνη"),
|
("Fullscreen", "Πλήρης οθόνη"),
|
||||||
("Mobile Actions", "Ενέργειες για κινητά"),
|
("Mobile Actions", "Mobile Actions"),
|
||||||
("Select Monitor", "Επιλογή οθόνης"),
|
("Select Monitor", "Επιλογή οθόνης"),
|
||||||
("Control Actions", "Ενέργειες ελέγχου"),
|
("Control Actions", "Ενέργειες ελέγχου"),
|
||||||
("Display Settings", "Ρυθμίσεις οθόνης"),
|
("Display Settings", "Ρυθμίσεις οθόνης"),
|
||||||
@@ -347,7 +347,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Enable audio", "Ενεργοποίηση ήχου"),
|
("Enable audio", "Ενεργοποίηση ήχου"),
|
||||||
("Unlock Network Settings", "Ξεκλείδωμα ρυθμίσεων δικτύου"),
|
("Unlock Network Settings", "Ξεκλείδωμα ρυθμίσεων δικτύου"),
|
||||||
("Server", "Διακομιστής"),
|
("Server", "Διακομιστής"),
|
||||||
("Direct IP Access", "Άμεση πρόσβαση IP"),
|
("Direct IP Access", "Πρόσβαση με χρήση IP"),
|
||||||
("Proxy", "Διαμεσολαβητής"),
|
("Proxy", "Διαμεσολαβητής"),
|
||||||
("Apply", "Εφαρμογή"),
|
("Apply", "Εφαρμογή"),
|
||||||
("Disconnect all devices?", "Αποσύνδεση όλων των συσκευών;"),
|
("Disconnect all devices?", "Αποσύνδεση όλων των συσκευών;"),
|
||||||
@@ -358,7 +358,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Pin Toolbar", "Καρφίτσωμα γραμμής εργαλείων"),
|
("Pin Toolbar", "Καρφίτσωμα γραμμής εργαλείων"),
|
||||||
("Unpin Toolbar", "Ξεκαρφίτσωμα γραμμής εργαλείων"),
|
("Unpin Toolbar", "Ξεκαρφίτσωμα γραμμής εργαλείων"),
|
||||||
("Recording", "Εγγραφή"),
|
("Recording", "Εγγραφή"),
|
||||||
("Directory", "Διαδρομή"),
|
("Directory", "Φάκελος εγγραφών"),
|
||||||
("Automatically record incoming sessions", "Αυτόματη εγγραφή εισερχόμενων συνεδριών"),
|
("Automatically record incoming sessions", "Αυτόματη εγγραφή εισερχόμενων συνεδριών"),
|
||||||
("Automatically record outgoing sessions", "Αυτόματη εγγραφή εξερχόμενων συνεδριών"),
|
("Automatically record outgoing sessions", "Αυτόματη εγγραφή εξερχόμενων συνεδριών"),
|
||||||
("Change", "Αλλαγή"),
|
("Change", "Αλλαγή"),
|
||||||
@@ -373,23 +373,23 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("elevated_foreground_window_tip", "Το τρέχον παράθυρο της απομακρυσμένης επιφάνειας εργασίας απαιτεί υψηλότερα δικαιώματα για να λειτουργήσει, επομένως δεν μπορεί να χρησιμοποιήσει προσωρινά το ποντίκι και το πληκτρολόγιο. Μπορείτε να ζητήσετε από τον απομακρυσμένο χρήστη να ελαχιστοποιήσει το τρέχον παράθυρο ή να κάνετε κλικ στο κουμπί ανύψωσης στο παράθυρο διαχείρισης σύνδεσης. Για να αποφύγετε αυτό το πρόβλημα, συνιστάται η εγκατάσταση του λογισμικού στην απομακρυσμένη συσκευή."),
|
("elevated_foreground_window_tip", "Το τρέχον παράθυρο της απομακρυσμένης επιφάνειας εργασίας απαιτεί υψηλότερα δικαιώματα για να λειτουργήσει, επομένως δεν μπορεί να χρησιμοποιήσει προσωρινά το ποντίκι και το πληκτρολόγιο. Μπορείτε να ζητήσετε από τον απομακρυσμένο χρήστη να ελαχιστοποιήσει το τρέχον παράθυρο ή να κάνετε κλικ στο κουμπί ανύψωσης στο παράθυρο διαχείρισης σύνδεσης. Για να αποφύγετε αυτό το πρόβλημα, συνιστάται η εγκατάσταση του λογισμικού στην απομακρυσμένη συσκευή."),
|
||||||
("Disconnected", "Αποσυνδέθηκε"),
|
("Disconnected", "Αποσυνδέθηκε"),
|
||||||
("Other", "Άλλα"),
|
("Other", "Άλλα"),
|
||||||
("Confirm before closing multiple tabs", "Επιβεβαίωση πριν κλείσουν πολλαπλές καρτέλες"),
|
("Confirm before closing multiple tabs", "Επιβεβαίωση πριν κλείσετε πολλές καρτέλες"),
|
||||||
("Keyboard Settings", "Ρυθμίσεις πληκτρολογίου"),
|
("Keyboard Settings", "Ρυθμίσεις πληκτρολογίου"),
|
||||||
("Full Access", "Πλήρης πρόσβαση"),
|
("Full Access", "Πλήρης πρόσβαση"),
|
||||||
("Screen Share", "Κοινή χρήση οθόνης"),
|
("Screen Share", "Κοινή χρήση οθόνης"),
|
||||||
("Wayland requires Ubuntu 21.04 or higher version.", "Το Wayland απαιτεί Ubuntu 21.04 ή νεότερη έκδοση."),
|
("Wayland requires Ubuntu 21.04 or higher version.", "Το Wayland απαιτεί Ubuntu 21.04 ή νεότερη έκδοση."),
|
||||||
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Το Wayland απαιτεί υψηλότερη έκδοση διανομής του linux. Δοκιμάστε την επιφάνεια εργασίας X11 ή αλλάξτε το λειτουργικό σας σύστημα."),
|
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Το Wayland απαιτεί υψηλότερη έκδοση του linux distro. Δοκιμάστε την επιφάνεια εργασίας X11 ή αλλάξτε το λειτουργικό σας σύστημα."),
|
||||||
("JumpLink", "Σύνδεσμος μετάβασης"),
|
("JumpLink", "Προβολή"),
|
||||||
("Please Select the screen to be shared(Operate on the peer side).", "Επιλέξτε την οθόνη που θέλετε να μοιραστείτε (Λειτουργία στην πλευρά του απομακρυσμένου σταθμού)."),
|
("Please Select the screen to be shared(Operate on the peer side).", "Επιλέξτε την οθόνη που θέλετε να μοιραστείτε (Λειτουργία στην πλευρά του απομακρυσμένου σταθμού)."),
|
||||||
("Show RustDesk", "Εμφάνιση του RustDesk"),
|
("Show RustDesk", "Εμφάνιση RustDesk"),
|
||||||
("This PC", "Αυτός ο υπολογιστής"),
|
("This PC", "Αυτός ο υπολογιστής"),
|
||||||
("or", "ή"),
|
("or", "ή"),
|
||||||
("Elevate", "Ανύψωση"),
|
("Elevate", "Ανύψωση"),
|
||||||
("Zoom cursor", "Δρομέας ζουμ"),
|
("Zoom cursor", "Kέρσορας μεγέθυνσης"),
|
||||||
("Accept sessions via password", "Αποδοχή συνεδριών με κωδικό πρόσβασης"),
|
("Accept sessions via password", "Αποδοχή συνεδριών με κωδικό πρόσβασης"),
|
||||||
("Accept sessions via click", "Αποδοχή συνεδριών με κλικ"),
|
("Accept sessions via click", "Αποδοχή συνεδριών με κλικ"),
|
||||||
("Accept sessions via both", "Αποδοχή συνεδριών και με τα δύο"),
|
("Accept sessions via both", "Αποδοχή συνεδριών και με τα δύο"),
|
||||||
("Please wait for the remote side to accept your session request...", "Παρακαλώ περιμένετε μέχρι η απομακρυσμένη πλευρά να αποδεχτεί το αίτημα της συνεδρίας σας..."),
|
("Please wait for the remote side to accept your session request...", "Παρακαλώ περιμένετε μέχρι η απομακρυσμένη πλευρά να αποδεχτεί το αίτημα συνεδρίας σας..."),
|
||||||
("One-time Password", "Κωδικός μίας χρήσης"),
|
("One-time Password", "Κωδικός μίας χρήσης"),
|
||||||
("Use one-time password", "Χρήση κωδικού πρόσβασης μίας χρήσης"),
|
("Use one-time password", "Χρήση κωδικού πρόσβασης μίας χρήσης"),
|
||||||
("One-time password length", "Μήκος κωδικού πρόσβασης μίας χρήσης"),
|
("One-time password length", "Μήκος κωδικού πρόσβασης μίας χρήσης"),
|
||||||
@@ -398,27 +398,27 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("hide_cm_tip", "Να επιτρέπεται η απόκρυψη, μόνο εάν αποδέχεστε συνδέσεις μέσω κωδικού πρόσβασης και χρησιμοποιείτε μόνιμο κωδικό πρόσβασης"),
|
("hide_cm_tip", "Να επιτρέπεται η απόκρυψη, μόνο εάν αποδέχεστε συνδέσεις μέσω κωδικού πρόσβασης και χρησιμοποιείτε μόνιμο κωδικό πρόσβασης"),
|
||||||
("wayland_experiment_tip", "Η υποστήριξη Wayland βρίσκεται σε πειραματικό στάδιο, χρησιμοποιήστε το X11 εάν χρειάζεστε πρόσβαση χωρίς επίβλεψη."),
|
("wayland_experiment_tip", "Η υποστήριξη Wayland βρίσκεται σε πειραματικό στάδιο, χρησιμοποιήστε το X11 εάν χρειάζεστε πρόσβαση χωρίς επίβλεψη."),
|
||||||
("Right click to select tabs", "Κάντε δεξί κλικ για να επιλέξετε καρτέλες"),
|
("Right click to select tabs", "Κάντε δεξί κλικ για να επιλέξετε καρτέλες"),
|
||||||
("Skipped", "Παραλήφθηκε"),
|
("Skipped", "Παράλειψη"),
|
||||||
("Add to address book", "Προσθήκη στο βιβλίο διευθύνσεων"),
|
("Add to address book", "Προσθήκη στο Βιβλίο Διευθύνσεων"),
|
||||||
("Group", "Ομάδα"),
|
("Group", "Ομάδα"),
|
||||||
("Search", "Αναζήτηση"),
|
("Search", "Αναζήτηση"),
|
||||||
("Closed manually by web console", "Κλείσιμο χειροκίνητα από την κονσόλα ιστού"),
|
("Closed manually by web console", "Κλειστό χειροκίνητα από την κονσόλα web"),
|
||||||
("Local keyboard type", "Τύπος τοπικού πληκτρολογίου"),
|
("Local keyboard type", "Τύπος τοπικού πληκτρολογίου"),
|
||||||
("Select local keyboard type", "Επιλογή τύπου τοπικού πληκτρολογίου"),
|
("Select local keyboard type", "Επιλογή τύπου τοπικού πληκτρολογίου"),
|
||||||
("software_render_tip", "Εάν χρησιμοποιείτε κάρτα γραφικών της Nvidia σε Linux και το παράθυρο απομακρυσμένης πρόσβασης κλείνει αμέσως μετά τη σύνδεση, η μετάβαση στο πρόγραμμα οδήγησης της Nouveau ανοιχτού κώδικα και η επιλογή χρήσης απόδοσης λογισμικού μπορεί να βοηθήσει. Απαιτείται επανεκκίνηση του λογισμικού."),
|
("software_render_tip", "Εάν έχετε κάρτα γραφικών Nvidia και το παράθυρο σύνδεσης κλείνει αμέσως μετά τη σύνδεση, η εγκατάσταση του προγράμματος οδήγησης nouveau και η επιλογή χρήσης της επιτάχυνσης γραφικών μέσω λογισμικού μπορεί να βοηθήσει. Απαιτείται επανεκκίνηση."),
|
||||||
("Always use software rendering", "Να χρησιμοποιείτε πάντα η απόδοση λογισμικού"),
|
("Always use software rendering", "Επιτάχυνση γραφικών μέσω λογισμικού"),
|
||||||
("config_input", "Για να ελέγξετε την απομακρυσμένη επιφάνεια εργασίας με το πληκτρολόγιο, πρέπει να παραχωρήσετε στο RustDesk το δικαίωμα της \"Παρακολούθηση εισόδου\"."),
|
("config_input", "Για να ελέγξετε την απομακρυσμένη επιφάνεια εργασίας με πληκτρολόγιο, πρέπει να εκχωρήσετε δικαιώματα στο RustDesk"),
|
||||||
("config_microphone", "Για να μιλήσετε εξ αποστάσεως, πρέπει να παραχωρήσετε στο RustDesk το δικαίωμα της \"Εγγραφή ήχου\"."),
|
("config_microphone", "Ρύθμιση μικροφώνου"),
|
||||||
("request_elevation_tip", "Μπορείτε επίσης να ζητήσετε ανύψωση εάν υπάρχει κάποιος στην απομακρυσμένη πλευρά."),
|
("request_elevation_tip", "αίτημα ανύψωσης δικαιωμάτων χρήστη"),
|
||||||
("Wait", "Περιμένετε"),
|
("Wait", "Περιμένετε"),
|
||||||
("Elevation Error", "Σφάλμα ανύψωσης"),
|
("Elevation Error", "Σφάλμα ανύψωσης δικαιωμάτων χρήστη"),
|
||||||
("Ask the remote user for authentication", "Ζητήστε από τον απομακρυσμένο χρήστη έλεγχο ταυτότητας"),
|
("Ask the remote user for authentication", "Ζητήστε από τον απομακρυσμένο χρήστη έλεγχο ταυτότητας"),
|
||||||
("Choose this if the remote account is administrator", "Επιλέξτε αυτό εάν ο απομακρυσμένος λογαριασμός είναι διαχειριστής"),
|
("Choose this if the remote account is administrator", "Επιλέξτε αυτό εάν ο απομακρυσμένος λογαριασμός είναι διαχειριστής"),
|
||||||
("Transmit the username and password of administrator", "Μεταδώστε το όνομα χρήστη και τον κωδικό πρόσβασης του διαχειριστή"),
|
("Transmit the username and password of administrator", "Αποστολή του ονόματος χρήστη και του κωδικού πρόσβασης του διαχειριστή"),
|
||||||
("still_click_uac_tip", "Εξακολουθεί να απαιτεί από τον απομακρυσμένο χρήστη να κάνει κλικ στο πλήκτρο Εντάξει στο παράθυρο UAC όπου εκτελείται το RustDesk."),
|
("still_click_uac_tip", "Εξακολουθεί να απαιτεί από τον απομακρυσμένο χρήστη να κάνει κλικ στο OK στο παράθυρο UAC όπου εκτελείται το RustDesk."),
|
||||||
("Request Elevation", "Αίτημα ανύψωσης"),
|
("Request Elevation", "Αίτημα ανύψωσης δικαιωμάτων χρήστη"),
|
||||||
("wait_accept_uac_tip", "Περιμένετε μέχρι ο απομακρυσμένος χρήστης να αποδεχτεί το παράθυρο διαλόγου UAC."),
|
("wait_accept_uac_tip", "Περιμένετε να αποδεχτεί ο απομακρυσμένος χρήστης το παράθυρο διαλόγου UAC."),
|
||||||
("Elevate successfully", "Επιτυχής ανύψωση"),
|
("Elevate successfully", "Επιτυχής ανύψωση δικαιωμάτων χρήστη"),
|
||||||
("uppercase", "κεφαλαία γράμματα"),
|
("uppercase", "κεφαλαία γράμματα"),
|
||||||
("lowercase", "πεζά γράμματα"),
|
("lowercase", "πεζά γράμματα"),
|
||||||
("digit", "αριθμός"),
|
("digit", "αριθμός"),
|
||||||
@@ -427,7 +427,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Weak", "Αδύναμο"),
|
("Weak", "Αδύναμο"),
|
||||||
("Medium", "Μέτριο"),
|
("Medium", "Μέτριο"),
|
||||||
("Strong", "Δυνατό"),
|
("Strong", "Δυνατό"),
|
||||||
("Switch Sides", "Αλλαγή πλευρών"),
|
("Switch Sides", "Εναλλαγή πλευράς"),
|
||||||
("Please confirm if you want to share your desktop?", "Παρακαλώ επιβεβαιώστε αν επιθυμείτε την κοινή χρήση της επιφάνειας εργασίας;"),
|
("Please confirm if you want to share your desktop?", "Παρακαλώ επιβεβαιώστε αν επιθυμείτε την κοινή χρήση της επιφάνειας εργασίας;"),
|
||||||
("Display", "Εμφάνιση"),
|
("Display", "Εμφάνιση"),
|
||||||
("Default View Style", "Προκαθορισμένος τρόπος εμφάνισης"),
|
("Default View Style", "Προκαθορισμένος τρόπος εμφάνισης"),
|
||||||
@@ -441,11 +441,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Voice call", "Φωνητική κλήση"),
|
("Voice call", "Φωνητική κλήση"),
|
||||||
("Text chat", "Συνομιλία κειμένου"),
|
("Text chat", "Συνομιλία κειμένου"),
|
||||||
("Stop voice call", "Διακοπή φωνητικής κλήσης"),
|
("Stop voice call", "Διακοπή φωνητικής κλήσης"),
|
||||||
("relay_hint_tip", "Ενδέχεται να μην είναι δυνατή η απευθείας σύνδεση: μπορείτε να δοκιμάσετε να συνδεθείτε μέσω αναμετάδοσης. Επιπλέον, εάν θέλετε να χρησιμοποιήσετε την αναμετάδοση στην πρώτη σας προσπάθεια, μπορείτε να προσθέσετε την \"/r\" κατάληξη στο ID ή να επιλέξετε την επιλογή \"Πάντα σύνδεση μέσω αναμετάδοσης\" στην κάρτα πρόσφατων συνεδριών, εάν υπάρχει."),
|
("relay_hint_tip", "Εάν δεν είναι δυνατή η απευθείας σύνδεση, μπορείτε να δοκιμάσετε να συνδεθείτε μέσω διακομιστή αναμετάδοσης"),
|
||||||
("Reconnect", "Επανασύνδεση"),
|
("Reconnect", "Επανασύνδεση"),
|
||||||
("Codec", "Κωδικοποίηση"),
|
("Codec", "Κωδικοποίηση"),
|
||||||
("Resolution", "Ανάλυση"),
|
("Resolution", "Ανάλυση"),
|
||||||
("No transfers in progress", "Δεν υπάρχουν μεταφορές σε εξέλιξη"),
|
("No transfers in progress", "Δεν υπάρχει μεταφορά σε εξέλιξη"),
|
||||||
("Set one-time password length", "Μέγεθος κωδικού μιας χρήσης"),
|
("Set one-time password length", "Μέγεθος κωδικού μιας χρήσης"),
|
||||||
("RDP Settings", "Ρυθμίσεις RDP"),
|
("RDP Settings", "Ρυθμίσεις RDP"),
|
||||||
("Sort by", "Ταξινόμηση κατά"),
|
("Sort by", "Ταξινόμηση κατά"),
|
||||||
@@ -454,35 +454,35 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Minimize", "Ελαχιστοποίηση"),
|
("Minimize", "Ελαχιστοποίηση"),
|
||||||
("Maximize", "Μεγιστοποίηση"),
|
("Maximize", "Μεγιστοποίηση"),
|
||||||
("Your Device", "Η συσκευή σας"),
|
("Your Device", "Η συσκευή σας"),
|
||||||
("empty_recent_tip", "Ωχ, δεν υπάρχουν πρόσφατες συνεδρίες!\nΏρα να προγραμματίσετε μια νέα."),
|
("empty_recent_tip", "Δεν υπάρχουν πρόσφατες συνεδρίες!\nΔοκιμάστε να ξεκινήσετε μια νέα."),
|
||||||
("empty_favorite_tip", "Δεν έχετε ακόμα αγαπημένους απομακρυσμένους σταθμούς;\nΑς βρούμε κάποιον για να συνδεθούμε και ας τον προσθέσουμε στα αγαπημένα σας!"),
|
("empty_favorite_tip", "Δεν υπάρχουν ακόμη αγαπημένες συνδέσεις;\nΑφού πραγματοποιήσετε σύνδεση με κάποιο απομακρυσμένο σταθμό, μπορείτε να τον προσθέσετε στα αγαπημένα σας!"),
|
||||||
("empty_lan_tip", "Ωχ όχι, φαίνεται ότι δεν έχουμε ανακαλύψει ακόμη κανέναν απομακρυσμένο σταθμό."),
|
("empty_lan_tip", "Δεν έχουμε ανακαλυφθεί ακόμη απομακρυσμένοι σταθμοί."),
|
||||||
("empty_address_book_tip", "Ω, Αγαπητέ/ή μου, φαίνεται ότι αυτήν τη στιγμή δεν υπάρχουν απομακρυσμένοι σταθμοί στο βιβλίο διευθύνσεών σας."),
|
("empty_address_book_tip", "Φαίνεται ότι αυτή τη στιγμή δεν υπάρχουν αγαπημένες συνδέσεις στο βιβλίο διευθύνσεών σας."),
|
||||||
("Empty Username", "Κενό όνομα χρήστη"),
|
("Empty Username", "Κενό όνομα χρήστη"),
|
||||||
("Empty Password", "Κενός κωδικός πρόσβασης"),
|
("Empty Password", "Κενός κωδικός πρόσβασης"),
|
||||||
("Me", "Εγώ"),
|
("Me", "Εγώ"),
|
||||||
("identical_file_tip", "Αυτό το αρχείο είναι πανομοιότυπο με αυτό του απομακρυσμένου σταθμού."),
|
("identical_file_tip", "Το αρχείο είναι πανομοιότυπο με αυτό του άλλου υπολογιστή."),
|
||||||
("show_monitors_tip", "Εμφάνιση οθονών στη γραμμή εργαλείων"),
|
("show_monitors_tip", "Εμφάνιση οθονών στη γραμμή εργαλείων"),
|
||||||
("View Mode", "Λειτουργία προβολής"),
|
("View Mode", "Λειτουργία προβολής"),
|
||||||
("login_linux_tip", "Πρέπει να συνδεθείτε σε έναν απομακρυσμένο λογαριασμό Linux για να ενεργοποιήσετε μια συνεδρία επιφάνειας εργασίας X"),
|
("login_linux_tip", "Απαιτείται είσοδος σε απομακρυσμένο λογαριασμό Linux για την ενεργοποίηση του περιβάλλον εργασίας Χ."),
|
||||||
("verify_rustdesk_password_tip", "Επιβεβαιώστε τον κωδικό του RustDesk"),
|
("verify_rustdesk_password_tip", "Επιβεβαιώστε τον κωδικό του RustDesk"),
|
||||||
("remember_account_tip", "Απομνημόνευση αυτού του λογαριασμού"),
|
("remember_account_tip", "Απομνημόνευση αυτού του λογαριασμού"),
|
||||||
("os_account_desk_tip", "Αυτός ο λογαριασμός χρησιμοποιείται για σύνδεση στο απομακρυσμένο λειτουργικό σύστημα και ενεργοποίηση της συνεδρίας επιφάνειας εργασίας σε headless"),
|
("os_account_desk_tip", "Αυτός ο λογαριασμός θα χρησιμοποιηθεί για την είσοδο και διαχείριση του απομακρυσμένου λειτουργικού συστήματος"),
|
||||||
("OS Account", "Λογαριασμός λειτουργικού συστήματος"),
|
("OS Account", "Λογαριασμός λειτουργικού συστήματος"),
|
||||||
("another_user_login_title_tip", "Υπάρχει ήδη άλλος συνδεδεμένος χρήστης"),
|
("another_user_login_title_tip", "Υπάρχει ήδη άλλος συνδεδεμένος χρήστης"),
|
||||||
("another_user_login_text_tip", "Αποσύνδεση"),
|
("another_user_login_text_tip", "Αποσύνδεση"),
|
||||||
("xorg_not_found_title_tip", "Δεν βρέθηκε το Xorg"),
|
("xorg_not_found_title_tip", "Δεν βρέθηκε το Xorg"),
|
||||||
("xorg_not_found_text_tip", "Παρακαλώ εγκαταστήστε το Xorg"),
|
("xorg_not_found_text_tip", "Παρακαλώ εγκαταστήστε το Xorg"),
|
||||||
("no_desktop_title_tip", "Δεν υπάρχει διαθέσιμο περιβάλλον επιφάνειας εργασίας"),
|
("no_desktop_title_tip", "Δεν υπάρχει διαθέσιμη επιφάνεια εργασίας"),
|
||||||
("no_desktop_text_tip", "Παρακαλώ εγκαταστήστε το περιβάλλον GNOME"),
|
("no_desktop_text_tip", "Παρακαλώ εγκαταστήστε το περιβάλλον GNOME"),
|
||||||
("No need to elevate", "Δεν χρειάζεται ανύψωση"),
|
("No need to elevate", "Δεν χρειάζονται αυξημένα δικαιώματα"),
|
||||||
("System Sound", "Ήχος συστήματος"),
|
("System Sound", "Ήχος συστήματος"),
|
||||||
("Default", "Προκαθορισμένο"),
|
("Default", "Προκαθορισμένο"),
|
||||||
("New RDP", "Νέα RDP"),
|
("New RDP", "Νέα απομακρυσμένη σύνδεση"),
|
||||||
("Fingerprint", "Δακτυλικό αποτύπωμα"),
|
("Fingerprint", ""),
|
||||||
("Copy Fingerprint", "Αντιγραφή δακτυλικού αποτυπώματος"),
|
("Copy Fingerprint", ""),
|
||||||
("no fingerprints", "χωρίς δακτυλικά αποτυπώματα"),
|
("no fingerprints", ""),
|
||||||
("Select a peer", "Επιλέξτε έναν σταθμό"),
|
("Select a peer", "Επιλέξτε σταθμό"),
|
||||||
("Select peers", "Επιλέξτε σταθμούς"),
|
("Select peers", "Επιλέξτε σταθμούς"),
|
||||||
("Plugins", "Επεκτάσεις"),
|
("Plugins", "Επεκτάσεις"),
|
||||||
("Uninstall", "Κατάργηση εγκατάστασης"),
|
("Uninstall", "Κατάργηση εγκατάστασης"),
|
||||||
@@ -493,10 +493,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("resolution_original_tip", "Αρχική ανάλυση"),
|
("resolution_original_tip", "Αρχική ανάλυση"),
|
||||||
("resolution_fit_local_tip", "Προσαρμογή στην τοπική ανάλυση"),
|
("resolution_fit_local_tip", "Προσαρμογή στην τοπική ανάλυση"),
|
||||||
("resolution_custom_tip", "Προσαρμοσμένη ανάλυση"),
|
("resolution_custom_tip", "Προσαρμοσμένη ανάλυση"),
|
||||||
("Collapse toolbar", "Σύμπτυξη γραμμής εργαλείων"),
|
("Collapse toolbar", "Εμφάνιση γραμμής εργαλείων"),
|
||||||
("Accept and Elevate", "Αποδοχή και ανύψωση"),
|
("Accept and Elevate", "Αποδοχή με αυξημένα δικαιώματα"),
|
||||||
("accept_and_elevate_btn_tooltip", "Αποδεχτείτε τη σύνδεση και ανυψώστε τα δικαιώματα UAC."),
|
("accept_and_elevate_btn_tooltip", "Αποδοχή της σύνδεσης με αυξημένα δικαιώματα χρήστη"),
|
||||||
("clipboard_wait_response_timeout_tip", "Λήξη χρονικού ορίου αναμονής για απάντηση αντιγραφής."),
|
("clipboard_wait_response_timeout_tip", "Έληξε ο χρόνος αναμονής για την ανταπόκριση της αντιγραφής"),
|
||||||
("Incoming connection", "Εισερχόμενη σύνδεση"),
|
("Incoming connection", "Εισερχόμενη σύνδεση"),
|
||||||
("Outgoing connection", "Εξερχόμενη σύνδεση"),
|
("Outgoing connection", "Εξερχόμενη σύνδεση"),
|
||||||
("Exit", "Έξοδος"),
|
("Exit", "Έξοδος"),
|
||||||
@@ -505,7 +505,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Service", "Υπηρεσία"),
|
("Service", "Υπηρεσία"),
|
||||||
("Start", "Έναρξη"),
|
("Start", "Έναρξη"),
|
||||||
("Stop", "Διακοπή"),
|
("Stop", "Διακοπή"),
|
||||||
("exceed_max_devices", "Έχετε φτάσει τον μέγιστο αριθμό διαχειριζόμενων συσκευών."),
|
("exceed_max_devices", "Υπέρβαση μέγιστου ορίου αποθηκευμένων συνδέσεων"),
|
||||||
("Sync with recent sessions", "Συγχρονισμός των πρόσφατων συνεδριών"),
|
("Sync with recent sessions", "Συγχρονισμός των πρόσφατων συνεδριών"),
|
||||||
("Sort tags", "Ταξινόμηση ετικετών"),
|
("Sort tags", "Ταξινόμηση ετικετών"),
|
||||||
("Open connection in new tab", "Άνοιγμα σύνδεσης σε νέα καρτέλα"),
|
("Open connection in new tab", "Άνοιγμα σύνδεσης σε νέα καρτέλα"),
|
||||||
@@ -514,14 +514,14 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Already exists", "Υπάρχει ήδη"),
|
("Already exists", "Υπάρχει ήδη"),
|
||||||
("Change Password", "Αλλαγή κωδικού"),
|
("Change Password", "Αλλαγή κωδικού"),
|
||||||
("Refresh Password", "Ανανέωση κωδικού"),
|
("Refresh Password", "Ανανέωση κωδικού"),
|
||||||
("ID", "ID"),
|
("ID", ""),
|
||||||
("Grid View", "Προβολή σε πλακίδια"),
|
("Grid View", "Προβολή σε πλακίδια"),
|
||||||
("List View", "Προβολή σε λίστα"),
|
("List View", "Προβολή σε λίστα"),
|
||||||
("Select", "Επιλογή"),
|
("Select", "Επιλογή"),
|
||||||
("Toggle Tags", "Εναλλαγή ετικετών"),
|
("Toggle Tags", "Εναλλαγή ετικετών"),
|
||||||
("pull_ab_failed_tip", "Η ανανέωση του βιβλίου διευθύνσεων απέτυχε"),
|
("pull_ab_failed_tip", "Αποτυχία ανανέωσης βιβλίου διευθύνσεων"),
|
||||||
("push_ab_failed_tip", "Αποτυχία συγχρονισμού του βιβλίου διευθύνσεων με τον διακομιστή"),
|
("push_ab_failed_tip", "Αποτυχία συγχρονισμού βιβλίου διευθύνσεων"),
|
||||||
("synced_peer_readded_tip", "Οι συσκευές που υπήρχαν στις πρόσφατες συνεδρίες θα συγχρονιστούν ξανά με το βιβλίο διευθύνσεων."),
|
("synced_peer_readded_tip", "Οι συσκευές των τρεχουσών συνεδριών θα συγχρονιστούν με το βιβλίο διευθύνσεων"),
|
||||||
("Change Color", "Αλλαγή χρώματος"),
|
("Change Color", "Αλλαγή χρώματος"),
|
||||||
("Primary Color", "Κυρίως χρώμα"),
|
("Primary Color", "Κυρίως χρώμα"),
|
||||||
("HSV Color", "Χρώμα HSV"),
|
("HSV Color", "Χρώμα HSV"),
|
||||||
@@ -536,31 +536,31 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("I Agree", "Συμφωνώ"),
|
("I Agree", "Συμφωνώ"),
|
||||||
("Decline", "Διαφωνώ"),
|
("Decline", "Διαφωνώ"),
|
||||||
("Timeout in minutes", "Τέλος χρόνου σε λεπτά"),
|
("Timeout in minutes", "Τέλος χρόνου σε λεπτά"),
|
||||||
("auto_disconnect_option_tip", "Αυτόματο κλείσιμο εισερχόμενων συνεδριών σε περίπτωση αδράνειας χρήστη"),
|
("auto_disconnect_option_tip", "Αυτόματη αποσύνδεση απομακρυσμένης συνεδρίας έπειτα από την πάροδο του χρονικού ορίου αδράνειας "),
|
||||||
("Connection failed due to inactivity", "Η σύνδεση τερματίστηκε έπειτα από την πάροδο του χρόνου αδράνειας"),
|
("Connection failed due to inactivity", "Η σύνδεση τερματίστηκε έπειτα από την πάροδο του χρόνου αδράνειας"),
|
||||||
("Check for software update on startup", "Έλεγχος για ενημερώσεις κατά την εκκίνηση"),
|
("Check for software update on startup", "Έλεγχος για ενημερώσεις κατα την εκκίνηση"),
|
||||||
("upgrade_rustdesk_server_pro_to_{}_tip", "Παρακαλώ ενημερώστε το RustDesk Server Pro στην έκδοση {} ή νεότερη!"),
|
("upgrade_rustdesk_server_pro_to_{}_tip", "Παρακαλώ ενημερώστε τον RustDesk Server Pro στην έκδοση {} ή νεότερη!"),
|
||||||
("pull_group_failed_tip", "Αποτυχία ανανέωσης της ομάδας"),
|
("pull_group_failed_tip", "Αποτυχία ανανέωσης της ομάδας"),
|
||||||
("Filter by intersection", "Φιλτράρισμα κατά διασταύρωση"),
|
("Filter by intersection", ""),
|
||||||
("Remove wallpaper during incoming sessions", "Αφαίρεση εικόνας φόντου στις εισερχόμενες συνδέσεις"),
|
("Remove wallpaper during incoming sessions", "Αφαίρεση εικόνας φόντου στις εισερχόμενες συνδέσεις"),
|
||||||
("Test", "Δοκιμή"),
|
("Test", "Δοκιμή"),
|
||||||
("display_is_plugged_out_msg", "Η οθόνη είναι αποσυνδεδεμένη από την πρίζα, μεταβείτε στην πρώτη οθόνη."),
|
("display_is_plugged_out_msg", "Η οθόνη έχει αποσυνδεθεί, επιστρέψτε στην κύρια οθόνη προβολής"),
|
||||||
("No displays", "Δεν υπάρχουν οθόνες"),
|
("No displays", "Δεν υπάρχουν οθόνες"),
|
||||||
("Open in new window", "Άνοιγμα σε νέο παράθυρο"),
|
("Open in new window", "Άνοιγμα σε νέο παράθυρο"),
|
||||||
("Show displays as individual windows", "Εμφάνιση οθονών σε ξεχωριστά παράθυρα"),
|
("Show displays as individual windows", "Εμφάνιση οθονών σε ξεχωριστά παράθυρα"),
|
||||||
("Use all my displays for the remote session", "Χρήση όλων των οθονών της απομακρυσμένης σύνδεσης"),
|
("Use all my displays for the remote session", "Χρήση όλων των οθονών της απομακρυσμένης σύνδεσης"),
|
||||||
("selinux_tip", "Το SELinux είναι ενεργοποιημένο στη συσκευή σας, κάτι που ενδέχεται να εμποδίσει την σωστή λειτουργία του RustDesk ως ελεγχόμενης πλευράς."),
|
("selinux_tip", "Έχετε ενεργοποιημένο το SELinux, το οποίο πιθανόν εμποδίζει την ορθή λειτουργία του RustDesk."),
|
||||||
("Change view", "Αλλαγή απεικόνισης"),
|
("Change view", "Αλλαγή απεικόνισης"),
|
||||||
("Big tiles", "Μεγάλα εικονίδια"),
|
("Big tiles", "Μεγάλα εικονίδια"),
|
||||||
("Small tiles", "Μικρά εικονίδια"),
|
("Small tiles", "Μικρά εικονίδια"),
|
||||||
("List", "Λίστα"),
|
("List", "Λίστα"),
|
||||||
("Virtual display", "Εινονική οθόνη"),
|
("Virtual display", "Εινονική οθόνη"),
|
||||||
("Plug out all", "Αποσύνδεση όλων"),
|
("Plug out all", "Αποσύνδεση όλων"),
|
||||||
("True color (4:4:4)", "Αληθινό χρώμα (4:4:4)"),
|
("True color (4:4:4)", ""),
|
||||||
("Enable blocking user input", "Ενεργοποίηση αποκλεισμού χειρισμού από τον χρήστη"),
|
("Enable blocking user input", "Ενεργοποίηση αποκλεισμού χειρισμού από τον χρήστη"),
|
||||||
("id_input_tip", "Μπορείτε να εισάγετε ένα ID, μια διεύθυνση IP, ή ένα όνομα τομέα με την αντίστοιχη πόρτα (<domain>:<port>).\nΑν θέλετε να συνδεθείτε σε μια συσκευή σε άλλο διακομιστή, παρακαλώ να προσθέσετε και την διεύθυνση του διακομιστή (<id>@<server_address>?key=<key_value>), για παράδειγμα,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nΑν θέλετε να συνδεθείτε σε κάποιο δημόσιο διακομιστή, προσθέστε το όνομά του \"<id>@public\", η παράμετρος key δεν απαιτείται για τους δημόσιους διακομιστές."),
|
("id_input_tip", "Μπορείτε να εισάγετε ενα ID, μια διεύθυνση IP, ή ένα όνομα τομέα με την αντίστοιχη πόρτα (<domain>:<port>).\nΑν θέλετε να συνδεθείτε σε μια συσκευή σε άλλο διακομιστή, παρακαλώ να προσθέσετε και την διεύθυνση του διακομιστή (<id>@<server_address>?key=<key_value>), για παράδειγμα,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nΑν θέλετε να συνδεθείτε σε κάποιο δημόσιο διακομιστή, προσθέστε το όνομά του \"<id>@public\", η παράμετρος key δεν απαιτείται για τους δημόσιους διακομιστές."),
|
||||||
("privacy_mode_impl_mag_tip", "Λειτουργία 1"),
|
("privacy_mode_impl_mag_tip", "Προφύλαξη Οθόνης"),
|
||||||
("privacy_mode_impl_virtual_display_tip", "Λειτουργία 2"),
|
("privacy_mode_impl_virtual_display_tip", "Εικονική Οθόνη"),
|
||||||
("Enter privacy mode", "Ενεργοποίηση λειτουργίας απορρήτου"),
|
("Enter privacy mode", "Ενεργοποίηση λειτουργίας απορρήτου"),
|
||||||
("Exit privacy mode", "Διακοπή λειτουργίας απορρήτου"),
|
("Exit privacy mode", "Διακοπή λειτουργίας απορρήτου"),
|
||||||
("idd_not_support_under_win10_2004_tip", "Το πρόγραμμα οδήγησης έμμεσης οθόνης δεν υποστηρίζεται. Απαιτείτε λειτουργικό σύστημα Windows 10 έκδοση 2004 ή νεότερο."),
|
("idd_not_support_under_win10_2004_tip", "Το πρόγραμμα οδήγησης έμμεσης οθόνης δεν υποστηρίζεται. Απαιτείτε λειτουργικό σύστημα Windows 10 έκδοση 2004 ή νεότερο."),
|
||||||
@@ -570,26 +570,26 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("swap-left-right-mouse", "Εναλλαγή αριστερό-δεξί κουμπί του ποντικιού"),
|
("swap-left-right-mouse", "Εναλλαγή αριστερό-δεξί κουμπί του ποντικιού"),
|
||||||
("2FA code", "κωδικός 2FA"),
|
("2FA code", "κωδικός 2FA"),
|
||||||
("More", "Περισσότερα"),
|
("More", "Περισσότερα"),
|
||||||
("enable-2fa-title", "Ενεργοποίηση πιστοποίησης δύο παραγόντων"),
|
("enable-2fa-title", "Ενεργοποίηση Πιστοποίησης Δύο Παραγόντων"),
|
||||||
("enable-2fa-desc", "Παρακαλούμε να ρυθμίστε τώρα τον έλεγχο ταυτότητας. Μπορείτε να χρησιμοποιήσετε μια εφαρμογή ελέγχου ταυτότητας όπως το Authy, το Microsoft ή το Google Authenticator στο τηλέφωνο ή τον υπολογιστή σας.\n\nΣαρώστε τον κωδικό QR με την εφαρμογή σας και εισαγάγετε τον κωδικό που εμφανίζει η εφαρμογή σας για να ενεργοποιήσετε τον έλεγχο ταυτότητας δύο παραγόντων."),
|
("enable-2fa-desc", "Ρυθμίστε τον έλεγχο ταυτότητας τώρα. Μπορείτε να χρησιμοποιήσετε μια εφαρμογή ελέγχου ταυτότητας όπως Authy, Microsoft ή Google Authenticator στο τηλέφωνο ή στην επιφάνεια εργασίας σας.Σαρώστε τον κωδικό QR με την εφαρμογή σας και εισαγάγετε τον κωδικό που εμφανίζει η εφαρμογή σας για να ενεργοποιήσετε τον έλεγχο ταυτότητας δύο παραγόντων."),
|
||||||
("wrong-2fa-code", "Δεν είναι δυνατή η επαλήθευση του κωδικού. Ελέγξτε ότι οι ρυθμίσεις κωδικού και τοπικής ώρας είναι σωστές."),
|
("wrong-2fa-code", "Δεν είναι δυνατή η επαλήθευση του κωδικού. Ελέγξτε ότι ο κωδικός και οι ρυθμίσεις τοπικής ώρας είναι σωστές"),
|
||||||
("enter-2fa-title", "Έλεγχος ταυτότητας δύο παραγόντων"),
|
("enter-2fa-title", "Έλεγχος ταυτότητας δύο παραγόντων"),
|
||||||
("Email verification code must be 6 characters.", "Ο κωδικός επαλήθευσης email πρέπει να είναι έως 6 χαρακτήρες"),
|
("Email verification code must be 6 characters.", "Ο κωδικός επαλήθευσης email πρέπει να είναι εως 6 χαρακτήρες"),
|
||||||
("2FA code must be 6 digits.", "Ο κωδικός 2FA πρέπει να είναι 6ψήφιος."),
|
("2FA code must be 6 digits.", "Ο κωδικός 2FA πρέπει να είναι 6ψήφιος."),
|
||||||
("Multiple Windows sessions found", "Βρέθηκαν πολλές συνεδρίες των Windows"),
|
("Multiple Windows sessions found", ""),
|
||||||
("Please select the session you want to connect to", "Επιλέξτε τη συνεδρία στην οποία θέλετε να συνδεθείτε"),
|
("Please select the session you want to connect to", "Επιλέξτε τη συνεδρία στην οποία θέλετε να συνδεθείτε"),
|
||||||
("powered_by_me", "Με την υποστήριξη του RustDesk"),
|
("powered_by_me", "Με την υποστήριξη της RustDesk"),
|
||||||
("outgoing_only_desk_tip", "Αυτή είναι μια προσαρμοσμένη έκδοση.\nΜπορείτε να συνδεθείτε με άλλες συσκευές, αλλά άλλες συσκευές δεν μπορούν να συνδεθούν με τη δική σας συσκευή."),
|
("outgoing_only_desk_tip", ""),
|
||||||
("preset_password_warning", "Αυτή η προσαρμοσμένη έκδοση συνοδεύεται από έναν προκαθορισμένο κωδικό πρόσβασης. Όποιος γνωρίζει αυτόν τον κωδικό πρόσβασης θα μπορούσε να αποκτήσει τον πλήρη έλεγχο της συσκευής σας. Εάν δεν το περιμένατε αυτό, απεγκαταστήστε αμέσως το λογισμικό."),
|
("preset_password_warning", "προειδοποίηση προκαθορισμένου κωδικού πρόσβασης"),
|
||||||
("Security Alert", "Ειδοποίηση ασφαλείας"),
|
("Security Alert", "Ειδοποίηση ασφαλείας"),
|
||||||
("My address book", "Το βιβλίο διευθύνσεών μου"),
|
("My address book", "Το βιβλίο διευθύνσεών μου"),
|
||||||
("Personal", "Προσωπικό"),
|
("Personal", "Προσωπικό"),
|
||||||
("Owner", "Ιδιοκτήτης"),
|
("Owner", "Ιδιοκτήτης"),
|
||||||
("Set shared password", "Ορίστε έναν κοινόχρηστο κωδικό πρόσβασης"),
|
("Set shared password", "Ορίστε κοινόχρηστο κωδικό πρόσβασης"),
|
||||||
("Exist in", "Υπάρχει στο"),
|
("Exist in", "Υπάρχει στο"),
|
||||||
("Read-only", "Μόνο για ανάγνωση"),
|
("Read-only", "Μόνο για ανάγνωση"),
|
||||||
("Read/Write", "Ανάγνωση/Εγγραφή"),
|
("Read/Write", "Ανάγνωση/Εγγραφή"),
|
||||||
("Full Control", "Πλήρης έλεγχος"),
|
("Full Control", "Πλήρης Έλεγχος"),
|
||||||
("share_warning_tip", "Τα παραπάνω πεδία είναι κοινόχρηστα και ορατά σε άλλους."),
|
("share_warning_tip", "Τα παραπάνω πεδία είναι κοινόχρηστα και ορατά σε άλλους."),
|
||||||
("Everyone", "Όλοι"),
|
("Everyone", "Όλοι"),
|
||||||
("ab_web_console_tip", "Περισσότερα στην κονσόλα web"),
|
("ab_web_console_tip", "Περισσότερα στην κονσόλα web"),
|
||||||
@@ -597,18 +597,18 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("no_need_privacy_mode_no_physical_displays_tip", "Δεν υπάρχουν φυσικές οθόνες, δεν χρειάζεται να χρησιμοποιήσετε τη λειτουργία απορρήτου."),
|
("no_need_privacy_mode_no_physical_displays_tip", "Δεν υπάρχουν φυσικές οθόνες, δεν χρειάζεται να χρησιμοποιήσετε τη λειτουργία απορρήτου."),
|
||||||
("Follow remote cursor", "Παρακολούθηση απομακρυσμένου κέρσορα"),
|
("Follow remote cursor", "Παρακολούθηση απομακρυσμένου κέρσορα"),
|
||||||
("Follow remote window focus", "Παρακολούθηση απομακρυσμένου ενεργού παραθύρου"),
|
("Follow remote window focus", "Παρακολούθηση απομακρυσμένου ενεργού παραθύρου"),
|
||||||
("default_proxy_tip", "Το προεπιλεγμένο πρωτόκολλο και η θύρα είναι Socks5 και 1080"),
|
("default_proxy_tip", "Προκαθορισμένο πρωτόκολλο Socks5 στην πόρτα 1080"),
|
||||||
("no_audio_input_device_tip", "Δεν βρέθηκε συσκευή εισόδου ήχου."),
|
("no_audio_input_device_tip", "Δεν βρέθηκε συσκευή εισόδου ήχου."),
|
||||||
("Incoming", "Εισερχόμενη"),
|
("Incoming", "Εισερχόμενη"),
|
||||||
("Outgoing", "Εξερχόμενη"),
|
("Outgoing", "Εξερχόμενη"),
|
||||||
("Clear Wayland screen selection", "Εκκαθάριση επιλογής οθόνης Wayland"),
|
("Clear Wayland screen selection", ""),
|
||||||
("clear_Wayland_screen_selection_tip", "Αφού διαγράψετε την επιλογή οθόνης, μπορείτε να επιλέξετε ξανά την οθόνη για κοινή χρήση."),
|
("clear_Wayland_screen_selection_tip", ""),
|
||||||
("confirm_clear_Wayland_screen_selection_tip", "Είστε βέβαιοι ότι θέλετε να διαγράψετε την επιλογή οθόνης Wayland;"),
|
("confirm_clear_Wayland_screen_selection_tip", ""),
|
||||||
("android_new_voice_call_tip", "Ελήφθη ένα νέο αίτημα φωνητικής κλήσης. Εάν το αποδεχτείτε, ο ήχος θα μεταβεί σε φωνητική επικοινωνία."),
|
("android_new_voice_call_tip", ""),
|
||||||
("texture_render_tip", "Χρησιμοποιήστε την απόδοση υφής για να κάνετε τις εικόνες πιο ομαλές. Μπορείτε να δοκιμάσετε να απενεργοποιήσετε αυτήν την επιλογή εάν αντιμετωπίσετε προβλήματα απόδοσης."),
|
("texture_render_tip", ""),
|
||||||
("Use texture rendering", "Χρήση απόδοσης υφής"),
|
("Use texture rendering", ""),
|
||||||
("Floating window", "Πλωτό παράθυρο"),
|
("Floating window", ""),
|
||||||
("floating_window_tip", "Βοηθά στη διατήρηση της υπηρεσίας παρασκηνίου RustDesk"),
|
("floating_window_tip", ""),
|
||||||
("Keep screen on", "Διατήρηση οθόνης Ανοιχτή"),
|
("Keep screen on", "Διατήρηση οθόνης Ανοιχτή"),
|
||||||
("Never", "Ποτέ"),
|
("Never", "Ποτέ"),
|
||||||
("During controlled", "Κατα την διάρκεια απομακρυσμένου ελέγχου"),
|
("During controlled", "Κατα την διάρκεια απομακρυσμένου ελέγχου"),
|
||||||
@@ -618,8 +618,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Apps", "Εφαρμογές"),
|
("Apps", "Εφαρμογές"),
|
||||||
("Volume up", "Αύξηση έντασης"),
|
("Volume up", "Αύξηση έντασης"),
|
||||||
("Volume down", "Μείωση έντασης"),
|
("Volume down", "Μείωση έντασης"),
|
||||||
("Power", "Ενέργεια"),
|
("Power", ""),
|
||||||
("Telegram bot", "Telegram bot"),
|
("Telegram bot", ""),
|
||||||
("enable-bot-tip", "Εάν ενεργοποιήσετε αυτήν τη δυνατότητα, μπορείτε να λάβετε τον κωδικό 2FA από το bot σας. Μπορεί επίσης να λειτουργήσει ως ειδοποίηση σύνδεσης."),
|
("enable-bot-tip", "Εάν ενεργοποιήσετε αυτήν τη δυνατότητα, μπορείτε να λάβετε τον κωδικό 2FA από το bot σας. Μπορεί επίσης να λειτουργήσει ως ειδοποίηση σύνδεσης."),
|
||||||
("enable-bot-desc", "1, Ανοίξτε μια συνομιλία με τον @BotFather., Στείλτε την εντολή \"/newbot\". Θα λάβετε ένα διακριτικό αφού ολοκληρώσετε αυτό το βήμα.3, Ξεκινήστε μια συνομιλία με το bot που μόλις δημιουργήσατε. Στείλτε ένα μήνυμα που αρχίζει με κάθετο (\"/\") όπως \"/hello\" για να το ενεργοποιήσετε."),
|
("enable-bot-desc", "1, Ανοίξτε μια συνομιλία με τον @BotFather., Στείλτε την εντολή \"/newbot\". Θα λάβετε ένα διακριτικό αφού ολοκληρώσετε αυτό το βήμα.3, Ξεκινήστε μια συνομιλία με το bot που μόλις δημιουργήσατε. Στείλτε ένα μήνυμα που αρχίζει με κάθετο (\"/\") όπως \"/hello\" για να το ενεργοποιήσετε."),
|
||||||
("cancel-2fa-confirm-tip", "Είστε βέβαιοι ότι θέλετε να ακυρώσετε το 2FA;"),
|
("cancel-2fa-confirm-tip", "Είστε βέβαιοι ότι θέλετε να ακυρώσετε το 2FA;"),
|
||||||
@@ -639,11 +639,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Parent directory", "Γονικός φάκελος"),
|
("Parent directory", "Γονικός φάκελος"),
|
||||||
("Resume", "Συνέχεια"),
|
("Resume", "Συνέχεια"),
|
||||||
("Invalid file name", "Μη έγκυρο όνομα αρχείου"),
|
("Invalid file name", "Μη έγκυρο όνομα αρχείου"),
|
||||||
("one-way-file-transfer-tip", "Η μονόδρομη μεταφορά αρχείων είναι ενεργοποιημένη στην ελεγχόμενη πλευρά."),
|
("one-way-file-transfer-tip", ""),
|
||||||
("Authentication Required", "Απαιτείται έλεγχος ταυτότητας"),
|
("Authentication Required", "Απαιτείται έλεγχος ταυτότητας"),
|
||||||
("Authenticate", "Πιστοποίηση"),
|
("Authenticate", "Πιστοποίηση"),
|
||||||
("web_id_input_tip", "Μπορείτε να εισαγάγετε ένα ID στον ίδιο διακομιστή, η άμεση πρόσβαση IP δεν υποστηρίζεται στον web client.\nΕάν θέλετε να αποκτήσετε πρόσβαση σε μια συσκευή σε άλλον διακομιστή, παρακαλούμε να προσθέστε τη διεύθυνση διακομιστή (<id>@<server_address>?key=<key_value>), για παράδειγμα,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nΕάν θέλετε να αποκτήσετε πρόσβαση σε μια συσκευή σε δημόσιο διακομιστή, παρακαλούμε να εισαγάγετε \"<id>@public\". Το κλειδί δεν είναι απαραίτητο για δημόσιο διακομιστή."),
|
("web_id_input_tip", ""),
|
||||||
("Download", "Λήψη"),
|
("Download", ""),
|
||||||
("Upload folder", "Μεταφόρτωση φακέλου"),
|
("Upload folder", "Μεταφόρτωση φακέλου"),
|
||||||
("Upload files", "Μεταφόρτωση αρχείων"),
|
("Upload files", "Μεταφόρτωση αρχείων"),
|
||||||
("Clipboard is synchronized", "Το πρόχειρο έχει συγχρονιστεί"),
|
("Clipboard is synchronized", "Το πρόχειρο έχει συγχρονιστεί"),
|
||||||
@@ -652,93 +652,93 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("new-version-of-{}-tip", "Υπάρχει διαθέσιμη νέα έκδοση του {}"),
|
("new-version-of-{}-tip", "Υπάρχει διαθέσιμη νέα έκδοση του {}"),
|
||||||
("Accessible devices", "Προσβάσιμες συσκευές"),
|
("Accessible devices", "Προσβάσιμες συσκευές"),
|
||||||
("upgrade_remote_rustdesk_client_to_{}_tip", "Αναβαθμίστε τον πελάτη RustDesk στην έκδοση {} ή νεότερη στην απομακρυσμένη πλευρά!"),
|
("upgrade_remote_rustdesk_client_to_{}_tip", "Αναβαθμίστε τον πελάτη RustDesk στην έκδοση {} ή νεότερη στην απομακρυσμένη πλευρά!"),
|
||||||
("d3d_render_tip", "Όταν είναι ενεργοποιημένη η απόδοση D3D, η οθόνη του τηλεχειριστηρίου ενδέχεται να είναι μαύρη σε ορισμένα μηχανήματα."),
|
("d3d_render_tip", ""),
|
||||||
("Use D3D rendering", "Χρήση απόδοσης D3D"),
|
("Use D3D rendering", ""),
|
||||||
("Printer", "Εκτυπωτής"),
|
("Printer", ""),
|
||||||
("printer-os-requirement-tip", "Η λειτουργία εξερχόμενης εκτύπωσης του εκτυπωτή απαιτεί Windows 10 ή νεότερη έκδοση."),
|
("printer-os-requirement-tip", ""),
|
||||||
("printer-requires-installed-{}-client-tip", "Για να χρησιμοποιήσετε την απομακρυσμένη εκτύπωση, πρέπει να εγκατασταθεί το {} σε αυτήν τη συσκευή."),
|
("printer-requires-installed-{}-client-tip", ""),
|
||||||
("printer-{}-not-installed-tip", "Ο εκτυπωτής {} δεν είναι εγκατεστημένος."),
|
("printer-{}-not-installed-tip", ""),
|
||||||
("printer-{}-ready-tip", "Ο εκτυπωτής {} είναι εγκατεστημένος και έτοιμος για χρήση."),
|
("printer-{}-ready-tip", ""),
|
||||||
("Install {} Printer", "Εγκατάσταση εκτυπωτή {}"),
|
("Install {} Printer", ""),
|
||||||
("Outgoing Print Jobs", "Εξερχόμενες εργασίες εκτύπωσης"),
|
("Outgoing Print Jobs", ""),
|
||||||
("Incoming Print Jobs", "Εισερχόμενες εργασίες εκτύπωσης"),
|
("Incoming Print Jobs", ""),
|
||||||
("Incoming Print Job", "Εισερχόμενη εργασία εκτύπωσης"),
|
("Incoming Print Job", ""),
|
||||||
("use-the-default-printer-tip", "Χρήση του προεπιλεγμένου εκτυπωτή"),
|
("use-the-default-printer-tip", ""),
|
||||||
("use-the-selected-printer-tip", "Χρήση του επιλεγμένου εκτυπωτή"),
|
("use-the-selected-printer-tip", ""),
|
||||||
("auto-print-tip", "Εκτυπώστε αυτόματα χρησιμοποιώντας τον επιλεγμένο εκτυπωτή."),
|
("auto-print-tip", ""),
|
||||||
("print-incoming-job-confirm-tip", "Λάβατε μια εργασία εκτύπωσης από απόσταση. Θέλετε να την εκτελέσετε από την πλευρά σας;"),
|
("print-incoming-job-confirm-tip", ""),
|
||||||
("remote-printing-disallowed-tile-tip", "Η απομακρυσμένη εκτύπωση δεν επιτρέπεται"),
|
("remote-printing-disallowed-tile-tip", ""),
|
||||||
("remote-printing-disallowed-text-tip", "Οι ρυθμίσεις δικαιωμάτων της ελεγχόμενης πλευράς απαγορεύουν την Απομακρυσμένη Εκτύπωση."),
|
("remote-printing-disallowed-text-tip", ""),
|
||||||
("save-settings-tip", "Αποθήκευση ρυθμίσεων"),
|
("save-settings-tip", ""),
|
||||||
("dont-show-again-tip", "Να μην εμφανιστεί ξανά αυτό"),
|
("dont-show-again-tip", ""),
|
||||||
("Take screenshot", "Λήψη στιγμιότυπου οθόνης"),
|
("Take screenshot", ""),
|
||||||
("Taking screenshot", "Γίνεται λήψη στιγμιότυπου οθόνης"),
|
("Taking screenshot", ""),
|
||||||
("screenshot-merged-screen-not-supported-tip", "Η συγχώνευση στιγμιότυπων οθόνης από πολλές οθόνες δεν υποστηρίζεται προς το παρόν. Αλλάξτε σε μία μόνο οθόνη και δοκιμάστε ξανά."),
|
("screenshot-merged-screen-not-supported-tip", ""),
|
||||||
("screenshot-action-tip", "Επιλέξτε πώς θα συνεχίσετε με το στιγμιότυπο οθόνης."),
|
("screenshot-action-tip", ""),
|
||||||
("Save as", "Αποθήκευση ως"),
|
("Save as", ""),
|
||||||
("Copy to clipboard", "Αντιγραφή στο πρόχειρο"),
|
("Copy to clipboard", ""),
|
||||||
("Enable remote printer", "Ενεργοποίηση απομακρυσμένου εκτυπωτή"),
|
("Enable remote printer", ""),
|
||||||
("Downloading {}", "Γίνεται Λήψη {}"),
|
("Downloading {}", ""),
|
||||||
("{} Update", "{} Ενημέρωση"),
|
("{} Update", ""),
|
||||||
("{}-to-update-tip", "Το {} θα κλείσει τώρα και θα εγκαταστήσει τη νέα έκδοση."),
|
("{}-to-update-tip", ""),
|
||||||
("download-new-version-failed-tip", "Η λήψη απέτυχε. Μπορείτε να δοκιμάσετε ξανά ή να κάνετε κλικ στο κουμπί \"Λήψη\" για να κάνετε λήψη από τη σελίδα έκδοσης και να κάνετε αναβάθμιση χειροκίνητα."),
|
("download-new-version-failed-tip", ""),
|
||||||
("Auto update", "Αυτόματη ενημέρωση"),
|
("Auto update", ""),
|
||||||
("update-failed-check-msi-tip", "Η μέθοδος εγκατάστασης απέτυχε. Κάντε κλικ στο κουμπί \"Λήψη\" για λήψη από τη σελίδα έκδοσης και κάντε χειροκίνητα την αναβάθμιση."),
|
("update-failed-check-msi-tip", ""),
|
||||||
("websocket_tip", "Όταν χρησιμοποιείτε το WebSocket, υποστηρίζονται μόνο συνδέσεις αναμετάδοσης."),
|
("websocket_tip", ""),
|
||||||
("Use WebSocket", "Χρήση WebSocket"),
|
("Use WebSocket", ""),
|
||||||
("Trackpad speed", "Ταχύτητα trackpad"),
|
("Trackpad speed", ""),
|
||||||
("Default trackpad speed", "Προεπιλεγμένη ταχύτητα trackpad"),
|
("Default trackpad speed", ""),
|
||||||
("Numeric one-time password", "Αριθμητικός κωδικός πρόσβασης μίας χρήσης"),
|
("Numeric one-time password", ""),
|
||||||
("Enable IPv6 P2P connection", "Ενεργοποίηση σύνδεσης IPv6 P2P"),
|
("Enable IPv6 P2P connection", ""),
|
||||||
("Enable UDP hole punching", "Ενεργοποίηση διάτρησης οπών UDP"),
|
("Enable UDP hole punching", ""),
|
||||||
("View camera", "Προβολή κάμερας"),
|
("View camera", "Προβολή κάμερας"),
|
||||||
("Enable camera", "Ενεργοποίηση κάμερας"),
|
("Enable camera", ""),
|
||||||
("No cameras", "Δεν υπάρχουν κάμερες"),
|
("No cameras", ""),
|
||||||
("view_camera_unsupported_tip", "Η τηλεχειριστήριο δεν υποστηρίζει την προβολή της κάμερας."),
|
("view_camera_unsupported_tip", ""),
|
||||||
("Terminal", "Τερματικό"),
|
("Terminal", ""),
|
||||||
("Enable terminal", "Ενεργοποίηση τερματικού"),
|
("Enable terminal", ""),
|
||||||
("New tab", "Νέα καρτέλα"),
|
("New tab", ""),
|
||||||
("Keep terminal sessions on disconnect", "Διατήρηση περιόδων λειτουργίας τερματικού κατά την αποσύνδεση"),
|
("Keep terminal sessions on disconnect", ""),
|
||||||
("Terminal (Run as administrator)", "Τερματικό (Εκτέλεση ως διαχειριστής)"),
|
("Terminal (Run as administrator)", ""),
|
||||||
("terminal-admin-login-tip", "Παρακαλώ εισάγετε το όνομα χρήστη και τον κωδικό πρόσβασης διαχειριστή της ελεγχόμενης πλευράς."),
|
("terminal-admin-login-tip", ""),
|
||||||
("Failed to get user token.", "Αποτυχία λήψης διακριτικού χρήστη."),
|
("Failed to get user token.", ""),
|
||||||
("Incorrect username or password.", "Λανθασμένο όνομα χρήστη ή κωδικός πρόσβασης."),
|
("Incorrect username or password.", ""),
|
||||||
("The user is not an administrator.", "Ο χρήστης δεν είναι διαχειριστής."),
|
("The user is not an administrator.", ""),
|
||||||
("Failed to check if the user is an administrator.", "Αποτυχία ελέγχου εάν ο χρήστης είναι διαχειριστής."),
|
("Failed to check if the user is an administrator.", ""),
|
||||||
("Supported only in the installed version.", "Υποστηρίζεται μόνο στην εγκατεστημένη έκδοση."),
|
("Supported only in the installed version.", ""),
|
||||||
("elevation_username_tip", "Εισαγάγετε όνομα χρήστη ή τομέα\\όνομα χρήστη"),
|
("elevation_username_tip", ""),
|
||||||
("Preparing for installation ...", "Προετοιμασία για εγκατάσταση..."),
|
("Preparing for installation ...", ""),
|
||||||
("Show my cursor", "Εμφάνιση του κέρσορα μου"),
|
("Show my cursor", ""),
|
||||||
("Scale custom", "Προσαρμοσμένη κλίμακα"),
|
("Scale custom", ""),
|
||||||
("Custom scale slider", "Ρυθμιστικό προσαρμοσμένης κλίμακας"),
|
("Custom scale slider", ""),
|
||||||
("Decrease", "Μείωση"),
|
("Decrease", ""),
|
||||||
("Increase", "Αύξηση"),
|
("Increase", ""),
|
||||||
("Show virtual mouse", "Εμφάνιση εικονικού ποντικιού"),
|
("Show virtual mouse", ""),
|
||||||
("Virtual mouse size", "Μέγεθος εικονικού ποντικιού"),
|
("Virtual mouse size", ""),
|
||||||
("Small", "Μικρό"),
|
("Small", ""),
|
||||||
("Large", "Μεγάλο"),
|
("Large", ""),
|
||||||
("Show virtual joystick", "Εμφάνιση εικονικού joystick"),
|
("Show virtual joystick", ""),
|
||||||
("Edit note", "Επεξεργασία σημείωσης"),
|
("Edit note", ""),
|
||||||
("Alias", "Ψευδώνυμο"),
|
("Alias", ""),
|
||||||
("ScrollEdge", "Άκρη κύλισης"),
|
("ScrollEdge", ""),
|
||||||
("Allow insecure TLS fallback", "Να επιτρέπεται η μη ασφαλής εφεδρική λειτουργία TLS"),
|
("Allow insecure TLS fallback", ""),
|
||||||
("allow-insecure-tls-fallback-tip", "Από προεπιλογή, το RustDesk επαληθεύει το πιστοποιητικό διακομιστή για πρωτόκολλα που χρησιμοποιούν TLS.\nΜε ενεργοποιημένη αυτήν την επιλογή, το RustDesk θα παρακάμψει το βήμα επαλήθευσης και θα προχωρήσει σε περίπτωση αποτυχίας επαλήθευσης."),
|
("allow-insecure-tls-fallback-tip", ""),
|
||||||
("Disable UDP", "Απενεργοποίηση UDP"),
|
("Disable UDP", ""),
|
||||||
("disable-udp-tip", "Ελέγχει εάν θα χρησιμοποιείται μόνο TCP.\nΌταν είναι ενεργοποιημένη αυτή η επιλογή, το RustDesk δεν θα χρησιμοποιεί πλέον το UDP 21116, αλλά θα χρησιμοποιείται το TCP 21116."),
|
("disable-udp-tip", ""),
|
||||||
("server-oss-not-support-tip", "ΣΗΜΕΙΩΣΗ: Το OSS του διακομιστή RustDesk δεν περιλαμβάνει αυτήν τη λειτουργία."),
|
("server-oss-not-support-tip", ""),
|
||||||
("input note here", "εισάγετε σημείωση εδώ"),
|
("input note here", ""),
|
||||||
("note-at-conn-end-tip", "Ζητήστε σημείωση στο τέλος της σύνδεσης"),
|
("note-at-conn-end-tip", ""),
|
||||||
("Show terminal extra keys", "Εμφάνιση επιπλέον κλειδιών τερματικού"),
|
("Show terminal extra keys", ""),
|
||||||
("Relative mouse mode", "Σχετική λειτουργία ποντικιού"),
|
("Relative mouse mode", ""),
|
||||||
("rel-mouse-not-supported-peer-tip", "Η λειτουργία σχετικού ποντικιού δεν υποστηρίζεται από τον συνδεδεμένο ομότιμο υπολογιστή."),
|
("rel-mouse-not-supported-peer-tip", ""),
|
||||||
("rel-mouse-not-ready-tip", "Η λειτουργία σχετικού ποντικιού δεν είναι ακόμη έτοιμη. Δοκιμάστε ξανά."),
|
("rel-mouse-not-ready-tip", ""),
|
||||||
("rel-mouse-lock-failed-tip", "Αποτυχία κλειδώματος δρομέα. Η λειτουργία σχετικού ποντικιού έχει απενεργοποιηθεί."),
|
("rel-mouse-lock-failed-tip", ""),
|
||||||
("rel-mouse-exit-{}-tip", "Πιέστε {} για έξοδο."),
|
("rel-mouse-exit-{}-tip", ""),
|
||||||
("rel-mouse-permission-lost-tip", "Η άδεια πληκτρολογίου ανακλήθηκε. Η λειτουργία σχετικού ποντικιού απενεργοποιήθηκε."),
|
("rel-mouse-permission-lost-tip", ""),
|
||||||
("Changelog", "Αρχείο αλλαγών"),
|
("Changelog", ""),
|
||||||
("keep-awake-during-outgoing-sessions-label", "Διατήρηση ενεργής οθόνης κατά τη διάρκεια εξερχόμενων συνεδριών"),
|
("keep-awake-during-outgoing-sessions-label", ""),
|
||||||
("keep-awake-during-incoming-sessions-label", "Διατήρηση ενεργής οθόνης κατά τη διάρκεια των εισερχόμενων συνεδριών"),
|
("keep-awake-during-incoming-sessions-label", ""),
|
||||||
("Continue with {}", "Συνέχεια με {}"),
|
("Continue with {}", "Συνέχεια με {}"),
|
||||||
("Display Name", "Εμφανιζόμενο όνομα"),
|
("Display Name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -313,7 +313,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Set permanent password", "Définir le mot de passe permanent"),
|
("Set permanent password", "Définir le mot de passe permanent"),
|
||||||
("Enable remote restart", "Activer le redémarrage à distance"),
|
("Enable remote restart", "Activer le redémarrage à distance"),
|
||||||
("Restart remote device", "Redémarrer l’appareil distant"),
|
("Restart remote device", "Redémarrer l’appareil distant"),
|
||||||
("Are you sure you want to restart", "Voulez-vous vraiment redémarrer"),
|
("Are you sure you want to restart", "Voulez-vous vraiment redémarrer l’appareil ?"),
|
||||||
("Restarting remote device", "Redémarrage de l’appareil distant"),
|
("Restarting remote device", "Redémarrage de l’appareil distant"),
|
||||||
("remote_restarting_tip", "L'appareil distant redémarre ; veuillez fermer cette boîte de dialogue et vous reconnecter en utilisant le mot de passe permanent dans quelques instants"),
|
("remote_restarting_tip", "L'appareil distant redémarre ; veuillez fermer cette boîte de dialogue et vous reconnecter en utilisant le mot de passe permanent dans quelques instants"),
|
||||||
("Copied", "Copié"),
|
("Copied", "Copié"),
|
||||||
@@ -739,6 +739,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("keep-awake-during-outgoing-sessions-label", "Maintenir l’écran allumé lors des sessions sortantes"),
|
("keep-awake-during-outgoing-sessions-label", "Maintenir l’écran allumé lors des sessions sortantes"),
|
||||||
("keep-awake-during-incoming-sessions-label", "Maintenir l’écran allumé lors des sessions entrantes"),
|
("keep-awake-during-incoming-sessions-label", "Maintenir l’écran allumé lors des sessions entrantes"),
|
||||||
("Continue with {}", "Continuer avec {}"),
|
("Continue with {}", "Continuer avec {}"),
|
||||||
("Display Name", "Nom d’affichage"),
|
("Display Name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Password", "Jelszó"),
|
("Password", "Jelszó"),
|
||||||
("Ready", "Kész"),
|
("Ready", "Kész"),
|
||||||
("Established", "Létrejött"),
|
("Established", "Létrejött"),
|
||||||
("connecting_status", "Kapcsolódás folyamatban ..."),
|
("connecting_status", "Kapcsolódás folyamatban…"),
|
||||||
("Enable service", "Szolgáltatás engedélyezése"),
|
("Enable service", "Szolgáltatás engedélyezése"),
|
||||||
("Start service", "Szolgáltatás indítása"),
|
("Start service", "Szolgáltatás indítása"),
|
||||||
("Service is running", "Szolgáltatás aktív"),
|
("Service is running", "Szolgáltatás aktív"),
|
||||||
@@ -28,7 +28,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Enable file transfer", "Fájlátvitel engedélyezése"),
|
("Enable file transfer", "Fájlátvitel engedélyezése"),
|
||||||
("Enable TCP tunneling", "TCP-alagút engedélyezése"),
|
("Enable TCP tunneling", "TCP-alagút engedélyezése"),
|
||||||
("IP Whitelisting", "IP engedélyezési lista"),
|
("IP Whitelisting", "IP engedélyezési lista"),
|
||||||
("ID/Relay Server", "ID/Továbbító-kiszolgáló"),
|
("ID/Relay Server", "Azonosító-/Továbbító-kiszolgáló"),
|
||||||
("Import server config", "Kiszolgáló-konfiguráció importálása"),
|
("Import server config", "Kiszolgáló-konfiguráció importálása"),
|
||||||
("Export Server Config", "Kiszolgáló-konfiguráció exportálása"),
|
("Export Server Config", "Kiszolgáló-konfiguráció exportálása"),
|
||||||
("Import server configuration successfully", "Kiszolgáló-konfiguráció sikeresen importálva"),
|
("Import server configuration successfully", "Kiszolgáló-konfiguráció sikeresen importálva"),
|
||||||
@@ -54,7 +54,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Enhancements", "Fejlesztések"),
|
("Enhancements", "Fejlesztések"),
|
||||||
("Hardware Codec", "Hardveres kodek"),
|
("Hardware Codec", "Hardveres kodek"),
|
||||||
("Adaptive bitrate", "Adaptív bitráta"),
|
("Adaptive bitrate", "Adaptív bitráta"),
|
||||||
("ID Server", "ID-kiszolgáló"),
|
("ID Server", "Azonosító-kiszolgáló"),
|
||||||
("Relay Server", "Továbbító-kiszolgáló"),
|
("Relay Server", "Továbbító-kiszolgáló"),
|
||||||
("API Server", "API-kiszolgáló"),
|
("API Server", "API-kiszolgáló"),
|
||||||
("invalid_http", "A címnek mindenképpen http(s)://-el kell kezdődnie."),
|
("invalid_http", "A címnek mindenképpen http(s)://-el kell kezdődnie."),
|
||||||
@@ -76,12 +76,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Connection Error", "Kapcsolódási hiba"),
|
("Connection Error", "Kapcsolódási hiba"),
|
||||||
("Error", "Hiba"),
|
("Error", "Hiba"),
|
||||||
("Reset by the peer", "A kapcsolatot a másik fél lezárta."),
|
("Reset by the peer", "A kapcsolatot a másik fél lezárta."),
|
||||||
("Connecting...", "Kapcsolódás..."),
|
("Connecting...", "Kapcsolódás…"),
|
||||||
("Connection in progress. Please wait.", "A kapcsolódás folyamatban van. Kis türelmet ..."),
|
("Connection in progress. Please wait.", "A kapcsolódás folyamatban van. Kis türelmet…"),
|
||||||
("Please try 1 minute later", "Próbálja meg 1 perc múlva"),
|
("Please try 1 minute later", "Próbálja meg 1 perc múlva"),
|
||||||
("Login Error", "Bejelentkezési hiba"),
|
("Login Error", "Bejelentkezési hiba"),
|
||||||
("Successful", "Sikeres"),
|
("Successful", "Sikeres"),
|
||||||
("Connected, waiting for image...", "Kapcsolódva, várakozás a képadatokra..."),
|
("Connected, waiting for image...", "Kapcsolódva, várakozás a képadatokra…"),
|
||||||
("Name", "Név"),
|
("Name", "Név"),
|
||||||
("Type", "Típus"),
|
("Type", "Típus"),
|
||||||
("Modified", "Módosított"),
|
("Modified", "Módosított"),
|
||||||
@@ -127,7 +127,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Optimize reaction time", "Gyorsan reagáló"),
|
("Optimize reaction time", "Gyorsan reagáló"),
|
||||||
("Custom", "Egyéni"),
|
("Custom", "Egyéni"),
|
||||||
("Show remote cursor", "Távoli kurzor megjelenítése"),
|
("Show remote cursor", "Távoli kurzor megjelenítése"),
|
||||||
("Show quality monitor", "Kijelző minőségének ellenőrzése"),
|
("Show quality monitor", "Kapcsolat minőségének megjelenítése"),
|
||||||
("Disable clipboard", "Közös vágólap kikapcsolása"),
|
("Disable clipboard", "Közös vágólap kikapcsolása"),
|
||||||
("Lock after session end", "Távoli fiók zárolása a munkamenet végén"),
|
("Lock after session end", "Távoli fiók zárolása a munkamenet végén"),
|
||||||
("Insert Ctrl + Alt + Del", "Illessze be a Ctrl + Alt + Del billentyűzetkombinációt"),
|
("Insert Ctrl + Alt + Del", "Illessze be a Ctrl + Alt + Del billentyűzetkombinációt"),
|
||||||
@@ -150,8 +150,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Configure", "Beállítás"),
|
("Configure", "Beállítás"),
|
||||||
("config_acc", "A számítógép távoli vezérléséhez a RustDesknek hozzáférési jogokat kell adnia."),
|
("config_acc", "A számítógép távoli vezérléséhez a RustDesknek hozzáférési jogokat kell adnia."),
|
||||||
("config_screen", "Ahhoz, hogy távolról hozzáférhessen a számítógépéhez, meg kell adnia a RustDesknek a \"Képernyőfelvétel\" jogosultságot."),
|
("config_screen", "Ahhoz, hogy távolról hozzáférhessen a számítógépéhez, meg kell adnia a RustDesknek a \"Képernyőfelvétel\" jogosultságot."),
|
||||||
("Installing ...", "Telepítés ..."),
|
("Installing ...", "Telepítés…"),
|
||||||
("Install", "Telepítse"),
|
("Install", "Telepítés"),
|
||||||
("Installation", "Telepítés"),
|
("Installation", "Telepítés"),
|
||||||
("Installation Path", "Telepítési útvonal"),
|
("Installation Path", "Telepítési útvonal"),
|
||||||
("Create start menu shortcuts", "Start menü parancsikonok létrehozása"),
|
("Create start menu shortcuts", "Start menü parancsikonok létrehozása"),
|
||||||
@@ -159,10 +159,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("agreement_tip", "A telepítés folytatásával automatikusan elfogadásra kerül a licenc szerződés."),
|
("agreement_tip", "A telepítés folytatásával automatikusan elfogadásra kerül a licenc szerződés."),
|
||||||
("Accept and Install", "Elfogadás és telepítés"),
|
("Accept and Install", "Elfogadás és telepítés"),
|
||||||
("End-user license agreement", "Végfelhasználói licenc szerződés"),
|
("End-user license agreement", "Végfelhasználói licenc szerződés"),
|
||||||
("Generating ...", "Létrehozás ..."),
|
("Generating ...", "Előállítás…"),
|
||||||
("Your installation is lower version.", "A telepített verzió alacsonyabb."),
|
("Your installation is lower version.", "A telepített verzió alacsonyabb."),
|
||||||
("not_close_tcp_tip", "Ne zárja be ezt az ablakot, amíg TCP-alagutat használ"),
|
("not_close_tcp_tip", "Ne zárja be ezt az ablakot, amíg TCP-alagutat használ"),
|
||||||
("Listening ...", "Figyelés ..."),
|
("Listening ...", "Figyelés…"),
|
||||||
("Remote Host", "Távoli kiszolgáló"),
|
("Remote Host", "Távoli kiszolgáló"),
|
||||||
("Remote Port", "Távoli port"),
|
("Remote Port", "Távoli port"),
|
||||||
("Action", "Indítás"),
|
("Action", "Indítás"),
|
||||||
@@ -177,7 +177,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Accept", "Elfogadás"),
|
("Accept", "Elfogadás"),
|
||||||
("Dismiss", "Elutasítás"),
|
("Dismiss", "Elutasítás"),
|
||||||
("Disconnect", "Kapcsolat bontása"),
|
("Disconnect", "Kapcsolat bontása"),
|
||||||
("Enable file copy and paste", "Fájlmásolás és beillesztés engedélyezése"),
|
("Enable file copy and paste", "Fájlmásolás és -beillesztés engedélyezése"),
|
||||||
("Connected", "Kapcsolódva"),
|
("Connected", "Kapcsolódva"),
|
||||||
("Direct and encrypted connection", "Közvetlen, és titkosított kapcsolat"),
|
("Direct and encrypted connection", "Közvetlen, és titkosított kapcsolat"),
|
||||||
("Relayed and encrypted connection", "Továbbított, és titkosított kapcsolat"),
|
("Relayed and encrypted connection", "Továbbított, és titkosított kapcsolat"),
|
||||||
@@ -185,7 +185,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Relayed and unencrypted connection", "Továbbított, és nem titkosított kapcsolat"),
|
("Relayed and unencrypted connection", "Továbbított, és nem titkosított kapcsolat"),
|
||||||
("Enter Remote ID", "Távoli számítógép azonosítója"),
|
("Enter Remote ID", "Távoli számítógép azonosítója"),
|
||||||
("Enter your password", "Adja meg a jelszavát"),
|
("Enter your password", "Adja meg a jelszavát"),
|
||||||
("Logging in...", "Belépés folyamatban..."),
|
("Logging in...", "Belépés folyamatban…"),
|
||||||
("Enable RDP session sharing", "RDP-munkamenet-megosztás engedélyezése"),
|
("Enable RDP session sharing", "RDP-munkamenet-megosztás engedélyezése"),
|
||||||
("Auto Login", "Automatikus bejelentkezés"),
|
("Auto Login", "Automatikus bejelentkezés"),
|
||||||
("Enable direct IP access", "Közvetlen IP-elérés engedélyezése"),
|
("Enable direct IP access", "Közvetlen IP-elérés engedélyezése"),
|
||||||
@@ -219,7 +219,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("verification_tip", "A regisztrált e-mail-címre egy ellenőrző kód lesz elküldve. Adja meg az ellenőrző kódot az újbóli bejelentkezéshez."),
|
("verification_tip", "A regisztrált e-mail-címre egy ellenőrző kód lesz elküldve. Adja meg az ellenőrző kódot az újbóli bejelentkezéshez."),
|
||||||
("Logout", "Kilépés"),
|
("Logout", "Kilépés"),
|
||||||
("Tags", "Címkék"),
|
("Tags", "Címkék"),
|
||||||
("Search ID", "Azonosító keresése..."),
|
("Search ID", "Azonosító keresése…"),
|
||||||
("whitelist_sep", "A címeket vesszővel, pontosvesszővel, szóközzel vagy új sorral kell elválasztani"),
|
("whitelist_sep", "A címeket vesszővel, pontosvesszővel, szóközzel vagy új sorral kell elválasztani"),
|
||||||
("Add ID", "Azonosító hozzáadása"),
|
("Add ID", "Azonosító hozzáadása"),
|
||||||
("Add Tag", "Címke hozzáadása"),
|
("Add Tag", "Címke hozzáadása"),
|
||||||
@@ -258,10 +258,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Three-Finger vertically", "Három ujj függőlegesen"),
|
("Three-Finger vertically", "Három ujj függőlegesen"),
|
||||||
("Mouse Wheel", "Egérgörgő"),
|
("Mouse Wheel", "Egérgörgő"),
|
||||||
("Two-Finger Move", "Kétujjas mozgatás"),
|
("Two-Finger Move", "Kétujjas mozgatás"),
|
||||||
("Canvas Move", "Nézet módosítása"),
|
("Canvas Move", "Vászon mozgatása"),
|
||||||
("Pinch to Zoom", "Kétujjas nagyítás"),
|
("Pinch to Zoom", "Kétujjas nagyítás"),
|
||||||
("Canvas Zoom", "Nézet nagyítása"),
|
("Canvas Zoom", "Vászon nagyítása"),
|
||||||
("Reset canvas", "Nézet visszaállítása"),
|
("Reset canvas", "Vászon visszaállítása"),
|
||||||
("No permission of file transfer", "Nincs engedély a fájlátvitelre"),
|
("No permission of file transfer", "Nincs engedély a fájlátvitelre"),
|
||||||
("Note", "Megjegyzés"),
|
("Note", "Megjegyzés"),
|
||||||
("Connection", "Kapcsolat"),
|
("Connection", "Kapcsolat"),
|
||||||
@@ -314,7 +314,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Enable remote restart", "Távoli újraindítás engedélyezése"),
|
("Enable remote restart", "Távoli újraindítás engedélyezése"),
|
||||||
("Restart remote device", "Távoli eszköz újraindítása"),
|
("Restart remote device", "Távoli eszköz újraindítása"),
|
||||||
("Are you sure you want to restart", "Biztosan újra szeretné indítani?"),
|
("Are you sure you want to restart", "Biztosan újra szeretné indítani?"),
|
||||||
("Restarting remote device", "Távoli eszköz újraindítása..."),
|
("Restarting remote device", "Távoli eszköz újraindítása…"),
|
||||||
("remote_restarting_tip", "A távoli eszköz újraindul, zárja be ezt az üzenetet, kapcsolódjon újra az állandó jelszavával"),
|
("remote_restarting_tip", "A távoli eszköz újraindul, zárja be ezt az üzenetet, kapcsolódjon újra az állandó jelszavával"),
|
||||||
("Copied", "Másolva"),
|
("Copied", "Másolva"),
|
||||||
("Exit Fullscreen", "Kilépés teljes képernyős módból"),
|
("Exit Fullscreen", "Kilépés teljes képernyős módból"),
|
||||||
@@ -369,12 +369,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Deny LAN discovery", "Felfedezés tiltása"),
|
("Deny LAN discovery", "Felfedezés tiltása"),
|
||||||
("Write a message", "Üzenet írása"),
|
("Write a message", "Üzenet írása"),
|
||||||
("Prompt", "Kérés"),
|
("Prompt", "Kérés"),
|
||||||
("Please wait for confirmation of UAC...", "Várjon az UAC megerősítésére..."),
|
("Please wait for confirmation of UAC...", "Várjon az UAC megerősítésére…"),
|
||||||
("elevated_foreground_window_tip", "A távvezérelt számítógép jelenleg nyitott ablakához magasabb szintű jogok szükségesek. Ezért jelenleg nem lehetséges az egér és a billentyűzet használata. Kérje meg azt a felhasználót, akinek a számítógépét távolról vezérli, hogy minimalizálja az ablakot, vagy növelje a jogokat. A jövőbeni probléma elkerülése érdekében ajánlott a szoftvert a távvezérelt számítógépre telepíteni."),
|
("elevated_foreground_window_tip", "A távvezérelt számítógép jelenleg nyitott ablakához magasabb szintű jogok szükségesek. Ezért jelenleg nem lehetséges az egér és a billentyűzet használata. Kérje meg azt a felhasználót, akinek a számítógépét távolról vezérli, hogy minimalizálja az ablakot, vagy növelje a jogokat. A jövőbeni probléma elkerülése érdekében ajánlott a szoftvert a távvezérelt számítógépre telepíteni."),
|
||||||
("Disconnected", "Kapcsolat bontva"),
|
("Disconnected", "Kapcsolat bontva"),
|
||||||
("Other", "Egyéb"),
|
("Other", "Egyéb"),
|
||||||
("Confirm before closing multiple tabs", "Biztosan bezárja az összes lapot?"),
|
("Confirm before closing multiple tabs", "Biztosan bezárja az összes lapot?"),
|
||||||
("Keyboard Settings", "Billentyűzetbeállítások"),
|
("Keyboard Settings", "Billentyűzet-beállítások"),
|
||||||
("Full Access", "Teljes hozzáférés"),
|
("Full Access", "Teljes hozzáférés"),
|
||||||
("Screen Share", "Képernyőmegosztás"),
|
("Screen Share", "Képernyőmegosztás"),
|
||||||
("Wayland requires Ubuntu 21.04 or higher version.", "A Waylandhez Ubuntu 21.04 vagy újabb verzió szükséges."),
|
("Wayland requires Ubuntu 21.04 or higher version.", "A Waylandhez Ubuntu 21.04 vagy újabb verzió szükséges."),
|
||||||
@@ -389,7 +389,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Accept sessions via password", "Munkamenetek elfogadása jelszóval"),
|
("Accept sessions via password", "Munkamenetek elfogadása jelszóval"),
|
||||||
("Accept sessions via click", "Munkamenetek elfogadása kattintással"),
|
("Accept sessions via click", "Munkamenetek elfogadása kattintással"),
|
||||||
("Accept sessions via both", "Munkamenetek fogadása mindkettőn keresztül"),
|
("Accept sessions via both", "Munkamenetek fogadása mindkettőn keresztül"),
|
||||||
("Please wait for the remote side to accept your session request...", "Várjon, amíg a távoli oldal elfogadja a munkamenet-kérelmét..."),
|
("Please wait for the remote side to accept your session request...", "Várjon, amíg a távoli oldal elfogadja a munkamenet-kérelmét…"),
|
||||||
("One-time Password", "Egyszer használatos jelszó"),
|
("One-time Password", "Egyszer használatos jelszó"),
|
||||||
("Use one-time password", "Használjon ideiglenes jelszót"),
|
("Use one-time password", "Használjon ideiglenes jelszót"),
|
||||||
("One-time password length", "Egyszer használatos jelszó hossza"),
|
("One-time password length", "Egyszer használatos jelszó hossza"),
|
||||||
@@ -447,13 +447,13 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Resolution", "Felbontás"),
|
("Resolution", "Felbontás"),
|
||||||
("No transfers in progress", "Nincs folyamatban átvitel"),
|
("No transfers in progress", "Nincs folyamatban átvitel"),
|
||||||
("Set one-time password length", "Állítsa be az egyszeri jelszó hosszát"),
|
("Set one-time password length", "Állítsa be az egyszeri jelszó hosszát"),
|
||||||
("RDP Settings", "RDP beállítások"),
|
("RDP Settings", "RDP-beállítások"),
|
||||||
("Sort by", "Rendezés"),
|
("Sort by", "Rendezés"),
|
||||||
("New Connection", "Új kapcsolat"),
|
("New Connection", "Új kapcsolat"),
|
||||||
("Restore", "Visszaállítás"),
|
("Restore", "Visszaállítás"),
|
||||||
("Minimize", "Minimalizálás"),
|
("Minimize", "Minimalizálás"),
|
||||||
("Maximize", "Maximalizálás"),
|
("Maximize", "Maximalizálás"),
|
||||||
("Your Device", "Az én eszközöm"),
|
("Your Device", "Saját eszköz"),
|
||||||
("empty_recent_tip", "Nincsenek aktuális munkamenetek!\nIdeje ütemezni egy újat."),
|
("empty_recent_tip", "Nincsenek aktuális munkamenetek!\nIdeje ütemezni egy újat."),
|
||||||
("empty_favorite_tip", "Még nincs kedvenc távoli állomása?\nHagyja, hogy találjunk valakit, akivel kapcsolatba tud lépni, és adja hozzá a kedvencekhez!"),
|
("empty_favorite_tip", "Még nincs kedvenc távoli állomása?\nHagyja, hogy találjunk valakit, akivel kapcsolatba tud lépni, és adja hozzá a kedvencekhez!"),
|
||||||
("empty_lan_tip", "Úgy tűnik, még nem adott hozzá egyetlen távoli helyszínt sem."),
|
("empty_lan_tip", "Úgy tűnik, még nem adott hozzá egyetlen távoli helyszínt sem."),
|
||||||
@@ -468,7 +468,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("verify_rustdesk_password_tip", "RustDesk jelszó megerősítése"),
|
("verify_rustdesk_password_tip", "RustDesk jelszó megerősítése"),
|
||||||
("remember_account_tip", "Emlékezzen erre a fiókra"),
|
("remember_account_tip", "Emlékezzen erre a fiókra"),
|
||||||
("os_account_desk_tip", "Ezzel a fiókkal bejelentkezhet a távoli operációs rendszerbe, és aktiválhatja az asztali munkamenetet fej nélküli módban."),
|
("os_account_desk_tip", "Ezzel a fiókkal bejelentkezhet a távoli operációs rendszerbe, és aktiválhatja az asztali munkamenetet fej nélküli módban."),
|
||||||
("OS Account", "OS fiók"),
|
("OS Account", "OS-fiók"),
|
||||||
("another_user_login_title_tip", "Egy másik felhasználó már bejelentkezett."),
|
("another_user_login_title_tip", "Egy másik felhasználó már bejelentkezett."),
|
||||||
("another_user_login_text_tip", "Különálló"),
|
("another_user_login_text_tip", "Különálló"),
|
||||||
("xorg_not_found_title_tip", "Xorg nem található."),
|
("xorg_not_found_title_tip", "Xorg nem található."),
|
||||||
@@ -568,7 +568,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("input_source_2_tip", "2. bemeneti forrás"),
|
("input_source_2_tip", "2. bemeneti forrás"),
|
||||||
("Swap control-command key", "Vezérlő- és parancsgombok cseréje"),
|
("Swap control-command key", "Vezérlő- és parancsgombok cseréje"),
|
||||||
("swap-left-right-mouse", "Bal és jobb egérgomb felcserélése"),
|
("swap-left-right-mouse", "Bal és jobb egérgomb felcserélése"),
|
||||||
("2FA code", "2FA kód"),
|
("2FA code", "2FA-kód"),
|
||||||
("More", "Továbbiak"),
|
("More", "Továbbiak"),
|
||||||
("enable-2fa-title", "Kétfaktoros hitelesítés aktiválása"),
|
("enable-2fa-title", "Kétfaktoros hitelesítés aktiválása"),
|
||||||
("enable-2fa-desc", "Állítsa be a hitelesítőt. Használhat egy hitelesítő alkalmazást, például az Aegis, Authy, a Microsoft- vagy a Google Authenticator alkalmazást a telefonján vagy az asztali számítógépén.\n\nOlvassa be a QR-kódot az alkalmazással, és adja meg az alkalmazás által megjelenített kódot a kétfaktoros hitelesítés aktiválásához."),
|
("enable-2fa-desc", "Állítsa be a hitelesítőt. Használhat egy hitelesítő alkalmazást, például az Aegis, Authy, a Microsoft- vagy a Google Authenticator alkalmazást a telefonján vagy az asztali számítógépén.\n\nOlvassa be a QR-kódot az alkalmazással, és adja meg az alkalmazás által megjelenített kódot a kétfaktoros hitelesítés aktiválásához."),
|
||||||
@@ -647,13 +647,13 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Upload folder", "Mappa feltöltése"),
|
("Upload folder", "Mappa feltöltése"),
|
||||||
("Upload files", "Fájlok feltöltése"),
|
("Upload files", "Fájlok feltöltése"),
|
||||||
("Clipboard is synchronized", "A vágólap szinkronizálva van"),
|
("Clipboard is synchronized", "A vágólap szinkronizálva van"),
|
||||||
("Update client clipboard", "Az ügyfél vágólapjának frissítése"),
|
("Update client clipboard", "Kliens vágólapjának frissítése"),
|
||||||
("Untagged", "Címkézetlen"),
|
("Untagged", "Címkézetlen"),
|
||||||
("new-version-of-{}-tip", "A(z) {} új verziója"),
|
("new-version-of-{}-tip", "A(z) {} új verziója"),
|
||||||
("Accessible devices", "Hozzáférhető eszközök"),
|
("Accessible devices", "Hozzáférhető eszközök"),
|
||||||
("upgrade_remote_rustdesk_client_to_{}_tip", "Frissítse a RustDesk klienst {} vagy újabb verziójára a távoli oldalon!"),
|
("upgrade_remote_rustdesk_client_to_{}_tip", "Frissítse a RustDesk klienst {} vagy újabb verziójára a távoli oldalon!"),
|
||||||
("d3d_render_tip", "D3D leképezés"),
|
("d3d_render_tip", "D3D-leképezés"),
|
||||||
("Use D3D rendering", "D3D leképezés használata"),
|
("Use D3D rendering", "D3D-leképezés használata"),
|
||||||
("Printer", "Nyomtató"),
|
("Printer", "Nyomtató"),
|
||||||
("printer-os-requirement-tip", "Nyomtató operációs rendszerének minimális rendszerkövetelménye"),
|
("printer-os-requirement-tip", "Nyomtató operációs rendszerének minimális rendszerkövetelménye"),
|
||||||
("printer-requires-installed-{}-client-tip", "A nyomtatóhoz szükséges a(z) {} kliens telepítése"),
|
("printer-requires-installed-{}-client-tip", "A nyomtatóhoz szükséges a(z) {} kliens telepítése"),
|
||||||
@@ -672,7 +672,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("save-settings-tip", "Beállítások mentése"),
|
("save-settings-tip", "Beállítások mentése"),
|
||||||
("dont-show-again-tip", "Ne jelenítse meg újra"),
|
("dont-show-again-tip", "Ne jelenítse meg újra"),
|
||||||
("Take screenshot", "Képernyőkép készítése"),
|
("Take screenshot", "Képernyőkép készítése"),
|
||||||
("Taking screenshot", "Képernyőkép készítése..."),
|
("Taking screenshot", "Képernyőkép készítése…"),
|
||||||
("screenshot-merged-screen-not-supported-tip", "Egyesített képernyőről nem támogatott a képernyőkép készítése"),
|
("screenshot-merged-screen-not-supported-tip", "Egyesített képernyőről nem támogatott a képernyőkép készítése"),
|
||||||
("screenshot-action-tip", "Képernyőkép-művelet"),
|
("screenshot-action-tip", "Képernyőkép-művelet"),
|
||||||
("Save as", "Mentés másként"),
|
("Save as", "Mentés másként"),
|
||||||
@@ -680,7 +680,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Enable remote printer", "Távoli nyomtatók engedélyezése"),
|
("Enable remote printer", "Távoli nyomtatók engedélyezése"),
|
||||||
("Downloading {}", "{} letöltése"),
|
("Downloading {}", "{} letöltése"),
|
||||||
("{} Update", "{} frissítés"),
|
("{} Update", "{} frissítés"),
|
||||||
("{}-to-update-tip", "{} bezárása és az új verzió telepítése."),
|
("{}-to-update-tip", "A(z) {} bezárása és az új verzió telepítése."),
|
||||||
("download-new-version-failed-tip", "Ha a letöltés sikertelen, akkor vagy újrapróbálkozhat, vagy a \"Letöltés\" gombra kattintva letöltheti a kiadási oldalról, és manuálisan frissíthet."),
|
("download-new-version-failed-tip", "Ha a letöltés sikertelen, akkor vagy újrapróbálkozhat, vagy a \"Letöltés\" gombra kattintva letöltheti a kiadási oldalról, és manuálisan frissíthet."),
|
||||||
("Auto update", "Automatikus frissítés"),
|
("Auto update", "Automatikus frissítés"),
|
||||||
("update-failed-check-msi-tip", "A telepítési módszer felismerése nem sikerült. Kattintson a \"Letöltés\" gombra, hogy letöltse a kiadási oldalról, és manuálisan frissítse."),
|
("update-failed-check-msi-tip", "A telepítési módszer felismerése nem sikerült. Kattintson a \"Letöltés\" gombra, hogy letöltse a kiadási oldalról, és manuálisan frissítse."),
|
||||||
@@ -707,7 +707,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Failed to check if the user is an administrator.", "Hiba merült fel annak ellenőrzése során, hogy a felhasználó rendszergazda-e."),
|
("Failed to check if the user is an administrator.", "Hiba merült fel annak ellenőrzése során, hogy a felhasználó rendszergazda-e."),
|
||||||
("Supported only in the installed version.", "Csak a telepített változatban támogatott."),
|
("Supported only in the installed version.", "Csak a telepített változatban támogatott."),
|
||||||
("elevation_username_tip", "Felhasználónév vagy tartománynév megadása"),
|
("elevation_username_tip", "Felhasználónév vagy tartománynév megadása"),
|
||||||
("Preparing for installation ...", "Felkészülés a telepítésre ..."),
|
("Preparing for installation ...", "Felkészülés a telepítésre…"),
|
||||||
("Show my cursor", "Kurzor megjelenítése"),
|
("Show my cursor", "Kurzor megjelenítése"),
|
||||||
("Scale custom", "Egyéni méretarány"),
|
("Scale custom", "Egyéni méretarány"),
|
||||||
("Custom scale slider", "Egyéni méretarány-csúszka"),
|
("Custom scale slider", "Egyéni méretarány-csúszka"),
|
||||||
@@ -733,10 +733,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("rel-mouse-not-supported-peer-tip", "A kapcsolódott partner nem támogatja a relatív egér módot."),
|
("rel-mouse-not-supported-peer-tip", "A kapcsolódott partner nem támogatja a relatív egér módot."),
|
||||||
("rel-mouse-not-ready-tip", "A relatív egér mód még nem elérhető. Próbálja meg újra."),
|
("rel-mouse-not-ready-tip", "A relatív egér mód még nem elérhető. Próbálja meg újra."),
|
||||||
("rel-mouse-lock-failed-tip", "Nem sikerült zárolni a kurzort. A relatív egér mód le lett tiltva."),
|
("rel-mouse-lock-failed-tip", "Nem sikerült zárolni a kurzort. A relatív egér mód le lett tiltva."),
|
||||||
("rel-mouse-exit-{}-tip", "A kilépéshez nyomja meg a következő gombot: {}"),
|
("rel-mouse-exit-{}-tip", "A kilépéshez nyomja meg a(z) {} gombot."),
|
||||||
("rel-mouse-permission-lost-tip", "A billentyűzet-hozzáférés vissza lett vonva. A relatív egér mód le lett tilva."),
|
("rel-mouse-permission-lost-tip", "A billentyűzet-hozzáférés vissza lett vonva. A relatív egér mód le lett tilva."),
|
||||||
("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 a következővel: {}"),
|
||||||
|
("Display Name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -739,6 +739,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("keep-awake-during-outgoing-sessions-label", "Mantieni lo schermo attivo durante le sessioni in uscita"),
|
("keep-awake-during-outgoing-sessions-label", "Mantieni lo schermo attivo durante le sessioni in uscita"),
|
||||||
("keep-awake-during-incoming-sessions-label", "Mantieni lo schermo attivo durante le sessioni in ingresso"),
|
("keep-awake-during-incoming-sessions-label", "Mantieni lo schermo attivo durante le sessioni in ingresso"),
|
||||||
("Continue with {}", "Continua con {}"),
|
("Continue with {}", "Continua con {}"),
|
||||||
("Display Name", "Visualizza nome"),
|
("Display Name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -739,6 +739,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("keep-awake-during-outgoing-sessions-label", "Giden oturumlar süresince ekranı açık tutun"),
|
("keep-awake-during-outgoing-sessions-label", "Giden oturumlar süresince ekranı açık tutun"),
|
||||||
("keep-awake-during-incoming-sessions-label", "Gelen oturumlar süresince ekranı açık tutun"),
|
("keep-awake-during-incoming-sessions-label", "Gelen oturumlar süresince ekranı açık tutun"),
|
||||||
("Continue with {}", "{} ile devam et"),
|
("Continue with {}", "{} ile devam et"),
|
||||||
("Display Name", "Görünen Ad"),
|
("Display Name", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -580,31 +580,6 @@ extern "C"
|
|||||||
return rdp_or_console;
|
return rdp_or_console;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL is_session_locked(BOOL include_rdp)
|
|
||||||
{
|
|
||||||
DWORD session_id = get_current_session(include_rdp);
|
|
||||||
if (session_id == 0xFFFFFFFF) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
PWTSINFOEXW pInfo = NULL;
|
|
||||||
DWORD bytes = 0;
|
|
||||||
BOOL locked = FALSE;
|
|
||||||
if (WTSQuerySessionInformationW(
|
|
||||||
WTS_CURRENT_SERVER_HANDLE,
|
|
||||||
session_id,
|
|
||||||
WTSSessionInfoEx,
|
|
||||||
(LPWSTR *)&pInfo,
|
|
||||||
&bytes)) {
|
|
||||||
if (pInfo && pInfo->Level == 1) {
|
|
||||||
locked = (pInfo->Data.WTSInfoExLevel1.SessionFlags == WTS_SESSIONSTATE_LOCK);
|
|
||||||
}
|
|
||||||
if (pInfo) {
|
|
||||||
WTSFreeMemory(pInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return locked;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t get_active_user(PWSTR bufin, uint32_t nin, BOOL rdp)
|
uint32_t get_active_user(PWSTR bufin, uint32_t nin, BOOL rdp)
|
||||||
{
|
{
|
||||||
uint32_t nout = 0;
|
uint32_t nout = 0;
|
||||||
|
|||||||
@@ -107,9 +107,9 @@ pub fn get_focused_display(displays: Vec<DisplayInfo>) -> Option<usize> {
|
|||||||
let center_x = rect.left + (rect.right - rect.left) / 2;
|
let center_x = rect.left + (rect.right - rect.left) / 2;
|
||||||
let center_y = rect.top + (rect.bottom - rect.top) / 2;
|
let center_y = rect.top + (rect.bottom - rect.top) / 2;
|
||||||
center_x >= display.x
|
center_x >= display.x
|
||||||
&& center_x < display.x + display.width
|
&& center_x <= display.x + display.width
|
||||||
&& center_y >= display.y
|
&& center_y >= display.y
|
||||||
&& center_y < display.y + display.height
|
&& center_y <= display.y + display.height
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -527,7 +527,6 @@ const SERVICE_TYPE: ServiceType = ServiceType::OWN_PROCESS;
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn get_current_session(rdp: BOOL) -> DWORD;
|
fn get_current_session(rdp: BOOL) -> DWORD;
|
||||||
fn is_session_locked(include_rdp: BOOL) -> BOOL;
|
|
||||||
fn LaunchProcessWin(
|
fn LaunchProcessWin(
|
||||||
cmd: *const u16,
|
cmd: *const u16,
|
||||||
session_id: DWORD,
|
session_id: DWORD,
|
||||||
@@ -1130,10 +1129,6 @@ pub fn is_prelogin() -> bool {
|
|||||||
username.is_empty() || username == "SYSTEM"
|
username.is_empty() || username == "SYSTEM"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_locked() -> bool {
|
|
||||||
unsafe { is_session_locked(share_rdp()) == TRUE }
|
|
||||||
}
|
|
||||||
|
|
||||||
// `is_logon_ui()` is regardless of multiple sessions now.
|
// `is_logon_ui()` is regardless of multiple sessions now.
|
||||||
// It only check if "LogonUI.exe" exists.
|
// It only check if "LogonUI.exe" exists.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ pub async fn listen(
|
|||||||
remote_host: String,
|
remote_host: String,
|
||||||
remote_port: i32,
|
remote_port: i32,
|
||||||
) -> ResultType<()> {
|
) -> ResultType<()> {
|
||||||
let listener = tcp::new_listener(format!("127.0.0.1:{}", port), true).await?;
|
let listener = tcp::new_listener(format!("0.0.0.0:{}", port), true).await?;
|
||||||
let addr = listener.local_addr()?;
|
let addr = listener.local_addr()?;
|
||||||
log::info!("listening on port {:?}", addr);
|
log::info!("listening on port {:?}", addr);
|
||||||
let is_rdp = port == 0;
|
let is_rdp = port == 0;
|
||||||
|
|||||||
@@ -2232,12 +2232,11 @@ impl Connection {
|
|||||||
|
|
||||||
// https://github.com/rustdesk/rustdesk-server-pro/discussions/646
|
// https://github.com/rustdesk/rustdesk-server-pro/discussions/646
|
||||||
// `is_logon` is used to check login with `OPTION_ALLOW_LOGON_SCREEN_PASSWORD` == "Y".
|
// `is_logon` is used to check login with `OPTION_ALLOW_LOGON_SCREEN_PASSWORD` == "Y".
|
||||||
// `is_logon_ui()` is a fallback for logon UI detection on Windows.
|
// `is_logon_ui()` is used on Windows, because there's no good way to detect `is_locked()`.
|
||||||
|
// Detecting `is_logon_ui()` (if `LogonUI.exe` running) is a workaround.
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
let is_logon = || {
|
let is_logon = || {
|
||||||
crate::platform::is_prelogin()
|
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) => {
|
||||||
|
|||||||
@@ -30,54 +30,8 @@ const MAX_OUTPUT_BUFFER_SIZE: usize = 1024 * 1024; // 1MB per terminal
|
|||||||
const MAX_BUFFER_LINES: usize = 10000;
|
const MAX_BUFFER_LINES: usize = 10000;
|
||||||
const MAX_SERVICES: usize = 100; // Maximum number of persistent terminal services
|
const MAX_SERVICES: usize = 100; // Maximum number of persistent terminal services
|
||||||
const SERVICE_IDLE_TIMEOUT: Duration = Duration::from_secs(3600); // 1 hour idle timeout
|
const SERVICE_IDLE_TIMEOUT: Duration = Duration::from_secs(3600); // 1 hour idle timeout
|
||||||
const CHANNEL_BUFFER_SIZE: usize = 500; // Channel buffer size. Max per-message size ~4KB (reader buffer), so worst case ~500*4KB ≈ 2MB/terminal. Increased from 100 to reduce data loss during disconnects.
|
const CHANNEL_BUFFER_SIZE: usize = 100; // Number of messages to buffer in channel
|
||||||
const COMPRESS_THRESHOLD: usize = 512; // Compress terminal data larger than this
|
const COMPRESS_THRESHOLD: usize = 512; // Compress terminal data larger than this
|
||||||
// Default max bytes for reconnection buffer replay.
|
|
||||||
const DEFAULT_RECONNECT_BUFFER_BYTES: usize = 8 * 1024;
|
|
||||||
const MAX_SIGWINCH_PHASE_ATTEMPTS: u8 = 3; // Max attempts per SIGWINCH phase before giving up
|
|
||||||
|
|
||||||
/// Two-phase SIGWINCH trigger for TUI app redraw on reconnection.
|
|
||||||
///
|
|
||||||
/// Why two phases? A single resize-then-restore done back-to-back is too fast:
|
|
||||||
/// by the time the TUI app handles the asynchronous SIGWINCH signal and calls
|
|
||||||
/// `ioctl(TIOCGWINSZ)`, the PTY size has already been restored to the original.
|
|
||||||
/// ncurses sees no size change and skips the full redraw.
|
|
||||||
///
|
|
||||||
/// Splitting across two `read_outputs()` calls (~30ms apart) ensures the app
|
|
||||||
/// sees a real size change on each SIGWINCH, forcing a complete redraw.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
enum SigwinchPhase {
|
|
||||||
/// No SIGWINCH needed.
|
|
||||||
Idle,
|
|
||||||
/// Phase 1: Resize PTY to temp dimensions (rows±1). The app handles SIGWINCH
|
|
||||||
/// and redraws at the temporary size.
|
|
||||||
TempResize { retries: u8 },
|
|
||||||
/// Phase 2: Restore PTY to correct dimensions. The app handles SIGWINCH,
|
|
||||||
/// detects the size change, and performs a full redraw at the correct size.
|
|
||||||
Restore { retries: u8 },
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Which resize to perform in the two-phase SIGWINCH sequence.
|
|
||||||
enum SigwinchAction {
|
|
||||||
/// Phase 1: resize to temp dimensions (rows±1) to trigger SIGWINCH with a visible size change.
|
|
||||||
TempResize,
|
|
||||||
/// Phase 2: restore to correct dimensions to trigger SIGWINCH and force full redraw.
|
|
||||||
Restore,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Session state machine for terminal streaming.
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum SessionState {
|
|
||||||
/// Session is closed, not streaming data to client.
|
|
||||||
Closed,
|
|
||||||
/// Session is active, streaming data to client.
|
|
||||||
/// pending_buffer: historical buffer to send before real-time data (set on reconnection).
|
|
||||||
/// sigwinch: two-phase SIGWINCH trigger state for TUI app redraw.
|
|
||||||
Active {
|
|
||||||
pending_buffer: Option<Vec<u8>>,
|
|
||||||
sigwinch: SigwinchPhase,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
// Global registry of persistent terminal services indexed by service_id
|
// Global registry of persistent terminal services indexed by service_id
|
||||||
@@ -479,103 +433,22 @@ impl OutputBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_recent(&self, max_bytes: usize) -> Vec<u8> {
|
fn get_recent(&self, max_bytes: usize) -> Vec<u8> {
|
||||||
if max_bytes == 0 {
|
let mut result = Vec::new();
|
||||||
return Vec::new();
|
|
||||||
}
|
|
||||||
let mut chunks: Vec<&[u8]> = Vec::new();
|
|
||||||
let mut size = 0;
|
let mut size = 0;
|
||||||
|
|
||||||
// Collect whole chunks from newest to oldest, preserving chronological continuity.
|
// Get recent lines up to max_bytes
|
||||||
// If the newest chunk alone exceeds max_bytes, take its tail (truncation may split
|
|
||||||
// an ANSI escape, but the terminal will self-correct on subsequent output).
|
|
||||||
for line in self.lines.iter().rev() {
|
for line in self.lines.iter().rev() {
|
||||||
if size + line.len() > max_bytes {
|
if size + line.len() > max_bytes {
|
||||||
if size == 0 && line.len() > max_bytes {
|
|
||||||
// Single oversized chunk: take the tail to preserve the most recent content.
|
|
||||||
// Align offset forward to a UTF-8 char boundary so that downstream
|
|
||||||
// clients (e.g. Dart) that decode the payload as UTF-8 text don't
|
|
||||||
// encounter split code points. The protobuf bytes field itself allows
|
|
||||||
// arbitrary bytes; this is a best-effort mitigation for client-side decoding.
|
|
||||||
let mut offset = line.len() - max_bytes;
|
|
||||||
// Skip at most 3 continuation bytes (UTF-8 max 4-byte sequence).
|
|
||||||
// Prevents runaway skipping on non-UTF-8 binary data.
|
|
||||||
let mut skipped = 0u8;
|
|
||||||
while skipped < 3
|
|
||||||
&& offset < line.len()
|
|
||||||
&& (line[offset] & 0b1100_0000) == 0b1000_0000
|
|
||||||
{
|
|
||||||
offset += 1;
|
|
||||||
skipped += 1;
|
|
||||||
}
|
|
||||||
// If we skipped past all remaining bytes (degenerate data), drop the
|
|
||||||
// chunk entirely rather than emitting a slice that decodes poorly on the client.
|
|
||||||
if offset < line.len() {
|
|
||||||
chunks.push(&line[offset..]);
|
|
||||||
size = line.len() - offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
size += line.len();
|
size += line.len();
|
||||||
chunks.push(line);
|
result.splice(0..0, line.iter().cloned());
|
||||||
}
|
|
||||||
|
|
||||||
// Reverse to restore chronological order and concatenate
|
|
||||||
chunks.reverse();
|
|
||||||
let mut result = Vec::with_capacity(size);
|
|
||||||
for chunk in chunks {
|
|
||||||
result.extend_from_slice(chunk);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to send data through the output channel with rate-limited drop logging.
|
|
||||||
/// Returns `true` if the caller should break out of the read loop (channel disconnected).
|
|
||||||
fn try_send_output(
|
|
||||||
output_tx: &mpsc::SyncSender<Vec<u8>>,
|
|
||||||
data: Vec<u8>,
|
|
||||||
terminal_id: i32,
|
|
||||||
label: &str,
|
|
||||||
drop_count: &mut u64,
|
|
||||||
last_drop_warn: &mut Instant,
|
|
||||||
) -> bool {
|
|
||||||
match output_tx.try_send(data) {
|
|
||||||
Ok(_) => {
|
|
||||||
if *drop_count > 0 {
|
|
||||||
log::trace!(
|
|
||||||
"Terminal {}{} output channel recovered, dropped {} chunks since last report",
|
|
||||||
terminal_id,
|
|
||||||
label,
|
|
||||||
*drop_count
|
|
||||||
);
|
|
||||||
*drop_count = 0;
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
Err(mpsc::TrySendError::Full(_)) => {
|
|
||||||
*drop_count += 1;
|
|
||||||
if last_drop_warn.elapsed() >= Duration::from_secs(5) {
|
|
||||||
log::trace!(
|
|
||||||
"Terminal {}{} output channel full, dropped {} chunks in last {:?}",
|
|
||||||
terminal_id,
|
|
||||||
label,
|
|
||||||
*drop_count,
|
|
||||||
last_drop_warn.elapsed()
|
|
||||||
);
|
|
||||||
*drop_count = 0;
|
|
||||||
*last_drop_warn = Instant::now();
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
Err(mpsc::TrySendError::Disconnected(_)) => {
|
|
||||||
log::debug!("Terminal {}{} output channel disconnected", terminal_id, label);
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TerminalSession {
|
pub struct TerminalSession {
|
||||||
pub created_at: Instant,
|
pub created_at: Instant,
|
||||||
last_activity: Instant,
|
last_activity: Instant,
|
||||||
@@ -596,8 +469,7 @@ pub struct TerminalSession {
|
|||||||
cols: u16,
|
cols: u16,
|
||||||
// Track if we've already sent the closed message
|
// Track if we've already sent the closed message
|
||||||
closed_message_sent: bool,
|
closed_message_sent: bool,
|
||||||
// Session state machine for reconnection handling
|
is_opened: bool,
|
||||||
state: SessionState,
|
|
||||||
// Helper mode: PTY is managed by helper process, communication via message protocol
|
// Helper mode: PTY is managed by helper process, communication via message protocol
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
is_helper_mode: bool,
|
is_helper_mode: bool,
|
||||||
@@ -624,7 +496,7 @@ impl TerminalSession {
|
|||||||
rows,
|
rows,
|
||||||
cols,
|
cols,
|
||||||
closed_message_sent: false,
|
closed_message_sent: false,
|
||||||
state: SessionState::Closed,
|
is_opened: false,
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
is_helper_mode: false,
|
is_helper_mode: false,
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
@@ -639,7 +511,7 @@ impl TerminalSession {
|
|||||||
// This helper function is to ensure that the threads are joined before the child process is dropped.
|
// This helper function is to ensure that the threads are joined before the child process is dropped.
|
||||||
// Though this is not strictly necessary on macOS.
|
// Though this is not strictly necessary on macOS.
|
||||||
fn stop(&mut self) {
|
fn stop(&mut self) {
|
||||||
self.state = SessionState::Closed;
|
self.is_opened = false;
|
||||||
self.exiting.store(true, Ordering::SeqCst);
|
self.exiting.store(true, Ordering::SeqCst);
|
||||||
|
|
||||||
// Drop the input channel to signal writer thread to exit
|
// Drop the input channel to signal writer thread to exit
|
||||||
@@ -796,9 +668,7 @@ impl PersistentTerminalService {
|
|||||||
(
|
(
|
||||||
session.rows,
|
session.rows,
|
||||||
session.cols,
|
session.cols,
|
||||||
session
|
session.output_buffer.get_recent(4096),
|
||||||
.output_buffer
|
|
||||||
.get_recent(DEFAULT_RECONNECT_BUFFER_BYTES),
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -813,7 +683,7 @@ impl PersistentTerminalService {
|
|||||||
self.needs_session_sync = true;
|
self.needs_session_sync = true;
|
||||||
for session in self.sessions.values() {
|
for session in self.sessions.values() {
|
||||||
let mut session = session.lock().unwrap();
|
let mut session = session.lock().unwrap();
|
||||||
session.state = SessionState::Closed;
|
session.is_opened = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -907,55 +777,11 @@ impl TerminalServiceProxy {
|
|||||||
) -> Result<Option<TerminalResponse>> {
|
) -> Result<Option<TerminalResponse>> {
|
||||||
let mut response = TerminalResponse::new();
|
let mut response = TerminalResponse::new();
|
||||||
|
|
||||||
// When the client requests a terminal_id that doesn't exist but there are
|
|
||||||
// surviving persistent sessions, remap the lowest-ID session to the requested
|
|
||||||
// terminal_id. This handles the case where _nextTerminalId resets to 1 on
|
|
||||||
// reconnect but the server-side sessions have non-contiguous IDs (e.g. {2: htop}).
|
|
||||||
//
|
|
||||||
// The client's requested terminal_id may not match any surviving session ID
|
|
||||||
// (e.g. _nextTerminalId incremented beyond the surviving IDs). This remap is a
|
|
||||||
// one-time handle reassignment — only the first reconnect triggers it because
|
|
||||||
// needs_session_sync is cleared afterward. Remaining sessions are communicated
|
|
||||||
// back via `persistent_sessions` with their original server-side IDs.
|
|
||||||
if !service.sessions.contains_key(&open.terminal_id)
|
|
||||||
&& service.needs_session_sync
|
|
||||||
&& !service.sessions.is_empty()
|
|
||||||
{
|
|
||||||
if let Some(&lowest_id) = service.sessions.keys().min() {
|
|
||||||
log::info!(
|
|
||||||
"Remapping persistent session {} -> {} for reconnection",
|
|
||||||
lowest_id,
|
|
||||||
open.terminal_id
|
|
||||||
);
|
|
||||||
if let Some(session_arc) = service.sessions.remove(&lowest_id) {
|
|
||||||
service.sessions.insert(open.terminal_id, session_arc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if terminal already exists
|
// Check if terminal already exists
|
||||||
if let Some(session_arc) = service.sessions.get(&open.terminal_id) {
|
if let Some(session_arc) = service.sessions.get(&open.terminal_id) {
|
||||||
// Reconnect to existing terminal
|
// Reconnect to existing terminal
|
||||||
let mut session = session_arc.lock().unwrap();
|
let mut session = session_arc.lock().unwrap();
|
||||||
// Directly enter Active state with pending buffer for immediate streaming.
|
session.is_opened = true;
|
||||||
// Historical buffer is sent first by read_outputs(), then real-time data follows.
|
|
||||||
// No overlap: pending_buffer comes from output_buffer (pre-disconnect history),
|
|
||||||
// while received_data in read_outputs() comes from the channel (post-reconnect).
|
|
||||||
// During disconnect, the run loop (sp.ok()) exits so read_outputs() stops being
|
|
||||||
// called; output_buffer is not updated, and channel data may be lost if it fills up.
|
|
||||||
let buffer = session
|
|
||||||
.output_buffer
|
|
||||||
.get_recent(DEFAULT_RECONNECT_BUFFER_BYTES);
|
|
||||||
let has_pending = !buffer.is_empty();
|
|
||||||
session.state = SessionState::Active {
|
|
||||||
pending_buffer: if has_pending { Some(buffer) } else { None },
|
|
||||||
// Always trigger two-phase SIGWINCH on reconnect to force TUI app redraw,
|
|
||||||
// regardless of whether there's pending buffer data. This avoids edge cases
|
|
||||||
// where buffer is empty but a TUI app (top/htop) still needs a full redraw.
|
|
||||||
sigwinch: SigwinchPhase::TempResize {
|
|
||||||
retries: MAX_SIGWINCH_PHASE_ATTEMPTS,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let mut opened = TerminalOpened::new();
|
let mut opened = TerminalOpened::new();
|
||||||
opened.terminal_id = open.terminal_id;
|
opened.terminal_id = open.terminal_id;
|
||||||
opened.success = true;
|
opened.success = true;
|
||||||
@@ -977,6 +803,13 @@ impl TerminalServiceProxy {
|
|||||||
}
|
}
|
||||||
response.set_opened(opened);
|
response.set_opened(opened);
|
||||||
|
|
||||||
|
// Send buffered output
|
||||||
|
let buffer = session.output_buffer.get_recent(4096);
|
||||||
|
if !buffer.is_empty() {
|
||||||
|
// We'll need to send this separately or extend the protocol
|
||||||
|
// For now, just acknowledge the reconnection
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(Some(response));
|
return Ok(Some(response));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -991,7 +824,7 @@ impl TerminalServiceProxy {
|
|||||||
|
|
||||||
// Create new terminal session
|
// Create new terminal session
|
||||||
log::info!(
|
log::info!(
|
||||||
"Creating new terminal {} for service {}",
|
"Creating new terminal {} for service: {}",
|
||||||
open.terminal_id,
|
open.terminal_id,
|
||||||
service.service_id
|
service.service_id
|
||||||
);
|
);
|
||||||
@@ -1086,9 +919,6 @@ impl TerminalServiceProxy {
|
|||||||
let reader_thread = thread::spawn(move || {
|
let reader_thread = thread::spawn(move || {
|
||||||
let mut reader = reader;
|
let mut reader = reader;
|
||||||
let mut buf = vec![0u8; 4096];
|
let mut buf = vec![0u8; 4096];
|
||||||
let mut drop_count: u64 = 0;
|
|
||||||
// Initialize to > 5s ago so the first drop triggers a warning immediately.
|
|
||||||
let mut last_drop_warn = Instant::now() - Duration::from_secs(6);
|
|
||||||
loop {
|
loop {
|
||||||
match reader.read(&mut buf) {
|
match reader.read(&mut buf) {
|
||||||
Ok(0) => {
|
Ok(0) => {
|
||||||
@@ -1102,22 +932,19 @@ impl TerminalServiceProxy {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let data = buf[..n].to_vec();
|
let data = buf[..n].to_vec();
|
||||||
// Use try_send to avoid blocking the reader thread when channel is full.
|
// Try to send, if channel is full, drop the data
|
||||||
// During disconnect, the run loop (sp.ok()) stops and read_outputs() is
|
match output_tx.try_send(data) {
|
||||||
// no longer called, so the channel won't be drained. Blocking send would
|
Ok(_) => {}
|
||||||
// deadlock the reader thread in that case.
|
Err(mpsc::TrySendError::Full(_)) => {
|
||||||
// Note: data produced during disconnect may be lost if channel fills up,
|
log::debug!(
|
||||||
// since output_buffer is only updated in read_outputs(). The buffer will
|
"Terminal {} output channel full, dropping data",
|
||||||
// contain history from before the disconnect, not data produced after it.
|
terminal_id
|
||||||
if try_send_output(
|
);
|
||||||
&output_tx,
|
}
|
||||||
data,
|
Err(mpsc::TrySendError::Disconnected(_)) => {
|
||||||
terminal_id,
|
log::debug!("Terminal {} output channel disconnected", terminal_id);
|
||||||
"",
|
break;
|
||||||
&mut drop_count,
|
}
|
||||||
&mut last_drop_warn,
|
|
||||||
) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
|
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
|
||||||
@@ -1143,10 +970,7 @@ impl TerminalServiceProxy {
|
|||||||
session.output_rx = Some(output_rx);
|
session.output_rx = Some(output_rx);
|
||||||
session.reader_thread = Some(reader_thread);
|
session.reader_thread = Some(reader_thread);
|
||||||
session.writer_thread = Some(writer_thread);
|
session.writer_thread = Some(writer_thread);
|
||||||
session.state = SessionState::Active {
|
session.is_opened = true;
|
||||||
pending_buffer: None,
|
|
||||||
sigwinch: SigwinchPhase::Idle,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut opened = TerminalOpened::new();
|
let mut opened = TerminalOpened::new();
|
||||||
opened.terminal_id = open.terminal_id;
|
opened.terminal_id = open.terminal_id;
|
||||||
@@ -1308,9 +1132,6 @@ impl TerminalServiceProxy {
|
|||||||
let terminal_id = open.terminal_id;
|
let terminal_id = open.terminal_id;
|
||||||
let reader_thread = thread::spawn(move || {
|
let reader_thread = thread::spawn(move || {
|
||||||
let mut buf = vec![0u8; 4096];
|
let mut buf = vec![0u8; 4096];
|
||||||
let mut drop_count: u64 = 0;
|
|
||||||
// Initialize to > 5s ago so the first drop triggers a warning immediately.
|
|
||||||
let mut last_drop_warn = Instant::now() - Duration::from_secs(6);
|
|
||||||
loop {
|
loop {
|
||||||
match output_pipe.read(&mut buf) {
|
match output_pipe.read(&mut buf) {
|
||||||
Ok(0) => {
|
Ok(0) => {
|
||||||
@@ -1323,16 +1144,18 @@ impl TerminalServiceProxy {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let data = buf[..n].to_vec();
|
let data = buf[..n].to_vec();
|
||||||
// Use try_send to avoid blocking the reader thread (same as direct PTY mode)
|
match output_tx.try_send(data) {
|
||||||
if try_send_output(
|
Ok(_) => {}
|
||||||
&output_tx,
|
Err(mpsc::TrySendError::Full(_)) => {
|
||||||
data,
|
log::debug!(
|
||||||
terminal_id,
|
"Terminal {} output channel full, dropping data",
|
||||||
" (helper)",
|
terminal_id
|
||||||
&mut drop_count,
|
);
|
||||||
&mut last_drop_warn,
|
}
|
||||||
) {
|
Err(mpsc::TrySendError::Disconnected(_)) => {
|
||||||
break;
|
log::debug!("Terminal {} output channel disconnected", terminal_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
|
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
|
||||||
@@ -1362,10 +1185,7 @@ impl TerminalServiceProxy {
|
|||||||
session.output_rx = Some(output_rx);
|
session.output_rx = Some(output_rx);
|
||||||
session.reader_thread = Some(reader_thread);
|
session.reader_thread = Some(reader_thread);
|
||||||
session.writer_thread = Some(writer_thread);
|
session.writer_thread = Some(writer_thread);
|
||||||
session.state = SessionState::Active {
|
session.is_opened = true;
|
||||||
pending_buffer: None,
|
|
||||||
sigwinch: SigwinchPhase::Idle,
|
|
||||||
};
|
|
||||||
session.is_helper_mode = true;
|
session.is_helper_mode = true;
|
||||||
session.helper_process_handle = Some(SendableHandle::new(helper_raw_handle));
|
session.helper_process_handle = Some(SendableHandle::new(helper_raw_handle));
|
||||||
|
|
||||||
@@ -1407,11 +1227,6 @@ impl TerminalServiceProxy {
|
|||||||
session.rows = resize.rows as u16;
|
session.rows = resize.rows as u16;
|
||||||
session.cols = resize.cols as u16;
|
session.cols = resize.cols as u16;
|
||||||
|
|
||||||
// Note: we do NOT clear the sigwinch phase here. The server-side two-phase
|
|
||||||
// SIGWINCH mechanism in read_outputs() is self-contained (temp resize → restore
|
|
||||||
// across two polling cycles), so client resize is purely a dimension sync and
|
|
||||||
// doesn't affect it.
|
|
||||||
|
|
||||||
// Windows: handle helper mode vs direct PTY mode
|
// Windows: handle helper mode vs direct PTY mode
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
{
|
{
|
||||||
@@ -1517,116 +1332,6 @@ impl TerminalServiceProxy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform a single PTY resize as part of the two-phase SIGWINCH sequence.
|
|
||||||
/// Returns true if the resize succeeded.
|
|
||||||
///
|
|
||||||
/// Takes individual field references to avoid borrowing the entire TerminalSession,
|
|
||||||
/// which would conflict with the mutable borrow of session.state in read_outputs().
|
|
||||||
fn do_sigwinch_resize(
|
|
||||||
terminal_id: i32,
|
|
||||||
rows: u16,
|
|
||||||
cols: u16,
|
|
||||||
pty_pair: &Option<portable_pty::PtyPair>,
|
|
||||||
input_tx: &Option<SyncSender<Vec<u8>>>,
|
|
||||||
_is_helper_mode: bool,
|
|
||||||
action: &SigwinchAction,
|
|
||||||
) -> bool {
|
|
||||||
// Skip if dimensions are not initialized (shouldn't happen on reconnect,
|
|
||||||
// but guard against it to avoid resizing to nonsensical values).
|
|
||||||
if rows == 0 || cols == 0 {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let target_rows = match action {
|
|
||||||
SigwinchAction::TempResize => {
|
|
||||||
// For very small terminals (≤2 rows), subtracting 1 would result in an unusable
|
|
||||||
// size (0 or 1 row), so we add 1 instead. Either direction triggers SIGWINCH.
|
|
||||||
if rows > 2 {
|
|
||||||
rows.saturating_sub(1)
|
|
||||||
} else {
|
|
||||||
rows.saturating_add(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SigwinchAction::Restore => rows,
|
|
||||||
};
|
|
||||||
|
|
||||||
let phase_name = match action {
|
|
||||||
SigwinchAction::TempResize => "temp resize",
|
|
||||||
SigwinchAction::Restore => "restore",
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
let use_helper = _is_helper_mode;
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
|
||||||
let use_helper = false;
|
|
||||||
|
|
||||||
if use_helper {
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
{
|
|
||||||
let input_tx = match input_tx {
|
|
||||||
Some(tx) => tx,
|
|
||||||
None => return false,
|
|
||||||
};
|
|
||||||
let msg = encode_resize_message(target_rows, cols);
|
|
||||||
if let Err(e) = input_tx.try_send(msg) {
|
|
||||||
log::warn!(
|
|
||||||
"Terminal {} SIGWINCH {} via helper failed: {}",
|
|
||||||
terminal_id,
|
|
||||||
phase_name,
|
|
||||||
e
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
|
||||||
{
|
|
||||||
let _ = (input_tx, phase_name);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
} else if let Some(pty_pair) = pty_pair {
|
|
||||||
if let Err(e) = pty_pair.master.resize(PtySize {
|
|
||||||
rows: target_rows,
|
|
||||||
cols,
|
|
||||||
pixel_width: 0,
|
|
||||||
pixel_height: 0,
|
|
||||||
}) {
|
|
||||||
log::warn!(
|
|
||||||
"Terminal {} SIGWINCH {} failed: {}",
|
|
||||||
terminal_id,
|
|
||||||
phase_name,
|
|
||||||
e
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Helper to create a TerminalResponse with optional compression.
|
|
||||||
fn create_terminal_data_response(terminal_id: i32, data: Vec<u8>) -> TerminalResponse {
|
|
||||||
let mut response = TerminalResponse::new();
|
|
||||||
let mut terminal_data = TerminalData::new();
|
|
||||||
terminal_data.terminal_id = terminal_id;
|
|
||||||
|
|
||||||
if data.len() > COMPRESS_THRESHOLD {
|
|
||||||
let compressed = compress::compress(&data);
|
|
||||||
if compressed.len() < data.len() {
|
|
||||||
terminal_data.data = bytes::Bytes::from(compressed);
|
|
||||||
terminal_data.compressed = true;
|
|
||||||
} else {
|
|
||||||
terminal_data.data = bytes::Bytes::from(data);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
terminal_data.data = bytes::Bytes::from(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
response.set_data(terminal_data);
|
|
||||||
response
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_outputs(&self) -> Vec<TerminalResponse> {
|
pub fn read_outputs(&self) -> Vec<TerminalResponse> {
|
||||||
let service = match get_service(&self.service_id) {
|
let service = match get_service(&self.service_id) {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
@@ -1668,11 +1373,12 @@ impl TerminalServiceProxy {
|
|||||||
closed_terminals.push(terminal_id);
|
closed_terminals.push(terminal_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always drain the output channel regardless of session state.
|
if !session.is_opened {
|
||||||
// When Active: data is sent to client. When Closed (within the same
|
// Skip the session if it is not opened.
|
||||||
// connection): data is buffered in output_buffer for reconnection replay.
|
continue;
|
||||||
// Note: during actual disconnect, the run loop exits and read_outputs()
|
}
|
||||||
// is not called, so channel data produced after disconnect may be lost.
|
|
||||||
|
// Read from output channel
|
||||||
let mut has_activity = false;
|
let mut has_activity = false;
|
||||||
let mut received_data = Vec::new();
|
let mut received_data = Vec::new();
|
||||||
if let Some(output_rx) = &session.output_rx {
|
if let Some(output_rx) = &session.output_rx {
|
||||||
@@ -1683,111 +1389,37 @@ impl TerminalServiceProxy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if has_activity {
|
// Update buffer after reading
|
||||||
session.update_activity();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update buffer (always buffer for reconnection support)
|
|
||||||
for data in &received_data {
|
for data in &received_data {
|
||||||
session.output_buffer.append(data);
|
session.output_buffer.append(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip sending responses if session is not Active.
|
// Process received data for responses
|
||||||
// Data is already buffered above and will be sent on next reconnection.
|
for data in received_data {
|
||||||
// Use a scoped block to limit the mutable borrow of session.state,
|
let mut response = TerminalResponse::new();
|
||||||
// so we can immutably borrow other session fields afterwards.
|
let mut terminal_data = TerminalData::new();
|
||||||
let sigwinch_action = {
|
terminal_data.terminal_id = terminal_id;
|
||||||
let (pending_buffer, sigwinch) = match &mut session.state {
|
|
||||||
SessionState::Active {
|
|
||||||
pending_buffer,
|
|
||||||
sigwinch,
|
|
||||||
} => (pending_buffer, sigwinch),
|
|
||||||
_ => continue,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Send pending buffer response first (set on reconnection in handle_open).
|
// Compress data if it exceeds threshold
|
||||||
// This ensures historical buffer is sent before any real-time data.
|
if data.len() > COMPRESS_THRESHOLD {
|
||||||
if let Some(buffer) = pending_buffer.take() {
|
let compressed = compress::compress(&data);
|
||||||
if !buffer.is_empty() {
|
if compressed.len() < data.len() {
|
||||||
responses
|
terminal_data.data = bytes::Bytes::from(compressed);
|
||||||
.push(Self::create_terminal_data_response(terminal_id, buffer));
|
terminal_data.compressed = true;
|
||||||
|
} else {
|
||||||
|
// Compression didn't help, send uncompressed
|
||||||
|
terminal_data.data = bytes::Bytes::from(data);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
terminal_data.data = bytes::Bytes::from(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Two-phase SIGWINCH: see SigwinchPhase doc comments for rationale.
|
response.set_data(terminal_data);
|
||||||
// Each phase is a single PTY resize, spaced ~30ms apart by the polling
|
responses.push(response);
|
||||||
// interval, ensuring the TUI app sees a real size change on each signal.
|
|
||||||
match sigwinch {
|
|
||||||
SigwinchPhase::TempResize { retries } => {
|
|
||||||
if *retries == 0 {
|
|
||||||
log::warn!(
|
|
||||||
"Terminal {} SIGWINCH phase 1 (temp resize) failed after {} attempts, giving up",
|
|
||||||
terminal_id, MAX_SIGWINCH_PHASE_ATTEMPTS
|
|
||||||
);
|
|
||||||
*sigwinch = SigwinchPhase::Idle;
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
*retries -= 1;
|
|
||||||
Some(SigwinchAction::TempResize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SigwinchPhase::Restore { retries } => {
|
|
||||||
if *retries == 0 {
|
|
||||||
log::warn!(
|
|
||||||
"Terminal {} SIGWINCH phase 2 (restore) failed after {} attempts, giving up",
|
|
||||||
terminal_id, MAX_SIGWINCH_PHASE_ATTEMPTS
|
|
||||||
);
|
|
||||||
*sigwinch = SigwinchPhase::Idle;
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
*retries -= 1;
|
|
||||||
Some(SigwinchAction::Restore)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SigwinchPhase::Idle => None,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Execute SIGWINCH resize outside the mutable borrow scope of session.state.
|
|
||||||
if let Some(action) = sigwinch_action {
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
let is_helper = session.is_helper_mode;
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
|
||||||
let is_helper = false;
|
|
||||||
let resize_ok = Self::do_sigwinch_resize(
|
|
||||||
terminal_id,
|
|
||||||
session.rows,
|
|
||||||
session.cols,
|
|
||||||
&session.pty_pair,
|
|
||||||
&session.input_tx,
|
|
||||||
is_helper,
|
|
||||||
&action,
|
|
||||||
);
|
|
||||||
if let SessionState::Active { sigwinch, .. } = &mut session.state {
|
|
||||||
match action {
|
|
||||||
SigwinchAction::TempResize => {
|
|
||||||
if resize_ok {
|
|
||||||
// Phase 1 succeeded — advance to phase 2 (restore).
|
|
||||||
*sigwinch = SigwinchPhase::Restore {
|
|
||||||
retries: MAX_SIGWINCH_PHASE_ATTEMPTS,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// If failed, retries already decremented; will retry phase 1.
|
|
||||||
}
|
|
||||||
SigwinchAction::Restore => {
|
|
||||||
if resize_ok {
|
|
||||||
// Phase 2 succeeded — SIGWINCH sequence complete.
|
|
||||||
*sigwinch = SigwinchPhase::Idle;
|
|
||||||
}
|
|
||||||
// If failed, retries already decremented; will retry phase 2.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send real-time data after historical buffer
|
if has_activity {
|
||||||
for data in received_data {
|
session.update_activity();
|
||||||
responses.push(Self::create_terminal_data_response(terminal_id, data));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,7 @@
|
|||||||
include "common.tis";
|
include "common.tis";
|
||||||
var p = view.parameters;
|
var p = view.parameters;
|
||||||
view.refresh = function() {
|
view.refresh = function() {
|
||||||
var draft_input = $(input);
|
|
||||||
var draft = draft_input ? (draft_input.value || "") : "";
|
|
||||||
$(body).content(<ChatBox msgs={p.msgs} callback={p.callback} />);
|
$(body).content(<ChatBox msgs={p.msgs} callback={p.callback} />);
|
||||||
var next_input = $(input);
|
|
||||||
if (next_input) next_input.value = draft;
|
|
||||||
view.focus = $(input);
|
view.focus = $(input);
|
||||||
}
|
}
|
||||||
function self.closing() {
|
function self.closing() {
|
||||||
|
|||||||
Reference in New Issue
Block a user