Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

Use a Background Application to Perform Mouse Operations in a Foreground Application

Posted on 2004-09-15
4
Medium Priority
?
204 Views
Last Modified: 2010-08-05
I have a vendor supplied program which allows me to export data to a file by doing
a series of mouse operations.  I'd like to have a background  program which would
perform the export mouse operations periodically without my intervention.  The
mouse targets are in predictable positions.  

I've researched many documents on writing code to perform various mouse operations
and they seem relatively straightforward.  However, I'm not sure about how to structure
the background program so that it does what I want without interfering with the
foreground application.  Also, I have a feeling that such a program may have been written before, maybe many times.

Do you know of any source code that would do what I want?  And if not, can you give me some guidance on how to structure my background program?  

0
Comment
Question by:RalphSCoffin
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
4 Comments
 
LVL 6

Expert Comment

by:Amir Azhdari
ID: 12070481
the easiest way to get all the systems mouse button Downs and Ups and ... is with the Journal hook.  This code uses a Form with 2 buttons on it, one button starts the journal hook and the other button stops it. There is One List box which will show all the mouse ups and downs and their screen coordinates.
There is also one TApplicationEvents to get the OnMessage event, so you can restart the hook if there's a WM_CANCELJOURNAL message.


unit MouseButton;

interface

uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
 StdCtrls, AppEvnts;

type
 TForm1 = class(TForm)
   Button_StartJour: TButton;
   Button_StopJour: TButton;
   ListBox1: TListBox;
   ApplicationEvents1: TApplicationEvents;
   procedure Button_StartJourClick(Sender: TObject);
   procedure Button_StopJourClick(Sender: TObject);
   procedure ApplicationEvents1Message(var Msg: tagMSG;
     var Handled: Boolean);
   procedure FormClose(Sender: TObject; var Action: TCloseAction);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1: TForm1;
 JHook: THandle;
 Track: Boolean;

implementation

{$R *.DFM}

function JournalProc(Code, wParam: Integer; var EventStrut: TEVENTMSG): Integer; stdcall;
var
Char1: PChar;
begin
{this is the JournalRecordProc}
Result := CallNextHookEx(JHook, Code, wParam, Longint(@EventStrut));
{the CallNextHookEX is not really needed for journal hook since it it not
really in a hook chain, but it's standard for a Hook}
if Code < 0 then Exit;

{you should cancel operation if you get HC_SYSMODALON}
if Code = HC_SYSMODALON then Exit;
if Code = HC_ACTION then
 begin
{the EventStrut record has the Information about the mouse or keyboard
event. You said you just wanted the mouse button events so I get the
mouse down and mouse up event messages}
   if EventStrut.message = WM_LBUTTONUP then
   Form1.ListBox1.Items.Add('Left Mouse UP at X pos '+IntToStr(EventStrut.paramL)
                            +' and Y pos '+IntToStr(EventStrut.paramH));
   if EventStrut.message = WM_LBUTTONDOWN then
   Form1.ListBox1.Items.Add('Left Mouse Down at X pos '+IntToStr(EventStrut.paramL)
                            +' and Y pos '+IntToStr(EventStrut.paramH));
   if EventStrut.message = WM_RBUTTONDOWN then
   Form1.ListBox1.Items.Add('Right Mouse Down at X pos '+IntToStr(EventStrut.paramL)
                            +' and Y pos '+IntToStr(EventStrut.paramH));
   if (EventStrut.message = WM_RBUTTONUP) then
   Form1.ListBox1.Items.Add('Right Mouse Up at X pos '+IntToStr(EventStrut.paramL)
                            +' and Y pos '+IntToStr(EventStrut.paramH));
 end;
end;

procedure TForm1.Button_StartJourClick(Sender: TObject);
begin
if Track then
 begin
 ShowMessage('Mouse is already being Journaled, can not restart');
 Exit;
 end;

JHook := SetWindowsHookEx(WH_JOURNALRECORD , @JournalProc, 0, 0);
{SetWindowsHookEx starts the Hook}
if JHook > 0 then
 begin
 Track := True;
 end else
 ShowMessage('No Journal Hook availible');
end;

procedure TForm1.Button_StopJourClick(Sender: TObject);
begin
Track := False;
UnhookWindowsHookEx(JHook);
JHook := 0;
end;

procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
 var Handled: Boolean);
