Jump to content
  • Advertisement
Sign in to follow this  

Lock mouse to window corner

This topic is 3412 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm doing some calculations to determine a windows height and width based on a minimum and aspect ratio. When the user is resizing the window from a corner and they go outside the bounds of the min/max aspect ratio I end up having to move the corner of the window. Once the corner of the window is moved the actual 'resize corner' mouse cursor is no longer in the same spot as the corner of the window, which is annoying. I'd like to lock the cursor to that corner of the window. So far the only thing I can think of is doing SetCursorPos to that corner. But if I want to support all four corners I'd have to keep track of which corner they are moving during WM_SIZING and then maybe during WM_SIZE I could set the position if they are moving a corner, and then calculate the position based on which corner it is using GetWindowRect. This sounds like a pain, there has got to be an easier way. Any ideas?

Share this post


Link to post
Share on other sites
Advertisement
That sounds very peculiar. Why exactly are you trying to do it that way? If you know where the corner of your window is located why don't you just pretend that the mouse is always in that spot?

Share this post


Link to post
Share on other sites
Imagine it like this, in a game like World of Warcraft, when you resize the window, is it always like you're dragging the corner. This is because it locks the aspect ratio.

However, if we allow the resizing to affect the aspect ratio within a certain range, say from 5:4 to 16:9, then while dragging the window there is a chance that the corner movement will eventually be restricted.

Let me give you an example. If the window is currently 1600x900 pixels, we're at the 16:9 limit, so if we drag it any wider then the window will need to become taller as well. I have this working, the window does become taller, however, the cursor does not move with the window's corner, so as the user continues to drag the window the cursor is no longer an indicator of where the corner will go, which becomes annoying.

Share this post


Link to post
Share on other sites
Bump?

Let me make this question more simple. I am changing a window's size on my own during WM_SIZING, any changes to the window need to move the mouse cursor so that it stays along the border/corner of the window too. Not sure if there is an easy way to do this or not.

Share this post


Link to post
Share on other sites
I think I know what you're talking about. I pulled up an explorer window and started dragging the right edge. The cursor would stay lined up with the right edge but could be moved lower than the corner of the window. What you might try doing is restricting the y coordinate of the cursor if the window is grabbed on it's side and restricting the x coordinate if it's grabbed on the top or bottom. It's just a matter of keeping track of the cursor's previous position and manually changing the said coordinate back to it's previous position. It sounds nice in theory, but I don't know if it would work. I'll try it myself.

EDIT:

Try this. It worked for me.

POINT p, p2; // Global

case WM_MOUSEMOVE:
GetCursorPos(&p);
break;

case WM_SIZING:
if(wParam == WMSZ_LEFT || wParam == WMSZ_RIGHT)
{
RECT *rcWnd = (RECT*)lParam;
GetCursorPos(&p2);
if(p2.y > rcWnd -> bottom) p2.y = rcWnd -> bottom;
else if(p2.y < rcWnd -> top) p2.y = rcWnd -> top;
SetCursorPos(p2.x, p2.y);
rcWnd = 0;
}

if(wParam == WMSZ_BOTTOM || wParam == WMSZ_TOP)
{
RECT *rcWnd = (RECT*)lParam;
GetCursorPos(&p2);
if(p2.x > rcWnd -> right) p2.x = rcWnd -> right;
else if(p2.x < rcWnd -> left) p2.x = rcWnd -> left;
SetCursorPos(p2.x, p2.y);
rcWnd = 0;
}
break;





EDIT2: This has actually inspired me to write a very complex sizing mechanism that deals with the aspect ratio myself. That thing up there is not complete at all.

[Edited by - kittycat768 on January 15, 2009 8:30:05 PM]

Share this post


Link to post
Share on other sites
I don't have the algorithm in front of me, but I'll try some pseudocode from memory:


float width = clientRect.right - clientRect.left;
float height = clientRect.bottom - clientRect.top;

// Keep track of whether user has moved width or height the most since the
// last render. This allows us to treat corner resizing like it was a side of
// the window instead. There is also the possibility that height and width
// deltas are the same, in which case we just default to treating it like height
// changed the most.
bool widthDeltaGreatest = ( fabs(widthLastRender - width) > fabs(heightLastRender - height) );

float MAX_ASPECT = 1.7777777f; // 16:9
float MIN_ASPECT = 1.25f; // 5:4

float aspectRatio = width / height;

