Game Development Community

How do I move a users/clients Mouse/cursor

by Cai Yundong · in Torque Game Engine Advanced · 07/31/2009 (2:51 am) · 7 replies

Hi,

I was wondering if it was possible to gain control of the users/clients mouse. I intend to use this feature as part of a tutorial.

I tried to setCursorPos but there are 2 problems with this. It seems to take the X,Y pos of the whole screen, so when i set its pos to 0,0 it does not go to the top left of my game window but to the top left of my entire screen. If i locked the mouse to the window using lockmouse, it still uses the whole screen's XY. In this case, if my window was in the center of my screen and I set its position to 300,300 it just teleports to the top right of the window as 300,300 on my screen is outside the window. The next problem is that it does not move to that position, but teleports there instantly.

Thanks in advance for any help !

#1
07/31/2009 (8:54 am)
There is a bug in the setCursorPos code. To get this to work properly, you need to change some engine code. In "gui/core/guiCanvas.cpp" the following changes need to be made:

Near the top, add a new header:

#include "gui/core/guiControl.h"
#include "console/consoleTypes.h"
#include "gfx/screenshot.h"
#include "windowManager/win32/win32Window.h"   // Add this header

In the "GuiCanvas::setCursorPos()" method, add these lines:

void GuiCanvas::setCursorPos(const Point2I &pt)   
{ 
   mCursorPt.x = F32(pt.x); 
   mCursorPt.y = F32(pt.y); 

   AssertISV(mPlatformWindow, "GuiCanvas::setCursorPos - no window present!");

   /// NEW CODE STARTS HERE
   POINT topleft;
   topleft.x = 0;
   topleft.y = 0;

   Win32Window* w = dynamic_cast<Win32Window*>(mPlatformWindow);

   if(w != NULL)
	  ClientToScreen(w->getHWND(), &topleft);

   mPlatformWindow->setCursorPosition( topleft.x + pt.x, topleft.y + pt.y );
   /// NEW CODE ENDS HERE

// mPlatformWindow->setCursorPosition( pt.x, pt.y );   // Remove this line
}

To get the cursor to animate, you could write a script that calculates the line between the current cursor position and the desired cursor position and schedules recursive Canvas.setCursorPos() calls that each move the cursor a short distance along that line.
#2
08/01/2009 (6:28 am)
Thank you very much for your help :D
#3
08/02/2009 (8:05 pm)
Good thing to know.
#4
08/02/2009 (11:47 pm)
The code seems to set 0,0 to the top left of the current window,
but does not restrict it to the current window. just what i needed though :D

Tested and working, Thank you very much :D

Below is the script for anyone interested

//enter destination point and time taken for mouse to move to that point
function setMouseDestination(%destination, %time){
	%curPosition = Canvas.getCursorPos();
	%dist = VectorSub(%destination, %curPosition);
	
	//%time is in ms, we set the mouse to update pos every 20ms
	%updateInterval = 20;
	%iteration = %time/%updateInterval;

   //distance to move each iteration
   %iterationDist = VectorScale(%dist,1/%iteration);
	
   moveMouseDestination(%curPosition, %destination, %iterationDist,%updateInterval);
	
}

function moveMouseDestination(%curPosition, %destination, %iterationDist,%updateInterval){
	%curPosition = VectorAdd(%curPosition, %iterationDist);
	%temp = mFloor(getWord(%curPosition,0)) SPC mFloor(getWord(%curPosition,1));
	Canvas.setCursorPos(%temp);
	
	if (VectorDist(%curPosition,%destination) > 1)
      schedule(%updateInterval,0,"moveMouseDestination",%curPosition, %destination, %iterationDist,%updateInterval);
}
#5
08/03/2009 (6:42 am)
Yeah, sorry about that. Wasn't thinking about the cursor being restricted to the Canvas on the right and bottom. :) To keep the cursor from going outside the Canvas bounds, simply modify the GuiCanvas::setCursorPos() method as follows:

void GuiCanvas::setCursorPos(const Point2I &pt)      
{    
   mCursorPt.x = F32(pt.x);    
   mCursorPt.y = F32(pt.y);    
  
   AssertISV(mPlatformWindow, "GuiCanvas::setCursorPos - no window present!");   
  
   /// NEW CODE STARTS HERE   
   POINT topleft;   
   topleft.x = 0;   
   topleft.y = 0;   
  
   Win32Window* w = dynamic_cast<Win32Window*>(PlatformWindowManager::get()->getFirstWindow());   
  
   if(w != NULL)
   {
	  ClientToScreen(w->getHWND(), &topleft);
								
	  Point2I extent = mPlatformWindow->getClientExtent();   // add

	  if(pt.x >= extent.x)                                   // add
	     topleft.x -= pt.x - extent.x + 1;                   // add
						
	  if(pt.y >= extent.y)                                   // add
	     topleft.y -= pt.y - extent.y + 1;                   // add
   }
  
   mPlatformWindow->setCursorPosition( topleft.x + pt.x, topleft.y + pt.y );   
   /// NEW CODE ENDS HERE   
  
// mPlatformWindow->setCursorPosition( pt.x, pt.y );   // Remove this line   
}
#6
08/04/2009 (4:02 am)
Wow ! Thanks for the update :D
#7
08/04/2009 (6:26 am)
As an additional note, I was talking to one of the associates in the T3D forum, and he suggested using:

Win32Window* w = dynamic_cast<Win32Window*>(mPlatformWindow);

Instead of:

Win32Window* w = dynamic_cast<Win32Window*>(PlatformWindowManager::get()->getFirstWindow());

I believe his suggestion is a better solution. I changed my first post to reflect this.