Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion Source/NETworkManager.Localization/Resources/Strings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions Source/NETworkManager.Localization/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -2250,6 +2250,21 @@ $$hostname$$ --&gt; Hostname</value>
<data name="CtrlAltDel" xml:space="preserve">
<value>Ctrl+Alt+Del</value>
</data>
<data name="TaskManager" xml:space="preserve">
<value>Task Manager (Ctrl+Shift+Esc)</value>
</data>
<data name="Lock" xml:space="preserve">
<value>Lock (Win+L)</value>
</data>
<data name="ShowDesktop" xml:space="preserve">
<value>Show Desktop (Win+D)</value>
</data>
<data name="Explorer" xml:space="preserve">
<value>Explorer (Win+E)</value>
</data>
<data name="RunDialog" xml:space="preserve">
<value>Run dialog (Win+R)</value>
</data>
<data name="KeyboardShortcuts" xml:space="preserve">
<value>Keyboard shortcuts</value>
</data>
Expand Down
27 changes: 26 additions & 1 deletion Source/NETworkManager.Models/RemoteDesktop/Keystroke.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,30 @@ public enum Keystroke
/// <summary>
/// Ctrl + Alt + Del keystroke.
/// </summary>
CtrlAltDel
CtrlAltDel,

/// <summary>
/// Ctrl + Shift + Esc keystroke (opens Task Manager).
/// </summary>
TaskManager,

/// <summary>
/// Win + L keystroke (locks the session).
/// </summary>
Lock,

/// <summary>
/// Win + D keystroke (shows the desktop / minimizes all windows).
/// </summary>
ShowDesktop,

/// <summary>
/// Win + E keystroke (opens File Explorer).
/// </summary>
Explorer,

/// <summary>
/// Win + R keystroke (opens the Run dialog).
/// </summary>
RunDialog
}
20 changes: 20 additions & 0 deletions Source/NETworkManager.Models/RemoteDesktop/RemoteDesktop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
20 changes: 20 additions & 0 deletions Source/NETworkManager/Controls/DragablzTabHostWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,26 @@
Header="{x:Static localization:Strings.CtrlAltDel}"
Command="{Binding Data.RemoteDesktop_SendCtrlAltDelCommand, Source={StaticResource BindingProxy}}"
CommandParameter="{Binding View}" />
<MenuItem
Header="{x:Static localization:Strings.TaskManager}"
Command="{Binding Data.RemoteDesktop_SendTaskManagerCommand, Source={StaticResource BindingProxy}}"
CommandParameter="{Binding View}" />
<MenuItem
Header="{x:Static localization:Strings.Lock}"
Command="{Binding Data.RemoteDesktop_SendLockCommand, Source={StaticResource BindingProxy}}"
CommandParameter="{Binding View}" />
<MenuItem
Header="{x:Static localization:Strings.ShowDesktop}"
Command="{Binding Data.RemoteDesktop_SendShowDesktopCommand, Source={StaticResource BindingProxy}}"
CommandParameter="{Binding View}" />
<MenuItem
Header="{x:Static localization:Strings.Explorer}"
Command="{Binding Data.RemoteDesktop_SendExplorerCommand, Source={StaticResource BindingProxy}}"
CommandParameter="{Binding View}" />
<MenuItem
Header="{x:Static localization:Strings.RunDialog}"
Command="{Binding Data.RemoteDesktop_SendRunDialogCommand, Source={StaticResource BindingProxy}}"
CommandParameter="{Binding View}" />
</MenuItem>
</ContextMenu>
</Grid.ContextMenu>
Expand Down
21 changes: 18 additions & 3 deletions Source/NETworkManager/Controls/DragablzTabHostWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/// <summary>
Expand Down
21 changes: 18 additions & 3 deletions Source/NETworkManager/ViewModels/RemoteDesktopHostViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
15 changes: 15 additions & 0 deletions Source/NETworkManager/Views/RemoteDesktopHostView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,21 @@
<MenuItem Header="{x:Static localization:Strings.CtrlAltDel}"
Command="{Binding Data.SendCtrlAltDelCommand, Source={StaticResource BindingProxy}}"
CommandParameter="{Binding View}" />
<MenuItem Header="{x:Static localization:Strings.TaskManager}"
Command="{Binding Data.SendTaskManagerCommand, Source={StaticResource BindingProxy}}"
CommandParameter="{Binding View}" />
<MenuItem Header="{x:Static localization:Strings.Lock}"
Command="{Binding Data.SendLockCommand, Source={StaticResource BindingProxy}}"
CommandParameter="{Binding View}" />
<MenuItem Header="{x:Static localization:Strings.ShowDesktop}"
Command="{Binding Data.SendShowDesktopCommand, Source={StaticResource BindingProxy}}"
CommandParameter="{Binding View}" />
<MenuItem Header="{x:Static localization:Strings.Explorer}"
Command="{Binding Data.SendExplorerCommand, Source={StaticResource BindingProxy}}"
CommandParameter="{Binding View}" />
<MenuItem Header="{x:Static localization:Strings.RunDialog}"
Command="{Binding Data.SendRunDialogCommand, Source={StaticResource BindingProxy}}"
CommandParameter="{Binding View}" />
</MenuItem>
</ContextMenu>
</Grid.ContextMenu>
Expand Down
7 changes: 6 additions & 1 deletion Website/docs/application/remote-desktop.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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`

Expand Down
3 changes: 2 additions & 1 deletion Website/docs/changelog/next-release.md
Original file line number Diff line number Diff line change
Expand Up @@ -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**

Expand Down
Loading