Skip to content

Commit 097840b

Browse files
committed
Feature: RDP scaling
1 parent 2b37134 commit 097840b

File tree

6 files changed

+118
-65
lines changed

6 files changed

+118
-65
lines changed

Source/NETworkManager/Controls/DragablzTabHostWindow.xaml.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ private void RemoteDesktop_FullscreenAction(object view)
212212
private void RemoteDesktop_AdjustScreenAction(object view)
213213
{
214214
if (view is RemoteDesktopControl control)
215-
control.AdjustScreen();
215+
control.AdjustScreen(force:true);
216216
}
217217

218218
public ICommand RemoteDesktop_SendCtrlAltDelCommand =>

Source/NETworkManager/Controls/IDragablzTabItem.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ public interface IDragablzTabItem
1313
/// </summary>
1414
public void CloseTab()
1515
{
16+
1617
}
1718
}

Source/NETworkManager/Controls/RemoteDesktopControl.xaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
xmlns:localization="clr-namespace:NETworkManager.Localization.Resources;assembly=NETworkManager.Localization"
1010
xmlns:local="clr-namespace:NETworkManager.Controls"
1111
xmlns:settings="clr-namespace:NETworkManager.Settings;assembly=NETworkManager.Settings"
12-
xmlns:windowsForms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
1312
mc:Ignorable="d" Loaded="UserControl_Loaded"
1413
d:DataContext="{d:DesignInstance local:RemoteDesktopControl}">
1514
<local:UserControlBase.Resources>

Source/NETworkManager/Controls/RemoteDesktopControl.xaml.cs

Lines changed: 101 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
using System.Threading.Tasks;
1313
using System.Windows;
1414
using System.Windows.Input;
15-
using System.Windows.Threading;
1615

1716
namespace NETworkManager.Controls;
1817

@@ -353,48 +352,95 @@ public void FullScreen()
353352
RdpClient.FullScreen = true;
354353
}
355354

356-
public async void AdjustScreen(bool dpiChange = false)
355+
public async void AdjustScreen(bool force = false)
357356
{
358-
// Check preconditions
359-
if (IsConnecting)
360-
return;
361-
362-
if (!IsConnected)
363-
return;
364-
365-
// Wait for the control to be drawn (if window is resized or the DPI changes)
366-
await Task.Delay(250);
367-
368-
var desktopSize = GetDesktopSize();
369-
370-
// Check if we need to adjust the screen (always on DPI changes)
371-
if (dpiChange == false)
357+
try
372358
{
373-
if (RdpClient.DesktopWidth == desktopSize.Item1 && RdpClient.DesktopHeight == desktopSize.Item2)
359+
// Check preconditions
360+
if (IsConnecting)
374361
{
375-
Debug.WriteLine("==>>> Screen size is already correct.");
362+
Log.Debug("AdjustScreen - RDP session is connecting... We can't adjust the screen, yet.");
376363
return;
377364
}
378365

379-
380-
if (RdpClient.Width == desktopSize.Item1 && RdpClient.Height == desktopSize.Item2)
366+
if (!IsConnected)
381367
{
382-
Debug.WriteLine("==>>> Screen size is already correct.");
368+
Log.Debug("AdjustScreen - RDP session is not connected! We can't adjust the screen.");
383369
return;
384370
}
385-
}
386371

387-
try
388-
{
389-
Debug.WriteLine("UpdateSessionDisplaySettings...");
372+
// Wait for the control to be drawn (if window is resized or the DPI changes)
373+
await Task.Delay(250);
374+
375+
var desktopSize = GetDesktopSize();
376+
377+
Log.Debug($"AdjustScreen - Desktop size: {desktopSize.Item1}x{desktopSize.Item2}");
378+
379+
// Check if we need to adjust the screen (always on DPI changes or manual)
380+
if (force == false)
381+
{
382+
var needUpdate = false;
383+
384+
var windowsFormsHostSize = GetWindowsFormsHostSize(desktopSize.Item1, desktopSize.Item2);
385+
386+
Log.Debug($"AdjustScreen - WindowsFormsHost size: {windowsFormsHostSize.Item1}x{windowsFormsHostSize.Item2}");
387+
388+
if (!(Math.Abs(WindowsFormsHostMaxWidth - windowsFormsHostSize.Item1) < double.Epsilon) ||
389+
!(Math.Abs(WindowsFormsHostMaxHeight - windowsFormsHostSize.Item2) < double.Epsilon))
390+
{
391+
Log.Debug("AdjustScreen - WindowsFormsHost size is not adjusted!" +
392+
$" Old size: {WindowsFormsHostMaxWidth}x{WindowsFormsHostMaxHeight}, new size: {windowsFormsHostSize.Item1}x{windowsFormsHostSize.Item2}");
393+
needUpdate = true;
394+
}
395+
396+
397+
if (!(Math.Abs(RdpClient.Width - desktopSize.Item1) < double.Epsilon) ||
398+
!(Math.Abs(RdpClient.Height - desktopSize.Item2) < double.Epsilon))
399+
{
400+
Log.Debug("AdjustScreen - RDP control size is not adjusted!" +
401+
$" Old size: {RdpClient.Width}x{RdpClient.Height}, new size: {desktopSize.Item1}x{desktopSize.Item2}");
402+
needUpdate = true;
403+
}
404+
405+
if (!(Math.Abs(RdpClient.DesktopWidth - desktopSize.Item1) < double.Epsilon) ||
406+
!(Math.Abs(RdpClient.DesktopHeight - desktopSize.Item2) < double.Epsilon))
407+
{
408+
Log.Debug("AdjustScreen - RDP session size is not adjusted!" +
409+
$" Old size: {RdpClient.DesktopWidth}x{RdpClient.DesktopHeight}, new size: {desktopSize.Item1}x{desktopSize.Item2}");
410+
needUpdate = true;
411+
}
412+
413+
if (needUpdate)
414+
{
415+
Log.Debug("AdjustScreen - Adjusting screen size...");
416+
}
417+
else
418+
{
419+
Log.Debug("AdjustScreen - Screen size is already adjusted!");
420+
return;
421+
}
422+
}
423+
else
424+
{
425+
Log.Debug("AdjustScreen - Screen size adjustment is forced...");
426+
}
427+
390428
// Fix the size of the WindowsFormsHost and the RDP control
391429
FixWindowsFormsHostSize(desktopSize.Item1, desktopSize.Item2);
392-
// This may fail if the RDP session was connected recently
393-
RdpClient.UpdateSessionDisplaySettings((uint)desktopSize.Item1, (uint)desktopSize.Item2, (uint)desktopSize.Item1, (uint)desktopSize.Item2, 0, GetDesktopScaleFactor(), GetDeviceScaleFactor());
430+
431+
try
432+
{
433+
// This may fail if the RDP session was connected recently
434+
RdpClient.UpdateSessionDisplaySettings((uint)desktopSize.Item1, (uint)desktopSize.Item2, (uint)desktopSize.Item1, (uint)desktopSize.Item2, 0, GetDesktopScaleFactor(), GetDeviceScaleFactor());
435+
}
436+
catch (Exception ex)
437+
{
438+
Log.Error("Error while updating the session display settings of the RDP control!", ex);
439+
}
394440
}
395-
catch (Exception ex)
441+
catch (Exception e)
396442
{
397-
Log.Error("Error while adjusting screen", ex);
443+
Log.Error("Could not adjust screen!", e);
398444
}
399445
}
400446

