Hi
I am trying to limit the cursor to a single form on loading. It works fine when testing it in Visual Studio but when I compile the exe the rectangle it limits is bigger than the form also if I change the start up position of the form from windows default to center screen the clip area stays in default windows position- any ideas?

using the following code:
Option Explicit
Private Type RECT
left As Integer
top As Integer
right As Integer
bottom As Integer
End Type

Private Type POINT
x As Long
y As Long
End Type

Private Declare Sub ClipCursor Lib "user32" (lpRect As Any)
Private Declare Sub GetClientRect Lib "user32" (ByVal hWnd As Long, lpRect As RECT)
Private Declare Sub ClientToScreen Lib "user32" (ByVal hWnd As Long, lpPoint As POINT)
Private Declare Sub OffsetRect Lib "user32" (lpRect As RECT, ByVal x As Long, ByVal y As Long)


Private Sub Form_Load()
'limit cursor movement
LimitCursor
End Sub

Private Sub LimitCursor()
Dim client As RECT
Dim upperleft As POINT

GetClientRect Me.hWnd, client
upperleft.x = client.left
upperleft.y = client.top
ClientToScreen Me.hWnd, upperleft
OffsetRect client, upperleft.x, upperleft.y
ClipCursor client

End Sub
Private Sub Form_Unload(Cancel As Integer)
'Releases the cursor limits
ClipCursor ByVal 0&
End Sub

well left, top, right are functions and properties in vb and perhaps you should prefix them with My or MyFormsLeft etc.

then in form load... me.visible=true, prior to your setting the cursor

Good Luck

well left, top, right are functions and properties in vb and perhaps you should prefix them with My or MyFormsLeft etc.

then in form load... me.visible=true, prior to your setting the cursor

Good Luck

