Reputation: 73
I'm working on an app that takes touches/pen input from an Android device and sends them to PC. The overwhelming majority of it is done but now I'm working on things like monitor switching and other little niceties.. I've run into a hiccup.
I have four monitors. Arranged physically like:
\\.\DISPLAY3
\\.\DISPLAY2
\\.\DISPLAY1
\\.\DISPLAY4
If I use the Windows.Forms.Screen
class to get bounds it says my primary monitor (\\.\DISPLAY2
) is {X=0,Y=0,Width=1920,Height=1080}. This, of course, is because of the Virtual Screen; primary monitor defines <0,0>. I understand that much.
Ok, so let's say I send InjectSyntheticPointerInput
with the coordinates <960, 540>
. This should touch the center of my primary monitor. Instead, it is the center of \\.\DISPLAY3
(the left-most monitor). I... what? The reported bounds of \\.\DISPLAY3
are {X=-1920,Y=0,Width=1920,Height=1080}
So, I took a guess at it and sent <960 + 1920, 540>
(offsetting by the lowest given X coordinate). It worked, dead center of my primary monitor. Ok, so I need physical location not virtual screen.
So I attempted more WinAPI calls to get the information directly. Imported EnumDisplayMonitors
and used that to get the information I need. Nope. that reports the exact same bounds. GetMonitorInfo
... Nope, that's the same info. Is there no way to query the physical monitor location?
Now, I could take the lowest X and lowest Y values and offset every other monitor's coordinates based off that, thereby "zero'ing" the lowest point and redefining the origin, but is that the "correct" way to do this? Is there a better way to query physical coordinates instead of virtual screen coordinates?
Upvotes: 1
Views: 64
Reputation: 73
The comment by IInspectable pointed me to exactly what I need so I created this helper class to get the information and translate the bounding rectangle. What's even nicer is it doesn't require GetMonitorInfo
as it works with the C# Screen class.
using System.Runtime.InteropServices;
namespace AndroPen.Helpers;
internal static class ScreenUtils
{
[DllImport( "user32.dll", SetLastError = true )]
private static extern int GetSystemMetrics( [In] int nIndex );
// Get the origin of the virtual screen.
private const int SM_XVIRTUALSCREEN = 76;
private const int SM_YVIRTUALSCREEN = 77;
// Get the origin position as the offset.
internal static Point Offset => new()
{
X = GetSystemMetrics( SM_XVIRTUALSCREEN ),
Y = GetSystemMetrics( SM_YVIRTUALSCREEN ),
};
// Extension method for the Screen class to translate
// the coordinates to be virtual screen relative.
internal static Rectangle Translate(this Screen s)
{
return new()
{
X = s.Bounds.X - Offset.X,
Y = s.Bounds.Y - Offset.Y,
Width = s.Bounds.Width,
Height = s.Bounds.Height
};
}
}
Upvotes: 0