From a336cbb2ceda64fb7b938bf5f6a08e44add0d773 Mon Sep 17 00:00:00 2001 From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> Date: Wed, 24 Jun 2026 01:30:54 +0200 Subject: [PATCH 1/2] Feature: Remote desktop additional shortcuts --- .../Resources/Strings.Designer.cs | 47 ++++++++++++++++++- .../Resources/Strings.resx | 15 ++++++ .../RemoteDesktop/Keystroke.cs | 27 ++++++++++- .../RemoteDesktop/RemoteDesktop.cs | 20 ++++++++ .../Controls/DragablzTabHostWindow.xaml | 20 ++++++++ .../Controls/DragablzTabHostWindow.xaml.cs | 21 +++++++-- .../Controls/RemoteDesktopControl.xaml.cs | 2 +- .../ViewModels/RemoteDesktopHostViewModel.cs | 21 +++++++-- .../Views/RemoteDesktopHostView.xaml | 15 ++++++ Website/docs/application/remote-desktop.md | 7 ++- 10 files changed, 185 insertions(+), 10 deletions(-) diff --git a/Source/NETworkManager.Localization/Resources/Strings.Designer.cs b/Source/NETworkManager.Localization/Resources/Strings.Designer.cs index bd5ba1fb2c..2154fa8875 100644 --- a/Source/NETworkManager.Localization/Resources/Strings.Designer.cs +++ b/Source/NETworkManager.Localization/Resources/Strings.Designer.cs @@ -2465,7 +2465,52 @@ public static string CtrlAltDel { return ResourceManager.GetString("CtrlAltDel", resourceCulture); } } - + + /// + /// Looks up a localized string similar to Task Manager (Ctrl+Shift+Esc). + /// + public static string TaskManager { + get { + return ResourceManager.GetString("TaskManager", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Lock (Win+L). + /// + public static string Lock { + get { + return ResourceManager.GetString("Lock", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Show Desktop (Win+D). + /// + public static string ShowDesktop { + get { + return ResourceManager.GetString("ShowDesktop", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Explorer (Win+E). + /// + public static string Explorer { + get { + return ResourceManager.GetString("Explorer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Run dialog (Win+R). + /// + public static string RunDialog { + get { + return ResourceManager.GetString("RunDialog", resourceCulture); + } + } + /// /// Looks up a localized string similar to Currency. /// diff --git a/Source/NETworkManager.Localization/Resources/Strings.resx b/Source/NETworkManager.Localization/Resources/Strings.resx index e56b832433..1492cf1be0 100644 --- a/Source/NETworkManager.Localization/Resources/Strings.resx +++ b/Source/NETworkManager.Localization/Resources/Strings.resx @@ -2250,6 +2250,21 @@ $$hostname$$ --> Hostname Ctrl+Alt+Del + + Task Manager (Ctrl+Shift+Esc) + + + Lock (Win+L) + + + Show Desktop (Win+D) + + + Explorer (Win+E) + + + Run dialog (Win+R) + Keyboard shortcuts diff --git a/Source/NETworkManager.Models/RemoteDesktop/Keystroke.cs b/Source/NETworkManager.Models/RemoteDesktop/Keystroke.cs index 335e41d899..28b5cc6c2b 100644 --- a/Source/NETworkManager.Models/RemoteDesktop/Keystroke.cs +++ b/Source/NETworkManager.Models/RemoteDesktop/Keystroke.cs @@ -8,5 +8,30 @@ public enum Keystroke /// /// Ctrl + Alt + Del keystroke. /// - CtrlAltDel + CtrlAltDel, + + /// + /// Ctrl + Shift + Esc keystroke (opens Task Manager). + /// + TaskManager, + + /// + /// Win + L keystroke (locks the session). + /// + Lock, + + /// + /// Win + D keystroke (shows the desktop / minimizes all windows). + /// + ShowDesktop, + + /// + /// Win + E keystroke (opens File Explorer). + /// + Explorer, + + /// + /// Win + R keystroke (opens the Run dialog). + /// + RunDialog } \ No newline at end of file diff --git a/Source/NETworkManager.Models/RemoteDesktop/RemoteDesktop.cs b/Source/NETworkManager.Models/RemoteDesktop/RemoteDesktop.cs index f6a756cb8d..128e70d48b 100644 --- a/Source/NETworkManager.Models/RemoteDesktop/RemoteDesktop.cs +++ b/Source/NETworkManager.Models/RemoteDesktop/RemoteDesktop.cs @@ -38,6 +38,26 @@ public static RemoteDesktopKeystrokeInfo GetKeystroke(Keystroke keystroke) info.ArrayKeyUp = [false, false, false, true, true, true]; info.KeyData = [0x1d, 0x38, 0x53, 0x53, 0x38, 0x1d]; break; + case Keystroke.TaskManager: // Ctrl + Shift + Esc + info.ArrayKeyUp = [false, false, false, true, true, true]; + info.KeyData = [0x1d, 0x2a, 0x01, 0x01, 0x2a, 0x1d]; + break; + case Keystroke.Lock: // Win + L + info.ArrayKeyUp = [false, false, true, true]; + info.KeyData = [0x15b, 0x26, 0x26, 0x15b]; + break; + case Keystroke.ShowDesktop: // Win + D + info.ArrayKeyUp = [false, false, true, true]; + info.KeyData = [0x15b, 0x20, 0x20, 0x15b]; + break; + case Keystroke.Explorer: // Win + E + info.ArrayKeyUp = [false, false, true, true]; + info.KeyData = [0x15b, 0x12, 0x12, 0x15b]; + break; + case Keystroke.RunDialog: // Win + R + info.ArrayKeyUp = [false, false, true, true]; + info.KeyData = [0x15b, 0x13, 0x13, 0x15b]; + break; } return info; diff --git a/Source/NETworkManager/Controls/DragablzTabHostWindow.xaml b/Source/NETworkManager/Controls/DragablzTabHostWindow.xaml index 784a51eae7..2a911d0d79 100644 --- a/Source/NETworkManager/Controls/DragablzTabHostWindow.xaml +++ b/Source/NETworkManager/Controls/DragablzTabHostWindow.xaml @@ -160,6 +160,26 @@ Header="{x:Static localization:Strings.CtrlAltDel}" Command="{Binding Data.RemoteDesktop_SendCtrlAltDelCommand, Source={StaticResource BindingProxy}}" CommandParameter="{Binding View}" /> + + + + + diff --git a/Source/NETworkManager/Controls/DragablzTabHostWindow.xaml.cs b/Source/NETworkManager/Controls/DragablzTabHostWindow.xaml.cs index a98b7233ac..2d3140870b 100644 --- a/Source/NETworkManager/Controls/DragablzTabHostWindow.xaml.cs +++ b/Source/NETworkManager/Controls/DragablzTabHostWindow.xaml.cs @@ -222,16 +222,31 @@ private void RemoteDesktop_AdjustScreenAction(object view) } public ICommand RemoteDesktop_SendCtrlAltDelCommand => - new RelayCommand(RemoteDesktop_SendCtrlAltDelAction, RemoteDesktop_IsConnectedAndNotViewOnly_CanExecute); + new RelayCommand(view => RemoteDesktop_SendKeyAction(view, Keystroke.CtrlAltDel), RemoteDesktop_IsConnectedAndNotViewOnly_CanExecute); - private async void RemoteDesktop_SendCtrlAltDelAction(object view) + public ICommand RemoteDesktop_SendTaskManagerCommand => + new RelayCommand(view => RemoteDesktop_SendKeyAction(view, Keystroke.TaskManager), RemoteDesktop_IsConnectedAndNotViewOnly_CanExecute); + + public ICommand RemoteDesktop_SendLockCommand => + new RelayCommand(view => RemoteDesktop_SendKeyAction(view, Keystroke.Lock), RemoteDesktop_IsConnectedAndNotViewOnly_CanExecute); + + public ICommand RemoteDesktop_SendShowDesktopCommand => + new RelayCommand(view => RemoteDesktop_SendKeyAction(view, Keystroke.ShowDesktop), RemoteDesktop_IsConnectedAndNotViewOnly_CanExecute); + + public ICommand RemoteDesktop_SendExplorerCommand => + new RelayCommand(view => RemoteDesktop_SendKeyAction(view, Keystroke.Explorer), RemoteDesktop_IsConnectedAndNotViewOnly_CanExecute); + + public ICommand RemoteDesktop_SendRunDialogCommand => + new RelayCommand(view => RemoteDesktop_SendKeyAction(view, Keystroke.RunDialog), RemoteDesktop_IsConnectedAndNotViewOnly_CanExecute); + + private void RemoteDesktop_SendKeyAction(object view, Keystroke keystroke) { if (view is not RemoteDesktopControl control) return; try { - control.SendKey(Keystroke.CtrlAltDel); + control.SendKey(keystroke); } catch (Exception ex) { diff --git a/Source/NETworkManager/Controls/RemoteDesktopControl.xaml.cs b/Source/NETworkManager/Controls/RemoteDesktopControl.xaml.cs index d4542884ea..65b938e309 100644 --- a/Source/NETworkManager/Controls/RemoteDesktopControl.xaml.cs +++ b/Source/NETworkManager/Controls/RemoteDesktopControl.xaml.cs @@ -508,7 +508,7 @@ public void SendKey(Keystroke keystroke) RdpClient.Focus(); - ocx.SendKeys(info.KeyData.Length, info.ArrayKeyUp, info.KeyData); + ocx?.SendKeys(info.KeyData.Length, info.ArrayKeyUp, info.KeyData); } /// diff --git a/Source/NETworkManager/ViewModels/RemoteDesktopHostViewModel.cs b/Source/NETworkManager/ViewModels/RemoteDesktopHostViewModel.cs index 7906161cc2..3b8f753d25 100644 --- a/Source/NETworkManager/ViewModels/RemoteDesktopHostViewModel.cs +++ b/Source/NETworkManager/ViewModels/RemoteDesktopHostViewModel.cs @@ -351,16 +351,31 @@ private void AdjustScreenAction(object view) } public ICommand SendCtrlAltDelCommand => - new RelayCommand(SendCtrlAltDelAction, IsConnectedAndNotViewOnly_CanExecute); + new RelayCommand(view => SendKeyAction(view, Keystroke.CtrlAltDel), IsConnectedAndNotViewOnly_CanExecute); - private async void SendCtrlAltDelAction(object view) + public ICommand SendTaskManagerCommand => + new RelayCommand(view => SendKeyAction(view, Keystroke.TaskManager), IsConnectedAndNotViewOnly_CanExecute); + + public ICommand SendLockCommand => + new RelayCommand(view => SendKeyAction(view, Keystroke.Lock), IsConnectedAndNotViewOnly_CanExecute); + + public ICommand SendShowDesktopCommand => + new RelayCommand(view => SendKeyAction(view, Keystroke.ShowDesktop), IsConnectedAndNotViewOnly_CanExecute); + + public ICommand SendExplorerCommand => + new RelayCommand(view => SendKeyAction(view, Keystroke.Explorer), IsConnectedAndNotViewOnly_CanExecute); + + public ICommand SendRunDialogCommand => + new RelayCommand(view => SendKeyAction(view, Keystroke.RunDialog), IsConnectedAndNotViewOnly_CanExecute); + + private async void SendKeyAction(object view, Keystroke keystroke) { if (view is not RemoteDesktopControl control) return; try { - control.SendKey(Keystroke.CtrlAltDel); + control.SendKey(keystroke); } catch (Exception ex) { diff --git a/Source/NETworkManager/Views/RemoteDesktopHostView.xaml b/Source/NETworkManager/Views/RemoteDesktopHostView.xaml index 1eac70dca0..62cf5c13e0 100644 --- a/Source/NETworkManager/Views/RemoteDesktopHostView.xaml +++ b/Source/NETworkManager/Views/RemoteDesktopHostView.xaml @@ -142,6 +142,21 @@ + + + + + diff --git a/Website/docs/application/remote-desktop.md b/Website/docs/application/remote-desktop.md index ff83017118..4bc90a09e7 100644 --- a/Website/docs/application/remote-desktop.md +++ b/Website/docs/application/remote-desktop.md @@ -37,6 +37,11 @@ Right-clicking a session tab opens a context menu: | **Adjust screen** | Adjusts the screen size to the current view size; only available if [Display](#display) is set to `Adjust screen automatically` or `Use the current view size as screen size` (only if connected) | | **View only** | Toggles [view only](#view-only) mode, which blocks keyboard and mouse input to the remote session while the screen keeps updating (only if connected) | | **Keyboard shortcuts > Ctrl+Alt+Del** | Sends Ctrl+Alt+Del to the remote computer (only if connected and not in view only mode) | +| **Keyboard shortcuts > Task Manager** | Sends Ctrl+Shift+Esc to the remote computer, opening Task Manager directly (only if connected and not in view only mode) | +| **Keyboard shortcuts > Lock** | Sends Win+L to the remote computer, locking the session (only if connected and not in view only mode) | +| **Keyboard shortcuts > Show Desktop** | Sends Win+D to the remote computer, minimizing all windows (only if connected and not in view only mode) | +| **Keyboard shortcuts > Explorer** | Sends Win+E to the remote computer, opening File Explorer (only if connected and not in view only mode) | +| **Keyboard shortcuts > Run dialog** | Sends Win+R to the remote computer, opening the Run dialog (only if connected and not in view only mode) | ## Connect @@ -127,7 +132,7 @@ Connect to the admin (console) session of the remote computer. ### View only -Connect in view only mode. Keyboard and mouse input to the remote session is blocked while the screen keeps updating, so the session can be monitored without interacting with it. View only mode can also be toggled on the fly via the [tab context menu](#tab-context-menu). While it is active, an eye icon is shown on the tab and the **Fullscreen** and **Ctrl+Alt+Del** actions are disabled to prevent bypassing it. +Connect in view only mode. Keyboard and mouse input to the remote session is blocked while the screen keeps updating, so the session can be monitored without interacting with it. View only mode can also be toggled on the fly via the [tab context menu](#tab-context-menu). While it is active, an eye icon is shown on the tab and the **Fullscreen** action and all **Keyboard shortcuts** are disabled to prevent bypassing it. **Type:** `Boolean` From abc00ec1c9717bd3e14d64ed116cd02936bd6f41 Mon Sep 17 00:00:00 2001 From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> Date: Wed, 24 Jun 2026 01:33:02 +0200 Subject: [PATCH 2/2] Docs: #3500 --- Website/docs/changelog/next-release.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Website/docs/changelog/next-release.md b/Website/docs/changelog/next-release.md index 89ffa06c2c..dcb28741fd 100644 --- a/Website/docs/changelog/next-release.md +++ b/Website/docs/changelog/next-release.md @@ -70,7 +70,8 @@ Release date: **xx.xx.2025** **Remote Desktop** -- New **View only** mode to monitor a session without sending input: keyboard and mouse are blocked while the screen keeps updating. It can be enabled in the connect dialog, per profile/group, and globally (inherited Global → Group → Profile), or toggled on the fly via the tab's right-click menu. An eye icon on the tab indicates when a session is view-only, and the **Fullscreen** and **Ctrl+Alt+Del** actions are disabled while it is active to prevent bypassing it. [#3482](https://github.com/BornToBeRoot/NETworkManager/pull/3482) +- New **View only** mode to monitor a session without sending input: keyboard and mouse are blocked while the screen keeps updating. It can be enabled in the connect dialog, per profile/group, and globally (inherited Global → Group → Profile), or toggled on the fly via the tab's right-click menu. An eye icon on the tab indicates when a session is view-only, and the **Fullscreen** action and all **Keyboard shortcuts** are disabled while it is active to prevent bypassing it. [#3482](https://github.com/BornToBeRoot/NETworkManager/pull/3482) +- The tab context menu's **Keyboard shortcuts** submenu now also includes **Task Manager** (`Ctrl+Shift+Esc`), **Lock** (`Win+L`), **Show Desktop** (`Win+D`), **Explorer** (`Win+E`) and **Run dialog** (`Win+R`), in addition to the existing **Ctrl+Alt+Del**. Like Ctrl+Alt+Del, these are sent directly via scan codes into the remote session, bypassing local key interception. [#3500](https://github.com/BornToBeRoot/NETworkManager/pull/3500) **Language**