begin
{the journal hook is automaticly camceled if the Task manager
(Ctrl-Alt-Del) or the Ctrl-Esc keys are pressed, you restart it
when the WM_CANCELJOURNAL is sent to the parent window, Application}
Handled := False;
if (Msg.message = WM_CANCELJOURNAL) and Track then
 JHook := SetWindowsHookEx(WH_JOURNALRECORD , @JournalProc, 0, 0);
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
{make sure you UN hook it if the app closes}
UnhookWindowsHookEx(JHook);
end;

end.



- - - - - - - - - - - - - - - - -  - - - - - - - - - - - -

Hope you can use it, ask questions if you need more.
0
 

Author Comment

by:RalphSCoffin
ID: 12070606
I want my background program to position the mouse over specific targets
on the screen and click or double click to cause the foreground program
(on the screen) to react just as though I had manually positioned the mouse
and clicked it myself.  Collecting data on mouse activity from the journal
is not of use to me in what I'm trying to do.  
0
 
LVL 34

Expert Comment

by:Slick812
ID: 12071839
hello  RalphSCoffin, , what would be of use to you? ? ?  I am not sure what to do to help you? If you already know the positions of the controls you need to click , then just use the  mouse_event( ) function to "CLICK" that control, the mouse_event( ) function can do a "CLICK" (mouse down ans mouse Up) at any position , so you will need to know the postion of the control. I can not see any reason to position the cursor over the control, the postion of the cursor has nothing, that I know of, ,  to do with the programatic mouse down and mouse up  mouse_event( ) funtion. . . .  if you know the window's system handle for the controls, then you can also send them system messageses for the "CLICK" events. . . so you might say what you can do or have knowledge about the "Foreground"  app.
the jounaling hook is an excelent way to record and then PLAYBACK a series of mouse or keyboard events, although  AmirAzhdari  did not show how to store and PLAYBACK the recorded journaling. . .
0
 
LVL 17

Accepted Solution

by:
geobul earned 750 total points
ID: 12072572
Hi,

The following example comes from one of my working apps. It has a timer and stays in the background.

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    procedure Timer1Timer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  IsWorking: boolean;

implementation

{$R *.DFM}

procedure MouseMoveAndClick(x, y: Integer);
var
  OldCoord: TPoint;
begin
  // save current position
  GetCursorPos(OldCoord);
  // move to new position
  SetCursorPos(x, y);
  // click
  mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
  mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
  // restore position
  SetCursorPos(OldCoord.x, OldCoord.y);
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
  h: HWND;
begin
 if not IsWorking then begin
  IsWorking := true;
  try
  // check if the time has come, i.e. your app has to perform mouse clicks
  if <something> then begin
    // find, show and maximize the target app
    h := FindWindow(nil, 'TheFormTitle');
    if IsWindow(h) then begin
      ShowWindow(h, SW_RESTORE);
      // maximaze it
      if not IsZoomed(h) then begin
        ShowWindow(h, SW_MAXIMIZE);
      end;

      // do your mouse clicks here - in absolute screen coordinates
      MouseMoveAndClick(20, 50);
      MouseMoveAndClick(100, 200);
      // etc.
    end;
  end;
  finally
    IsWorking := false;
  end;
 end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  IsWorking := false;
  Timer1.Enabled := true;
end;

Regards, Geo
0

Featured Post

Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
In this video you will find out how to export Office 365 mailboxes using the built in eDiscovery tool. Bear in mind that although this method might be useful in some cases, using PST files as Office 365 backup is troublesome in a long run (more on t…
Want to learn how to record your desktop screen without having to use an outside camera. Click on this video and learn how to use the cool google extension called "Screencastify"! Step 1: Open a new google tab Step 2: Go to the left hand upper corn…
Suggested Courses

704 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question