@@ -406,25 +452,30 @@ public async void AdjustScreen(bool dpiChange = false)
406452
/// <param name="height">Height of the RDP session.</param>
407453
private void FixWindowsFormsHostSize(double width, double height)
408454
{
409-
var widthScaled = width / GetDpiScaleFactor() * 100;
410-
var heightScaled = height / GetDpiScaleFactor() * 100;
411-
412-
widthScaled = Math.Ceiling(widthScaled / 2) * 2;
413-
heightScaled = Math.Ceiling(heightScaled / 2) * 2;
455+
var windowsFormsHostSize = GetWindowsFormsHostSize(width, height);
414456

415457
// Set the max width and height for the WindowsFormsHost
416-
WindowsFormsHostMaxWidth = widthScaled;
417-
WindowsFormsHostMaxHeight = heightScaled;
458+
WindowsFormsHostMaxWidth = windowsFormsHostSize.Item1;
459+
WindowsFormsHostMaxHeight = windowsFormsHostSize.Item2;
418460

419461
// Update the size of the RDP control
420462
RdpClient.Width = (int)width;
421463
RdpClient.Height = (int)height;
422-
423-
Debug.WriteLine($"RDP control size: {RdpClient.Width}x{RdpClient.Height}");
424-
Debug.WriteLine($"WindowsFormsHost size: {WindowsFormsHostMaxWidth}x{WindowsFormsHostMaxHeight}");
425-
Debug.WriteLine($"Values: {width}x{height} - DPI: {GetDpiScaleFactor()}%");
426464
}
427465

466+
private Tuple<double, double> GetWindowsFormsHostSize(double width, double height)
467+
{
468+
var scaleFactor = GetDpiScaleFactor();
469+
470+
var widthScaled = width / scaleFactor * 100;
471+
var heightScaled = height / scaleFactor * 100;
472+
473+
widthScaled = Math.Ceiling(widthScaled / 2) * 2;
474+
heightScaled = Math.Ceiling(heightScaled / 2) * 2;
475+
476+
return new Tuple<double, double>(widthScaled, heightScaled);
477+
}
478+
428479
/// <summary>
429480
/// Send a keystroke to the remote session.
430481
/// </summary>
@@ -575,25 +626,17 @@ private static string GetDisconnectReason(int reason)
575626
/// https://cdnweb.devolutions.net/blog/pdf/smart-resizing-and-high-dpi-issues-in-remote-desktop-manager.pdf
576627
/// </summary>
577628
/// <returns></returns>
578-
protected uint GetDesktopScaleFactor()
629+
private uint GetDesktopScaleFactor()
579630
{
580631
var scaleFactor = GetDpiScaleFactor();
581632

582-
switch (scaleFactor)
633+
return scaleFactor switch
583634
{
584-
case 125:
585-
return 125;
586-
case 150:
587-
case 175:
588-
return 150;
589-
case 200:
590-
return 200;
591-
}
592-
593-
if (scaleFactor > 200)
594-
return 200;
595-
596-
return 100;
635+
125 => 125,
636+
150 or 175 => 150,
637+
200 => 200,
638+
_ => (uint)(scaleFactor > 200 ? 200 : 100)
639+
};
597640
}
598641

