Bobby Byrnes
Bobby Byrnes

Reputation: 430

Get cursor position relative to current screen in multi-monitor environments?

I am working on an application that will draw a screen capture box on the screen around the user's mouse coordinates. I am trying to get this to work across multiple monitors. Using Cursor.Position I can get the global coordinates and determine what screen the user is on, but because the coordinates I receive are global and not relative to the monitor it is on, I am running into difficulties converting the global coordinates to screen-relative positioning.

I can use basic logic to get the relative coordinates when the monitors are all lined up vertically, but I am unsure how to approach the problem when the monitors are set up in a unique fashion (i.e. Not all monitors are the same size, one is to the right of two vertical monitors, etc.)

Here is what I have so far:

_screens = ScreenHelper.GetMonitorsInfo();
CursorPosition = Cursor.Position;
var currentDevice = Screen.FromPoint(CursorPosition);

if (!currentDevice.Primary)
{
    // If the current screen is not the primary monitor, we need to calculate the cursor's current position relative to the screen.
    //Find the position in the screens array that the cursor is located, then the position of the primary display.
    var cursorIndex = _screens.IndexOf(_screens.Find(x => x.DeviceName == currentDevice.DeviceName));
    var primaryIndex = _screens.IndexOf(_screens.Find(x => x.DeviceName == Screen.PrimaryScreen.DeviceName));

    //Cursor is to the right of primary screen.
    if (primaryIndex > cursorIndex)
    {
        for (int i = cursorIndex + 1; i <= primaryIndex; i++)
        {
            CursorPosition = new Point(CursorPosition.X - _screens[i].HorizontalResolution, CursorPosition.Y);
        }
    }
    //Cursor is to the left of primary screen.
    else
    {
        for (int i = cursorIndex - 1; i >= primaryIndex; i--)
        {
            CursorPosition = new Point(CursorPosition.X + _screens[i].HorizontalResolution, CursorPosition.Y);
        }
    }
}

public static List<DeviceInfo> GetMonitorsInfo()
{
    _result = new List<DeviceInfo>();
    EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, MonitorEnum, IntPtr.Zero);
    return _result;
}

[DllImport("user32.dll")]
private static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumDelegate lpfnEnum, IntPtr dwData);

I'm part way there, but I am unsure how to take into account horizontal or even diagonally relative monitor positioning. How can I effectively get the Mouse Coordinates relative to the screen the cursor is currently on?

Upvotes: 2

Views: 3442

Answers (2)

Chaphasilor
Chaphasilor

Reputation: 51

There's a very easy way to do this:

Helper functions:

// to get the currently active display's bounding rectangle
public Rectangle GetCurrentDisplaySize()
{
  return System.Windows.Forms.Screen.FromPoint(System.Windows.Forms.Cursor.Position).Bounds;
}

// to get the current cursor position
public System.Drawing.Point GetCurrentCursorPosition()
{
  return System.Windows.Forms.Cursor.Position;
}

Usage:

// always reload the display properties as the active display could change in multi-monitor setups
Rectangle displayDimensions = GetCurrentDisplaySize();
Point cursorPos = GetCurrentCursorPosition();
int cursorRelativeToDisplayX = cursorPos.X - displayDimensions.X
int cursorRelativeToDisplayY = cursorPos.Y - displayDimensions.Y

This will subtract the active display's position offset from the cursor position, resulting in the cursor position relative to the active display's origin (0,0).
And that's it, there's nothing more to it ¯\_(ツ)_/¯

Upvotes: 1

Bobby Byrnes
Bobby Byrnes

Reputation: 430

It turns out I don't need to work so hard to hand-roll the conversion. The PointToClient method did the trick of converting global coordinates to form-relative coordinates. In my case, I just had a transparent form spawn on each screen, determined which form was the active form (the one containing the mouse cursor) by using the currentDevice variable above, then used the PointToClient method on the active form to convert the coordinates.

https://stackoverflow.com/a/19165028/3911065

Upvotes: 1

Related Questions