BUG: Canvas setCursorPos() does not work
by David Wyand · in Torque Game Engine · 07/09/2004 (11:32 am) · 43 replies
Greetings!
Introduction
It seems that people are having a problem with getting the Canvas.setCursorPos() method working. I was among those having this very problem. The cursor would move to the new position but would not stay there as soon as the user moved the mouse. I've managed to work around this problem for my DTS Viewing Tool and present my solution here.
Problem Statement
The current Canvas.setCursorPos() method modifies an internal cursorPt variable to change the cursor position. This variable is used in the drawing of the cursor. However, the hardware platform is not aware of the new mouse location. When the user moves the mouse after a Canvas.setCursorPos() call, the platform sends its current absolute mouse position and the TGE obliges by popping the mouse to this hardware position. What is needed is a method of notifying the hardware platform that the mouse position has changed.
Solution
My proposed solution involves a new Input method definition and a change to the Canvas setCursorPos() operation. First the new Input class method.
Open up platform/platformInput.h and go to the Input class definition. Just before the getManager() method definition, add the following (the new code is bolded):
That's it for this file. Next, open up platformWin32/wininput.cc and go to just after the void Input::process() and before the InputManager* Input::getManager() code. Add the following function:
This new setCursorPos() function will move the mouse at the hardware level to the new position (by using the Windows PDK setCursorPos() function). The coordinates passed to it are relative to the client area of the window (the part of the window the TGE draws into).
Finally, we'll need to change how the Canvas.setCursorPos() method works. Open gui/guiCanvas.h and add the following to the top of the file (new code is bolded):
This will make sure the Canvas has access to the new Input::setCursorPos() method through the platform layer. Next, find the Canvas' setCursorPos() method and replace it with the following:
This new function will make sure that the passed coordinates are relative to the Canvas' origin. So, by calling Canvas.setCursorPos(0,0); in script should now place the mouse pointer in the upper left corner of the Canvas' drawing area.
Multi-platform Notice
The presented solution will only work under Windows. All that is required to have it work on another platform is to write the appropriate platform specific code for the Input::setCursorPos() method. Hopefully someone will endeavor to do just that.
Enjoy!
- LightWave Dave
Introduction
It seems that people are having a problem with getting the Canvas.setCursorPos() method working. I was among those having this very problem. The cursor would move to the new position but would not stay there as soon as the user moved the mouse. I've managed to work around this problem for my DTS Viewing Tool and present my solution here.
Problem Statement
The current Canvas.setCursorPos() method modifies an internal cursorPt variable to change the cursor position. This variable is used in the drawing of the cursor. However, the hardware platform is not aware of the new mouse location. When the user moves the mouse after a Canvas.setCursorPos() call, the platform sends its current absolute mouse position and the TGE obliges by popping the mouse to this hardware position. What is needed is a method of notifying the hardware platform that the mouse position has changed.
Solution
My proposed solution involves a new Input method definition and a change to the Canvas setCursorPos() operation. First the new Input class method.
Open up platform/platformInput.h and go to the Input class definition. Just before the getManager() method definition, add the following (the new code is bolded):
static void process();
[b]static void setCursorPos(S32 x, S32 y); // DAW: Set the cursor position relative to the window's client space[/b]
static InputManager* getManager();That's it for this file. Next, open up platformWin32/wininput.cc and go to just after the void Input::process() and before the InputManager* Input::getManager() code. Add the following function:
//------------------------------------------------------------------------------
// DAW: Set the cursor position relative to the window's client space
void Input::setCursorPos(S32 x, S32 y)
{
POINT pt;
pt.x = x;
pt.y = y;
ClientToScreen(winState.appWindow, &pt);
SetCursorPos(pt.x, pt.y);
}This new setCursorPos() function will move the mouse at the hardware level to the new position (by using the Windows PDK setCursorPos() function). The coordinates passed to it are relative to the client area of the window (the part of the window the TGE draws into).
Finally, we'll need to change how the Canvas.setCursorPos() method works. Open gui/guiCanvas.h and add the following to the top of the file (new code is bolded):
#ifndef _EVENT_H_ #include "platform/event.h" #endif [b]#ifndef _PLATFORMINPUT_H_ #include "platform/platformInput.h" #endif[/b] #ifndef _GUICONTROL_H_ #include "gui/guiControl.h" #endif
This will make sure the Canvas has access to the new Input::setCursorPos() method through the platform layer. Next, find the Canvas' setCursorPos() method and replace it with the following:
void setCursorPos(const Point2I &pt) { Input::setCursorPos(mBounds.point.x+pt.x, mBounds.point.y+pt.y); } //DAW: Was: {cursorPt.x = F32(pt.x); cursorPt.y = F32(pt.y); }This new function will make sure that the passed coordinates are relative to the Canvas' origin. So, by calling Canvas.setCursorPos(0,0); in script should now place the mouse pointer in the upper left corner of the Canvas' drawing area.
Multi-platform Notice
The presented solution will only work under Windows. All that is required to have it work on another platform is to write the appropriate platform specific code for the Input::setCursorPos() method. Hopefully someone will endeavor to do just that.
Enjoy!
- LightWave Dave
About the author
A long time Associate of the GarageGames' community. I run www.zworldo.com a free-to-play, browser based games site using Torque 3D technology.
Recent Threads
#22
A great collaborative effort, everyone. A true community affair.
Now it's time to off Ben's Head!
Oh, wait...
Time for Ben to go off and update the Head!
- LightWave Dave
07/13/2004 (11:51 am)
Greetings!A great collaborative effort, everyone. A true community affair.
Now it's time to off Ben's Head!
Oh, wait...
Time for Ben to go off and update the Head!
- LightWave Dave
#23
Maybe we should start a new forum for this one?
:o)
- LightWave Dave
07/13/2004 (11:52 am)
Heh, Harold.Maybe we should start a new forum for this one?
:o)
- LightWave Dave
#24
How many programmers does it take to move a cursor?
07/13/2004 (1:31 pm)
Suggested name for the forum:How many programmers does it take to move a cursor?
#25
That doesn't speak very well of us! What about:
And you said Mac was simple?
07/13/2004 (1:32 pm)
ROFL!That doesn't speak very well of us! What about:
And you said Mac was simple?
#26
07/13/2004 (9:22 pm)
I'll have Josh try out the mac branch and Quigley try out the linux branch, then I can check this in. Thanks guys, great work! :)
#28
08/31/2004 (5:36 am)
Yes it is, check the CVS changelog.
#29
08/31/2004 (6:01 am)
Never mind, my bad, I confused another changelog entry with this. It's not in HEAD yet (just checked the code)
#30
Perhaps that is a good thing as I feel some lines of the Mac OSX code need to be moved around. Here's my version (changes in bold):
What I've done is flip the order of operations for the CGDisplayMoveCursorToPoint() function call.
From my understanding, this function is used to discover the display number that is under a particular set of global (or screen) coordinates. With the original ordering, the screen point (the cgp variable) was not being initialized prior to the function call. While the original ordering did not appear to cause an error on my eMac, I would not trust it to work with all display configurations (as who knows what point it is really checking).
Please let me know if there are any problems with this as it seems to be working fine here. Enjoy!
- LightWave Dave
08/31/2004 (6:37 am)
Greetings!Perhaps that is a good thing as I feel some lines of the Mac OSX code need to be moved around. Here's my version (changes in bold):
void Input::setCursorPos(S32 x, S32 y)
{
Point windowPnt;
Rect r;
GrafPtr savePort;
CGDirectDisplayID cgdid;
CGDisplayCount cgdc;
CGPoint cgp;
//grab the port
GetPort( &savePort );
SetPortWindowPort( platState.appWindow );
GetWindowPortBounds(platState.appWindow, &r);
//calc and convert to [b]global (screen) xy coords[/b]
windowPnt.h = r.left + x;
windowPnt.v = r.top + y;
LocalToGlobal( &windowPnt);
[b] //load up the CGPoint with global screen coords
cgp.x = windowPnt.h;
cgp.y = windowPnt.v;
//find the display that is under our point to set up CGDID
CGGetDisplaysWithPoint(cgp, 1, &cgdid, &cgdc);[/b]
//move the little sucka
CGDisplayMoveCursorToPoint(cgdid, cgp);
//return the port
SetPort( savePort );
}What I've done is flip the order of operations for the CGDisplayMoveCursorToPoint() function call.
From my understanding, this function is used to discover the display number that is under a particular set of global (or screen) coordinates. With the original ordering, the screen point (the cgp variable) was not being initialized prior to the function call. While the original ordering did not appear to cause an error on my eMac, I would not trust it to work with all display configurations (as who knows what point it is really checking).
Please let me know if there are any problems with this as it seems to be working fine here. Enjoy!
- LightWave Dave
#31
Apologies for asking for a summary. If I get time, I'll certainly read through this whole thing again (last time I looked was a couple weeks ago). But I may not have time until the weekend.
Regardless, this change probably won't get in for a little while, as we've locked things down for the 1.3 release at the moment. Good work though everyone. "How many programmers does it take to move a cursor?"... lol :)
09/02/2004 (5:27 am)
So, this thread is long. ;) Is the above code all that needs to be checked before being put into HEAD? Apologies for asking for a summary. If I get time, I'll certainly read through this whole thing again (last time I looked was a couple weeks ago). But I may not have time until the weekend.
Regardless, this change probably won't get in for a little while, as we've locked things down for the 1.3 release at the moment. Good work though everyone. "How many programmers does it take to move a cursor?"... lol :)
#32
I can send you a patch against HEAD if you want.
09/02/2004 (6:34 am)
@Josh: Yes, all chcanges are in this thread, it would be cool if it went in 1.3 since it's an important bug fix and not a hard one to get in, it's a simple change.I can send you a patch against HEAD if you want.
#33
09/03/2004 (12:44 pm)
That'd be great Xavier.
#34
09/03/2004 (1:32 pm)
Josh, I'm emailing you my patch. Watch out, it might still be hot.
#35
Thanks.
Jameson
09/07/2004 (3:16 pm)
Good catch on the above David...I hadnt run into a problem with the implementation I posted but your fix makes sense (we use and run this code frequently). Thanks.
Jameson
#36
I just stumbled upon this issue and was wondering the time line of getting this into 1.3 and 1.4?
-Ron
08/29/2005 (8:41 am)
Sorry for performing CPR on a dead/decayed thread...I just stumbled upon this issue and was wondering the time line of getting this into 1.3 and 1.4?
-Ron
#37
08/29/2005 (10:21 am)
Hmm, will have to check for 1.4. #331.
#38
I saw Drew's ConsoleMethod fixed in 1.4, but no sign of David's lifesaving work. Is it still pending, sadly forgotten, or do I need to update from CVS?
02/19/2006 (12:18 pm)
This thread must have a yearly heartbeat...I saw Drew's ConsoleMethod fixed in 1.4, but no sign of David's lifesaving work. Is it still pending, sadly forgotten, or do I need to update from CVS?
#39
To fix the break, just grep your sources for
And comment out that line, only place I could find it is in guiCanvas.h
Would prolly be better to do an ifdef, but I'm not sure what the define for dedicated is
04/28/2006 (3:08 am)
Hey folks just a heads up, this WILL break your dedicated server build under linux.To fix the break, just grep your sources for
Input::setCursorPos(mBounds.point.x+pt.x, mBounds.point.y+pt.y);
And comment out that line, only place I could find it is in guiCanvas.h
Would prolly be better to do an ifdef, but I'm not sure what the define for dedicated is
#40
The platform layer should fail safe on this function, not crash.
04/28/2006 (12:56 pm)
There is no define for dedicated, you just don't do any graphics init in that case. :)The platform layer should fail safe on this function, not crash.
Torque Owner Harold "LabRat" Brown
Moving the Cursor