2

I'm trying to simulate mouse input using SendInput, however I need to determine the virtual screen width in case there are multiple monitors, to set the dx and dy values, for example:

dx = (x * 65536) / SystemInformation.VirtualScreen.Width;
dy = (y * 65536) / SystemInformation.VirtualScreen.Height;

The problem is that the monitors apparently have different DPI values, which results in an incorrect virtual size. For reference, both SystemInformation.VirtualScreen.Size and calls to GetSystemMetrics(SM_CXVIRTUALSCREEN) return the same incorrect values.

I tried using GetSystemMetricsForDPI with no success either.

Yves Calaci
  • 1,019
  • 1
  • 11
  • 37
  • Does it help? https://stackoverflow.com/a/62798145/126995 – Soonts Mar 02 '21 at 06:29
  • @Soonts no. You're talking about scalling the application. I'm trying to compute the virtual screen size as stated in the title. – Yves Calaci Mar 02 '21 at 06:46
  • 1
    These DPI virtualization shenanigans don’t just scale the application’s GUI, they affect many OS APIs, including both SystemInformation.VirtualScreen.Size and GetSystemMetrics. When the app declares it supports per-monitor DPI, Windows stops lying about screen sizes, these API will then return you true hardware pixels. – Soonts Mar 02 '21 at 06:50
  • Wait, this actually does solve the problem, but why? The sample manifest states: `Indicates that the application is DPI-aware and will not be automatically scaled by Windows at higher DPIs.` It also states the WPF applications have this by default, but I'm actually doing this in a WPF app using `SystemParameters.VirtualScreenWidth` and the results aren't right. I'll take a look at this again. – Yves Calaci Mar 02 '21 at 06:52

1 Answers1

3

By default, Windows applies DPI virtualization to all coordinates.

If you have 2 displays, secondary FullHD on the left with 100% scaling, and primary 4k on the right with 200% DPI scaling, the APIs for screen configuration gonna tell you the desktop has 3840x1080 pixels, the secondary one from [-1920 .. 0], the primary one [0 .. 1920]. To simulate mouse input at the center of the left monitor, you should use X coordinate -960 * 0x10000 / 1920 = -32768 without MOUSEEVENTF_VIRTUALDESK flag, or 960 * 0x10000 / 3840 = 16384 with MOUSEEVENTF_VIRTUALDESK flag

You can tell Windows to stop messing with DPI in your application, with a manifest.

If you do that on the same computer, the APIs for screen configuration gonna tell you the desktop has 5760x2160 pixels, the secondary one is the same, in [-1920 .. 0 ], the primary one [ 0 .. 3840 ]. To send mouse input to the center of the left monitor in this case, you should use X coordinate -960 * 0x10000 / 3840 = -16384 without MOUSEEVENTF_VIRTUALDESK flag, or 960 * 0x10000 / 5760 = 10923 with MOUSEEVENTF_VIRTUALDESK flag.

Soonts
  • 20,079
  • 9
  • 57
  • 130