1. Computing

Advanced Mouse Processing

Is Present, Enter, Move, Exit, Stop, Set, Move, Enter, Over, Leave, Restrict...

By

Advanced Mouse Processing

In the previous article we have seen how to handle some basic mouse events like MouseUp/MouseDown and MouseMove. However, there are times when you want your mouse to do what you tell it.

'Basic' API stuff

Many of us write programs that are designed to work only with the mouse. If we are writing programs that require mouse presence and/or are dependent on mouse we have to be sure that various things are set up the right way.

Is Mouse Present?

The quickest way to see if the mouse is present:
 procedure TForm1.FormCreate(Sender: TObject) ;
 begin
 if GetSystemMetrics(SM_MOUSEPRESENT) <> 0 then
   ShowMessage('Mouse present')
 else
   ShowMessage('Mouse NOT present') ;
 end; 

Animated Mouse Cursor

Here's how to use animated cursors (or even how to use a BMP as a CUR):
 procedure TForm1.Button1Click(Sender: TObject) ;
 const MyCursor = 1;
 begin
 Screen.Cursors[MyCursor] :=
    LoadCursorFromFile
      ('c:\windows\cursors\globe.ani') ;
 Form1.Cursor := MyCursor;
 end; 

Positioning the mouse

The SetCursorPos API function moves the cursor to the specified screen coordinates. Since this function does not get a windows handle as a parameter, x/y have to be screen coordinates. Your component does use relative coordinates, e.g. relative to a TForm. You have to use the ClientToScreen function to calculate the proper screen coordinates.
 procedure SetMousePos(x, y: longint) ;
 var pt: TPoint;
 begin
    pt := ClientToScreen(point(x, y)) ;
    SetCursorPos(pt.x, pt.y) ;
 end;
 

Simulations

On most occasions we want mouse to move to a certain position on the screen. We know that some components do not respond to a cursor change until the user moves the mouse, we have to provide some small move-from-code technique. And what about simulation mouse clicks without calling the OnClick event handler?
 procedure TForm1.Button1Click(Sender: TObject) ;
 var pt : TPoint;
 begin
    Application.ProcessMessages;
    Screen.Cursor := crHourglass;
    GetCursorPos(pt) ;
    SetCursorPos(pt.x + 1, pt.y + 1) ;
    Application.ProcessMessages;
    SetCursorPos(pt.x - 1, pt.y - 1) ;
    Screen.Cursor := crArrow
 end;
 
The following example will simulate mouse click event on Button2 after the click to Button1. We have to use mouse_event() API call. The mouse_event function synthesizes mouse motion and button clicks. Mouse coordinates given are in "Mickeys", where their are 65535 "Mickeys" to a screen's width.
 //simulating mouse click
 //we need 2 buttons on the form
 procedure TForm1.Button1Click(Sender: TObject) ;
 var
    Pt : TPoint;
 begin
    Application.ProcessMessages;
    {Get the point in the center of Button 2}
    Pt.x := Button2.Left + (Button2.Width div 2) ;
    Pt.y := Button2.Top + (Button2.Height div 2) ;
   {Convert Pt to screen coordinates and Mickeys}
    Pt := ClientToScreen(Pt) ;
    Pt.x := Round(Pt.x * (65535 / Screen.Width)) ;
    Pt.y := Round(Pt.y * (65535 / Screen.Height)) ;
   {Simulate the mouse move}
    Mouse_Event(MOUSEEVENTF_ABSOLUTE or
                MOUSEEVENTF_MOVE,
                Pt.x, Pt.y, 0, 0) ;
   {Simulate the left mouse button down}
    Mouse_Event(MOUSEEVENTF_ABSOLUTE or
                MOUSEEVENTF_LEFTDOWN,
                Pt.x, Pt.y, 0, 0) ;;
   {Simulate the left mouse button up}
    Mouse_Event(MOUSEEVENTF_ABSOLUTE or
                MOUSEEVENTF_LEFTUP,
                Pt.x, Pt.y, 0, 0) ;;
 end;
 

Restrict The Mouse Movement

Using the Windows API function ClipCursor, it is possible to restrict the movement of the mouse to a specific rectangular region on the screen:
 procedure TForm1.FormCreate(Sender: TObject) ;
 var r : TRect;
 begin
     //it would be a good idea to move the
     //mouse inside the form before restriction
    r := BoundsRect;
    ClipCursor(@R) ;
 end;
 
 procedure TForm1.FormClick(Sender: TObject) ;
 begin
    //always be sure to release the cursor
    ClipCursor(nil) ;
 end; 

Mouse Enter, Mouse Leave?

Detecting entering and exiting of the mouse pointer over a component is often coming up when writing your own component. All descendants of TComponent send a CM_MOUSEENTER and CM_MOUSELEAVE message when the mouse enters and leaves the bounds of the component. You will need to write a message handler for the respective messages if we wish to respond to them.

©2014 About.com. All rights reserved.