switch ( wParam )
{
case WMSZ_LEFT:
case WMSZ_RIGHT:
if ( aspectRatio > MAX_ASPECT )
{
// Width change has made window too wide, so make it taller
height = width / MAX_ASPECT;
}
else if ( aspectRatio < MIN_ASPECT )
{
// Width change has made window too narrow, so make it shorter
height = width / MIN_ASPECT;
}
break;
case WMSZ_TOP:
case WMSZ_BOTTOM:
if ( aspectRatio > MAX_ASPECT )
{
// Height change has made window too short, so make it more narrow
width = height * MAX_ASPECT;
{
else if ( aspectRatio < MIN_ASPECT )
{
// Height change has made window too tall, so make it wider
width = height * MIN_ASPECT;
}
break;
case WMSZ_TOPLEFT:
case WMSZ_TOPRIGHT:
case WMSZ_BOTTOMLEFT:
case WMSZ_BOTTOMRIGHT:
// I'm too lazy to type this all in, so it goes like this:
if ( widthDeltaGreatest )
{
// Do same thing as WMSZ_LEFT and WMSZ_RIGHT cases.
}
else
{
// Do same thing as WMSZ_TOP and WMSZ_BOTTOM cases.
}
break;
default:
// Something strange was passed in for wParam.
assert(0);
break;
}

// Now pass out height and width.


I use this method during WM_SIZING. The clientRect that I got the height and width from is given by the LPARAM in WM_SIZING. You simply change the LPARAM variables and windows will change the screensize.

As to the cursor stuff:
Unfortunately I cannot use the windows sides to restrict the mouse cursor position, in my case the only time I need to restrict it is when I'm dragging from the corners. If I'm dragging from the corners I won't know which dimension to restrict the mouse to, and sometimes I'll need to restrict it to both.

Share this post


Link to post
Share on other sites
I apologize for my code being a wall of text, but it covers everything that I could possibly implement as far as resizing on the go. It took me a few hours to code it. It's not w/o it's limitations, but it works well. Your code is very slimmed down. The way I see my code is that it looks at the situation from a very logical point of view. I'll more than likely remove a lot of my redundancies in the future. Trying to solve your problem has made me aware of how snazzy I can make my programs by implementing this.

As far as restricting the mouse to the corner goes. What you do is get the mouse position. Set the corner to it. Fix the aspect ratio of the window and then set the mouse pointer as the corner of the window. In my case, my corner code sections all resize the height based on the aspect so so the mouse gets moved up or down.

point p;
float xaspect = 1.333333f; yaspect = 0.75f;

case WM_SIZING:
if(wParam == WMSZ_LEFT)
{
RECT *rcWnd = (RECT*)lParam;

long xborder = GetSystemMetrics(SM_CXFRAME) * 2;
long yborder = GetSystemMetrics(SM_CYFRAME) * 2;
long ycaption = GetSystemMetrics(SM_CYCAPTION);
long width = rcWnd -> right - rcWnd -> left - xborder;

GetCursorPos(&p);

// 123 is the minium window width on my system. I don't know how to calculate it.
if((rcWnd -> right - rcWnd -> left) <= 123)
{
rcWnd -> left = rcWnd -> right - 123;
if(p.x > rcWnd -> left) p.x = rcWnd -> left;
}
width = rcWnd -> right - rcWnd -> left;
rcWnd -> bottom = (long)((float)width * yaspect) + rcWnd -> top + yborder + ycaption;

if(p.y > rcWnd -> bottom) p.y = rcWnd -> bottom;
else if(p.y < rcWnd -> top) p.y = rcWnd -> top;
SetCursorPos(p.x, p.y);
rcWnd = 0;
}

if(wParam == WMSZ_RIGHT)
{
RECT *rcWnd = (RECT*)lParam;

long xborder = GetSystemMetrics(SM_CXFRAME) * 2;
long yborder = GetSystemMetrics(SM_CYFRAME) * 2;
long ycaption = GetSystemMetrics(SM_CYCAPTION);
long width = rcWnd -> right - rcWnd -> left - xborder;

GetCursorPos(&p);

// 123 is the minium window width on my system. I don't know how to calculate it.
if((rcWnd -> right - rcWnd -> left) <= 123)
{
rcWnd -> right = rcWnd -> left + 123;
if(p.x < rcWnd -> right) p.x = rcWnd -> right;
}
width = rcWnd -> right - rcWnd -> left;
rcWnd -> bottom = (long)((float)width * yaspect) + rcWnd -> top + yborder + ycaption;

if(p.y > rcWnd -> bottom) p.y = rcWnd -> bottom;
else if(p.y < rcWnd -> top) p.y = rcWnd -> top;
SetCursorPos(p.x, p.y);
rcWnd = 0;
}

if(wParam == WMSZ_TOP)
{
RECT *rcWnd = (RECT*)lParam;

long xborder = GetSystemMetrics(SM_CXFRAME) * 2;
long yborder = GetSystemMetrics(SM_CYFRAME) * 2;
long ycaption = GetSystemMetrics(SM_CYCAPTION);
long height = rcWnd -> bottom - rcWnd -> top - yborder - ycaption;

GetCursorPos(&p);

// 123 is the minium window width on my system. I don't know how to calculate it.
rcWnd -> right = (long)((float)height * xaspect) + rcWnd -> left + xborder;
if(rcWnd -> top >= (long)(rcWnd -> bottom - ((123 - xborder) * yaspect) - yborder - ycaption))
{
rcWnd -> top = (long)(rcWnd -> bottom - ((123 - xborder) * yaspect) - yborder - ycaption);
if(p.y > rcWnd -> top) p.y = rcWnd -> top;
}

if(p.x > rcWnd -> right) p.x = rcWnd -> right;
else if(p.x < rcWnd -> left) p.x = rcWnd -> left;
SetCursorPos(p.x, p.y);
rcWnd = 0;
}

if(wParam == WMSZ_BOTTOM)
{
RECT *rcWnd = (RECT*)lParam;

long xborder = GetSystemMetrics(SM_CXFRAME) * 2;
long yborder = GetSystemMetrics(SM_CYFRAME) * 2;
long ycaption = GetSystemMetrics(SM_CYCAPTION);
long height = rcWnd -> bottom - rcWnd -> top - yborder - ycaption;

GetCursorPos(&p);

// 123 is the minium window width on my system. I don't know how to calculate it.
rcWnd -> right = (long)((float)height * xaspect) + rcWnd -> left + xborder;
if(rcWnd -> bottom <= (long)(((123 - xborder) * yaspect) + rcWnd -> top + yborder + ycaption))
{
rcWnd -> bottom = (long)(((123 - xborder) * yaspect) + rcWnd -> top + yborder + ycaption);
if(p.y < rcWnd -> bottom) p.y = rcWnd -> bottom;
}

if(p.x > rcWnd -> right) p.x = rcWnd -> right;
else if(p.x < rcWnd -> left) p.x = rcWnd -> left;
SetCursorPos(p.x, p.y);
rcWnd = 0;
}

if(wParam == WMSZ_TOPLEFT)
{
RECT *rcWnd = (RECT*)lParam;

long xborder = GetSystemMetrics(SM_CXFRAME) * 2;
long yborder = GetSystemMetrics(SM_CYFRAME) * 2;
long ycaption = GetSystemMetrics(SM_CYCAPTION);
long width = rcWnd -> right - rcWnd -> left - xborder;
//long height = rcWnd -> bottom - rcWnd -> top - yborder - ycaption;

GetCursorPos(&p);
rcWnd -> left = p.x;
rcWnd -> top = p.y;

// 123 is the minium window width on my system. I don't know how to calculate it.
if((rcWnd -> right - rcWnd -> left) <= 123)
{
rcWnd -> left = rcWnd -> right - 123;
if(p.x > rcWnd -> left) p.x = rcWnd -> left;
}
width = rcWnd -> right - rcWnd -> left;
rcWnd -> top = rcWnd -> bottom - (long)((float)width * yaspect) - yborder - ycaption;

p.x = rcWnd -> left;
p.y = rcWnd -> top;
SetCursorPos(p.x, p.y);
rcWnd = 0;
}

if(wParam == WMSZ_BOTTOMLEFT)
{
RECT *rcWnd = (RECT*)lParam;

long xborder = GetSystemMetrics(SM_CXFRAME) * 2;
long yborder = GetSystemMetrics(SM_CYFRAME) * 2;
long ycaption = GetSystemMetrics(SM_CYCAPTION);
long width = rcWnd -> right - rcWnd -> left - xborder;

GetCursorPos(&p);
rcWnd -> left = p.x;
rcWnd -> bottom = p.y;

// 123 is the minium window width on my system. I don't know how to calculate it.
if(rcWnd -> bottom <= (long)(((123 - xborder) * yaspect) + rcWnd -> top + yborder + ycaption))
{
rcWnd -> bottom = (long)(((123 - xborder) * yaspect) + rcWnd -> top + yborder + ycaption);
if(p.y < rcWnd -> bottom) p.y = rcWnd -> bottom;
}

// 123 is the minium window width on my system. I don't know how to calculate it.
if((rcWnd -> right - rcWnd -> left) <= 123)
{
rcWnd -> left = rcWnd -> right - 123;
if(p.x > rcWnd -> left) p.x = rcWnd -> left;
}
width = rcWnd -> right - rcWnd -> left;
rcWnd -> bottom = (long)((float)width * yaspect) + rcWnd -> top + yborder + ycaption;

p.x = rcWnd -> left;
p.y = rcWnd -> bottom;
SetCursorPos(p.x, p.y);

rcWnd = 0;
}

if(wParam == WMSZ_TOPRIGHT)
{
RECT *rcWnd = (RECT*)lParam;

long xborder = GetSystemMetrics(SM_CXFRAME) * 2;
long yborder = GetSystemMetrics(SM_CYFRAME) * 2;
long ycaption = GetSystemMetrics(SM_CYCAPTION);
long width = rcWnd -> right - rcWnd -> left - xborder;

GetCursorPos(&p);
rcWnd -> right = p.x;
rcWnd -> top = p.y;

// 123 is the minium window width on my system. I don't know how to calculate it.
if((rcWnd -> right - rcWnd -> left) <= 123)
{
rcWnd -> right = rcWnd -> left + 123;
if(p.x < rcWnd -> right) p.x = rcWnd -> right;
}
width = rcWnd -> right - rcWnd -> left;
rcWnd -> top = rcWnd -> bottom - (long)((float)width * yaspect) - yborder - ycaption;

p.x = rcWnd -> right;
p.y = rcWnd -> top;
SetCursorPos(p.x, p.y);
rcWnd = 0;
}

if(wParam == WMSZ_BOTTOMRIGHT)
{
RECT *rcWnd = (RECT*)lParam;

long xborder = GetSystemMetrics(SM_CXFRAME) * 2;
long yborder = GetSystemMetrics(SM_CYFRAME) * 2;
long ycaption = GetSystemMetrics(SM_CYCAPTION);
long width = rcWnd -> right - rcWnd -> left - xborder;

GetCursorPos(&p);
rcWnd -> right = p.x;
rcWnd -> bottom = p.y;

// 123 is the minium window width on my system. I don't know how to calculate it.
if((rcWnd -> right - rcWnd -> left) <= 123)
{
rcWnd -> right = rcWnd -> left + 123;
if(p.x < rcWnd -> right) p.x = rcWnd -> right;
}
width = rcWnd -> right - rcWnd -> left;
rcWnd -> bottom = (long)((float)width * yaspect) + rcWnd -> top + yborder + ycaption;

p.x = rcWnd -> right;
p.y = rcWnd -> bottom;
SetCursorPos(p.x, p.y);
rcWnd = 0;
}
break;


Share this post


Link to post
Share on other sites
You can let windows handle minimum screen sizes. WM_MINMAXINFO I believe is the message to listen for, and within one of the params you can set a min height and width. This will keep you from having to do the calculations yourself, and it only takes about 4 lines of code.

Oh, and thanks for the advice on the mouse cursor, I may try that.

[Edited by - lordikon on January 15, 2009 11:16:41 PM]

Share this post


Link to post
Share on other sites
The default Windows behaviour is that the cursor keeps moving, even if the window is at its minimum or maximum size, but no longer stretches or shrinks the window.

I'd say this is the more desired behaviour. It is very rare that manually changing the cursor position improves user experience. Consistency is the most important thing in interfaces so I'd always suggest mimicking the way the OS behaves where possible.

Share this post


Link to post
Share on other sites
Quote:
Original post by EasilyConfused
The default Windows behaviour is that the cursor keeps moving, even if the window is at its minimum or maximum size, but no longer stretches or shrinks the window.

I'd say this is the more desired behaviour. It is very rare that manually changing the cursor position improves user experience. Consistency is the most important thing in interfaces so I'd always suggest mimicking the way the OS behaves where possible.


Generally I feel the same way, but if you resize enough the cursor can be off of the corner by a couple of hundred pixels, it just starts to feel strange. But I guess the cursor moving on its own might feel strange too.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!