Thanks - have tried this but still doesnt work :( I have noticed that the cursor does limit left and top but the clipped area extends to right and bottom. Any more ideas anyone?

In the first place, I would say you should be using functions and not subs for your APIs. That way you can deal with errors. You can't deal with any errors, if you don't have a function that returns a value.

Private Declare Function OffsetRect Lib "user32" _
    (lpRect As RECT, ByVal x As Long, ByVal y As Long) As Long

In the first place, I would say you should be using functions and not subs for your APIs. That way you can deal with errors. You can't deal with any errors, if you don't have a function that returns a value.

Private Declare Function OffsetRect Lib "user32" _
    (lpRect As RECT, ByVal x As Long, ByVal y As Long) As Long

In the second place, a RECT structure consists of 4 coordinates, not 2.

The RECT structure defines the coordinates of the upper-left and lower-right corners of a rectangle. 

typedef struct _RECT { 
    LONG left; 
    LONG top; 
    LONG right; 
    LONG bottom; 
} RECT;

Your custom type does not mimic that of the C structure RECT. Don't expect anything to work, if you don't pay attention to the details in the first place.

Thanks but for such a noob at programming as me that didnt make a great deal of sense

Noob, just use the API viewer in VB and paste and copy the functions, types, or constants in your program.

If you're a noob, why are you messing with APIs anyway?

Thank you for your warm welcome to these forums. It's lovely that people are sooooo nice.

It's lovely that people are sooooo nice.

Well, a typical VB6 noob does not even mess with APIs. He probably doesn't even know what an API is. As a noob, I know I didn't. You have surpassed my noobian beginnings. For whatever that's worth.

And then you have even modified the API call. This is something as an experienced programmer I wouldn't even imagine doing. So as a noob, you have showed great acumen, insight, and intelligence.

I hope you feel better.

Okay, now that, that is over...

Did you change your API to what was suggested and your type as noted above? If so, are you still having problems with the right/bottom areas of rect region?

HINT:
Right = left + width
Bottom = Top + Height

Still problems?

Did you change your scalemode from twips to pixels? (Or you should be able to find calculation code that will convert twips to pixels if you need it).

Good Luck

Well, let's start from base 1. What is the end goal of this code? What exactly is the program trying to achieve?

Good programming practice identifies the function, the purpose, give some pseudo logic on how they hope to achieve their end goal.

' Function: LimitTheCursor
' Purpose: Keep the cursor within a certain area.
' Pseudo Logic: Establish the Client area, Limit the cursor area to 
' that region.
' Method: Use Window API calls
'   ClipCursor, GetClientRect, ClientToScreen, OffsetRect

the rectangle it limits is bigger than the form also if I change the start up position of the form from windows default to center screen the clip area stays in default windows position- any ideas?

From looking at the purposes of the API calls in your code, I would guess you don't need the second or the third: ClientToScreen, or OffsetRect.

I'm guessing you just need to establish the Rect with the first call, and then call your ClipCursor using your established Rect structure.

The ClientToScreen API just converts client coordinates to Screen coordinates. The OffsetRect just changes the RECT coordinates to a different location. I don't see how using those 2 APIs coincides with your stated purpose.

The clip area probably stays in the default area because when you load the program, the RECT values loaded are the default values. The program then changes to center the form, but your code has not taken that into consideration.

You probably should redine your RECT coordinates in the Private Sub Form_Resize event.

Here, this should work. You can modify it to suit your needs.
It appears the GetWindowRect API is the way to go. This limits the cursor to the active windows screen coordinates. But I imagine you can set your RECT type to whatever you like. But it's good practice to find the original Screen Boundaries and then reset those boundaries on unloading the form.

Option Explicit

Private Type RECT
        Left As Long
        Top As Long
        Right As Long
        Bottom As Long
End Type

Private ScreenRect As RECT

Private Declare Function GetClipCursor Lib "user32" _
   (lprc As RECT) As Long
Private Declare Function GetWindowRect Lib "user32" _
   (ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function ClipCursor Lib "user32" _
   (lpRect As Any) As Long


Private Sub cmdCursor_Click()
   Dim MyRect As RECT, lngReturn As Long
   lngReturn = GetClipCursor(MyRect)
   Debug.Print MyRect.Top, MyRect.Left, MyRect.Bottom, MyRect.Right
   
End Sub

Private Sub cmdWindowRect_Click()
   Dim WindowRect As RECT, lngReturn As Long, lngHandle As Long
   Dim intCounter As Integer
   lngHandle = Me.hwnd
   lstResults.Clear
   lngReturn = GetWindowRect(lngHandle, WindowRect)
   
   With WindowRect
      lstResults.AddItem "Top: " & .Top
      lstResults.AddItem "Left: " & .Left
      lstResults.AddItem "Right: " & .Right
      lstResults.AddItem "Bottom: " & .Bottom
   End With
   
   ' Clip cursor to current Window rectangle
   lngReturn = ClipCursor(WindowRect)
End Sub

Private Sub Form_Load()
   Dim lngReturn As Long
   lngReturn = GetClipCursor(ScreenRect)
   stbScreen.Panels(1).Text = ScreenRect.Right & ", " & ScreenRect.Bottom
End Sub

Private Sub Form_Unload(Cancel As Integer)
   Dim lngReturn  As Long
   lngReturn = ClipCursor(ScreenRect)
End Sub

Okay, step one. Play by the rules. Or at least try to make sure that you do no damage. Save the original clip region so you can restore it on program exit:

Option Explicit
'  Other types ..... like RECT , Points, blah, blah, blah.
'  blah
Private Screen_RECT as RECT

Private sub Form_Load()
    Dim lReturn as long, 
    lReturn = GetClipCursor(Screen_RECT)
    ' The GetClipCursor API returns the current Clip Region of the cursor: this should be the whole screen area on your monitor at this point.
End Sub
' More Code
' 
'
Private Sub Form_Unload()
   Dim lReturn as long
   lReturn = ClipCursor(Screen_RECT)
   ' That should return the clip region back to normal.
End Sub

but when I compile the exe the rectangle it limits is bigger than the form

The GetClientRect API returns only the client area of the window in which the cursor will move. In regards to a normal VB Form, that means the area inside the borders not including the title bar.
So you need the handle to the Window (Me.hWnd) and you need to declare a RECT Type to store client area Dim CLIENT_RECT as RECT .

However, the four values of this RECT will not be in Screen Coordinates: the Top and Left Value will always be zero. The Right and Bottom properties will be the width and height of the client area in relation to the 0,0 origin (Top and Left). This poses a problem to the ClipCursor API since the RECT type used for this API needs a RECT with Screen Coordinates. Therefore, you need to take the values of the GetClientRect RECT and change them to screen coordinates.

This is where the ClientToScreen API comes in. This API will give you the screen coordinates of the Upper Left corner of the RECT you found with the GetClientRect API. It might be something like say 50, 70: top, left respectively.

So there you have it. 50 is the top, 70 is the left, 70 + width should be the Right Screen Coordinate, 50 + the Bottom (Right and Bottom values come from the GetClientRect API's RECT Type).

Assign those values to a RECT type and then call your ClipCursor API to limit the Cursor area.

With Client_RECT
    .Left = 70
    .Top = 50
    .Right = 70 + lngWidth ' Use the proper value for width
    .Bottom = Top + lngBottom
End With

lReturn = ClipCursor(Client_Rect)

if I change the start up position of the form from windows default to center screen the clip area stays in default windows position- any ideas?

It's VB6. It's funky. Wait till you can see the screen before using the ClipCursor API. Just drag a timer onto your form and enable it in your Form_Initialize Event. That way the form is already visible and the coordinates are already established. And as for the OffsetRect API, ignore it. You have no need to move the RECT points. You want to leave them where they are.

This article has been dead for over six months. Start a new discussion instead.