(C#) Use ClipCursor to block the mouse from going to a specific monitor

Elias Youssef 21 Reputation points
2021-04-02T18:30:19.193+00:00

The functions of ClipCursor and Cursor.Clip are "Confines the cursor to a rectangular area on the screen" and "Gets or sets the bounds that represent the clipping rectangle for the cursor" respectively. They do basically the same thing. So if your monitors are arranged in this way:

84060-example-small.png

You can use ClipCursor to set the bounds to only monitor number 1 (the rectangle's points are (full HD monitors): left = 0, top = 0, right = 1920, bottom = 1080) and your cursor would only be able to move inside monitor number 1 and that would look like this:

84078-example2-small.png

(Filled rectangle = usable monitor, not filled = outside of bounds, can't reach with mouse)

Or you can confine the cursor to monitors 1 and 2 (the rectangle's points are: left = 0, top = 0, right = 3840, bottom = 1080) and your cursor would only be able to move inside monitors number 1 and 2 and that would look like this:

84143-example3-small.png

You can only use a rectangle as the clip bounds, which brings me to my question: can I use ClipCursor to exclude only one monitor from the clip bounds? like so:

Image

Windows Forms
Windows Forms
A set of .NET Framework managed libraries for developing graphical user interfaces.
1,841 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,321 questions
0 comments No comments
{count} votes

Accepted answer
  1. Castorix31 81,836 Reputation points
    2021-04-03T01:47:40.873+00:00

    You can clip the mouse with a LL Mouse Hook
    This test works for me (Windows 10, clip at 400, 1000), but I have only 1 monitor,
    so you will probably have to adapt/recalculate x, y from the hook for multiple monitors =>

    public partial class Form1 : Form
    {
        public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
    
        [DllImport("User32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
    
        [DllImport("User32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern bool UnhookWindowsHookEx(int idHook);
    
        [DllImport("User32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);
    
        public const int WH_MIN = (-1);
        public const int WH_MSGFILTER = (-1);
        public const int WH_JOURNALRECORD = 0;
        public const int WH_JOURNALPLAYBACK = 1;
        public const int WH_KEYBOARD = 2;
        public const int WH_GETMESSAGE = 3;
        public const int WH_CALLWNDPROC = 4;
        public const int WH_CBT = 5;
        public const int WH_SYSMSGFILTER = 6;
        public const int WH_MOUSE = 7;
        public const int WH_HARDWARE = 8;
        public const int WH_DEBUG = 9;
        public const int WH_SHELL = 10;
        public const int WH_FOREGROUNDIDLE = 11;
        public const int WH_CALLWNDPROCRET = 12;
        public const int WH_KEYBOARD_LL = 13;
        public const int WH_MOUSE_LL = 14;
        public const int WH_MAX = 14;
        public const int WH_MINHOOK = WH_MIN;
        public const int WH_MAXHOOK = WH_MAX;
    
        [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct MSLLHOOKSTRUCT
        {
            public System.Drawing.Point pt;
            public int mouseData;
            public int flags;
            public int time;
            public uint dwExtraInfo;
        }
    
        public const int WM_MOUSEMOVE = 0x0200;
        public const int WM_LBUTTONDOWN = 0x0201;
        public const int WM_LBUTTONUP = 0x0202;
        public const int WM_RBUTTONDOWN = 0x0204;
        public const int WM_RBUTTONUP = 0x0205;
    
    
        public Form1()
        {
            //InitializeComponent();
            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
            this.Load += new System.EventHandler(this.Form1_Load);
        }
    
        private static Label label1;
        private static Label label2;
        private static bool bLocked = false;
    
        private static int hHook = 0;
        private HookProc MouseLLProcedure;
    
        private static int nYMax = 400;
        private static int nXMin = 1000;
    
        private void Form1_Load(object sender, EventArgs e)
        {
            label1 = new Label();
            label1.Size = new Size(100, 32);
            label1.Location = new Point(90, 100);
            label1.BorderStyle = BorderStyle.Fixed3D;
            label1.BackColor = Color.Black;
            label1.ForeColor = Color.Yellow;
            label1.Font = new Font("Arial", 8F, FontStyle.Bold, GraphicsUnit.Point, ((byte)(0)));
            label1.TextAlign = ContentAlignment.MiddleCenter;
            this.Controls.Add(label1);
    
            label2 = new Label();          
            label2.AutoSize = true;
            label2.Location = new System.Drawing.Point(70, 60);
            label2.Name = "label2";
            label2.Size = new System.Drawing.Size(35, 13);
            label2.Text = "Right-Click to unlock mouse";
            this.Controls.Add(label2);
    
            bLocked = true;
            MouseLLProcedure = new HookProc(MouseLLProc);
            hHook = SetWindowsHookEx(WH_MOUSE_LL, MouseLLProcedure, (IntPtr)0, 0);
    
            this.Text = "Test LL Mouse Hook";
            this.ClientSize = new System.Drawing.Size(300, 260);
            CenterToScreen();
        }
    
    
        private static Point ptOld;
        public static int MouseLLProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if ((nCode >= 0))
            {
                MSLLHOOKSTRUCT pMSLLHOOKSTRUCT = new MSLLHOOKSTRUCT();
                pMSLLHOOKSTRUCT = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, pMSLLHOOKSTRUCT.GetType());
                label1.Text = pMSLLHOOKSTRUCT.pt.ToString();
    
                if (wParam == (IntPtr)WM_RBUTTONDOWN)
                {
                    bLocked = false;
                    Console.Beep(5000, 10);
                }
    
                if (pMSLLHOOKSTRUCT.pt.Y > nYMax && pMSLLHOOKSTRUCT.pt.X < nXMin && bLocked)
                { 
                    int nNewX = pMSLLHOOKSTRUCT.pt.X;
                    int nNewY = pMSLLHOOKSTRUCT.pt.Y;
                    if (ptOld.Y <= nYMax)
                        nNewY = nYMax;
                    if (ptOld.X >= nXMin)
                        nNewX = nXMin;
                    System.Windows.Forms.Cursor.Position = new System.Drawing.Point(nNewX, nNewY);
                    return 1;                
                }
                ptOld = pMSLLHOOKSTRUCT.pt;
            }
            return nCode < 0 ? CallNextHookEx(hHook, nCode, wParam, lParam) : 0;
        }
    
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (hHook != 0)
                UnhookWindowsHookEx(hHook);
        }
    }
    
    2 people found this answer helpful.

0 additional answers

Sort by: Most helpful