question

EliasYoussef-9404 avatar image
0 Votes"
EliasYoussef-9404 asked simonberrurier-7045 commented

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

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


dotnet-csharpwindows-forms
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

Castorix31 avatar image
1 Vote"
Castorix31 answered simonberrurier-7045 commented

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
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thank you very much.

0 Votes 0 ·

If this answer helped, you can mark it as accepted which would be much more efficient for other community members to find useful information

1 Vote 1 ·