599642
/// <summary>
@@ -604,7 +647,7 @@ protected uint GetDesktopScaleFactor()
604647
/// https://cdnweb.devolutions.net/blog/pdf/smart-resizing-and-high-dpi-issues-in-remote-desktop-manager.pdf
605648
/// </summary>
606649
/// <returns>Device scale factor.</returns>
607-
protected uint GetDeviceScaleFactor()
650+
private uint GetDeviceScaleFactor()
608651
{
609652
var scaleFactor = GetDpiScaleFactor();
610653

@@ -628,7 +671,7 @@ protected uint GetDeviceScaleFactor()
628671
/// Get the current DPI scale factor like 100, 125, 150, 175, 200, 225, etc.
629672
/// </summary>
630673
/// <returns>Returns the DPI scale factor.</returns>
631-
public int GetDpiScaleFactor()
674+
private int GetDpiScaleFactor()
632675
{
633676
var x = System.Windows.Media.VisualTreeHelper.GetDpi(this);
634677

@@ -655,15 +698,12 @@ private void RdpClient_OnDisconnected(object sender, IMsTscAxEvents_OnDisconnect
655698

656699
public void UpdateOnWindowResize()
657700
{
658-
659-
Debug.WriteLine("UpdateOnWindowResize...");
660-
661701
if (_sessionInfo.AdjustScreenAutomatically)
662702
AdjustScreen();
663703
}
664704

665705
private void WindowsFormsHost_DpiChanged(object sender, DpiChangedEventArgs e)
666706
{
667-
AdjustScreen(dpiChange: true);
707+
AdjustScreen(force: true);
668708
}
669709
}

Source/NETworkManager/ViewModels/RemoteDesktopHostViewModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ private void FullscreenAction(object view)
281281
private void AdjustScreenAction(object view)
282282
{
283283
if (view is RemoteDesktopControl control)
284-
control.AdjustScreen();
284+
control.AdjustScreen(force:true);
285285
}
286286

287287
public ICommand SendCtrlAltDelCommand => new RelayCommand(SendCtrlAltDelAction, IsConnected_CanExecute);

Website/docs/changelog/next-release.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ Release date: **xx.xx.2024**
1717

1818
## Breaking Changes
1919

20-
- Minimum supported Windows version increased to `22H2`. [#2912](https://github.com/BornToBeRoot/NETworkManager/pull/2912)
20+
- Minimum supported Windows version increased to `22H2` to support:
21+
- WiFi 6 GHz, WPA3, 802.11be [#2912](https://github.com/BornToBeRoot/NETworkManager/pull/2912)
22+
- Remote Desktop high DPI, scaling and resizing [#2968](https://github.com/BornToBeRoot/NETworkManager/pull/2968)
2123

2224
## What's new?
2325

@@ -27,6 +29,17 @@ Release date: **xx.xx.2024**
2729
- `WPA3 Personal (SAE)`, `WPA3 Enterprise` and `WPA3 Enterprise (192-bit)` are now supported. [#2912](https://github.com/BornToBeRoot/NETworkManager/pull/2912)
2830
- `802.11be` (`EHT`) is now supported. [#2912](https://github.com/BornToBeRoot/NETworkManager/pull/2912)
2931

32+
- **Remote Desktop**
33+
34+
- Scale rdp session and control to support high DPI (e.g. per Monitor DPI like 125%, 150%, etc.). [#2968](https://github.com/BornToBeRoot/NETworkManager/pull/2968)
35+
- Resizing now uses [`IMsRdpClient9::UpdateSessionDisplaySettings`](<https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/mt703457(v=vs.85)>) instead of [`IMsRdpClient::Reconnect`](https://learn.microsoft.com/en-us/windows/win32/termserv/imsrdpclient8-reconnect) to support scaling and faster resizing (without the need of reconnecting). [#2968](https://github.com/BornToBeRoot/NETworkManager/pull/2968).
36+
37+
:::warning
38+
39+
The new features for high DPI, scaling and resizing may cause issues or doesn't work with legacy servers/clients. Please report any issues you find here: [#2911](https://github.com/BornToBeRoot/NETworkManager/issues/2911)
40+
41+
:::
42+
3043
## Improvements
3144

3245
- Improve ToolTips (e.g. migrate from Twitter to X, etc.), Buttons, etc. [#2955](https://github.com/BornToBeRoot/NETworkManager/pull/2955)

0 commit comments

Comments
 (0)