Klikacz
Adam Boduch
W tym gotowcu zaprezentowany zostanie sposób w jaki można sterować myszką, czyli przesuwać ją na określoną pozycje, klikać i powracać na poprzednią pozycję. Gotowiec, który tutaj zaprezentowano, a którego kod zostanie za chwile przedstawiony, działą następująco:
Najpierw użytkownik musi podać współrzędne ekranu na które myszka ma klikać. Następnie określa odstęp w jakim ma się to odbywać. Po tym naciska przycisk "Włącz". Co się dzieje później? Użytkownik może sobie spokojnie pracować o co określony czas aktywne okno zostaje przełączone, myszka kliknie się na określonych współrzędnych, a następnie powróci do poprzedniej pozycji.
Jeżeli użytkownik naciśnie określoną kombinacje klawiszy, obojętnie kiedy i gdzie (w naszym przypadku Ctrl+Enter) to w programie przypisywana zostaje aktualna pozycja kursora.
W sekcji Private należy deklarować metodę:
procedure WMHOTKEY(var Msg : TMessage); message WM_HOTKEY;
// przechwytuje skrot klawiaturowy
Jej definicja wygląda następująco:
procedure TMainForm.WMHOTKEY(var Msg: TMessage);
var
MousePos : TPoint;
Buffer : array[0..255] of char;
begin
{
procedura ta wykonywana jest w momencie, gdy uzytkownik wcisnie kombinacje
klawiszy Ctrl+Enter. Wtedy pobierana jest pozycja ekranu, a do zmiennej przypisuje
sie uchwyt aktywnego okna
}
if Msg.WParam = $0001 then
begin
GetCursorPos(MousePos); // pobierz pozycje kursora
Xedt.Text := IntToStr(MousePos.X); // przypisz do kontrolek
Yedt.Text := IntToStr(MousePos.Y);
Foreground := GetForegroundwindow; // pobierz uchwyt okna
// pobierz tytul aktywnego okna
GetWindowText(Foreground, Buffer, SizeOf(Buffer));
lblTitle.Caption := Buffer;
end;
end;
Bedzie to reakcja na nacisniecie kombinacji Ctrl+Enter. W takim przypadku nastapi pobranie pozycji kursora i wpisanie jego współrzędnych w kontrolkach typu TEdit
. Dodatkowo do zmiennej Foreground zostanie przypisany uchwyt aktywnego okna, a do zmiennej Buffer - jego tytuł.
Oczywiście to nie wszystko, ponieważ trzeba obsłużyć rejestracje i zwalnianie tego skrótu:
procedure TMainForm.FormCreate(Sender: TObject);
begin
{ Ta funkcja rejestruje skrót: Ctrl + Enter dla naszej aplikacji }
RegisterHotKey(Handle, $0001, MOD_CONTROL, VK_Return);
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
{ zwolnienie skrotu w systemi }
UnregisterHotKey(Handle, $0001);
end;
Na formularzu umieszczony jest komponent Timer
, ktory odgrywa kluczową rolę w programie.
Co pewien czas wykonuje on jakieś czynności, a konkretnie klika w określone miejsce ekranu.
Cały kod procedury zdarzenia OnTimer
wygląda tak:
procedure TMainForm.TimerTimer(Sender: TObject);
var
CurrentPos : TPoint;
CurrentWindow : HWND;
begin
CurrentWindow := GetForegroundWindow; // pobierz uchwyt aktywnego okna
GetCursorPos(CurrentPos); // pobierz tymczasowa pozycje ekranu
ShowWindow(Foreground, SW_SHOWNA); // pokaż okno
BringWindowToTop(Foreground); // dla pewnosci - wysun na wierzch
SetForegroundwindow(Foreground); // ustaw aktywne okno
SetCursorPos(StrToInt(Xedt.Text), StrToInt(Yedt.Text)); // ustaw w wybranej pozycji
{ kliknij na pozycje }
mouse_event(MOUSEEVENTF_LEFTDOWN, StrToInt(Xedt.Text), StrToInt(Yedt.Text), 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, StrToInt(Xedt.Text), StrToInt(Yedt.Text), 0, 0);
ShowWindow(Currentwindow, SW_SHOWNA); // pokaż okno
SetForegroundWindow(Currentwindow); // ustaw aktywne okno
SetCursorPos(CurrentPos.X, CurrentPos.Y); // ustaw ponownie na poprzedniej pozycji
iCountdown := Wait.Value * 60;
Inc(Counter); // zwieksz licznik
StatusBar.SimpleText := 'Kliknięto... poraz ' + IntToStr(Counter);
end;
Ta metoda działa mniej więcej tak: Pobiera dotychczasowe aktywne okno i pozycje kursora. Następnie ustawia kursor w wybranym miejscu i następuje kliknięcie. Wszystko to za sprawą procedury mouse_event
, która symuluje naciśnięcie klawisza myszki.
W naszym przypadku wywołanie tej procedury następuje dwa razy, gdyż w pierwszym przypadku następuje
wciśnięcie lewego klawisza, a później lego "wyciśnięcie". Na samym końcu po wykonaniu tej operacji kursor powraca do poprzedniej pozycji i do poprzedniego aktywnego okna.
Właściwie cały program jest już gotowy. Normalnie cała procedura jest wyłączona (Timer.Enabled = False)
i nic się nie dzieje. Trzeba oprogramować zdarzenie OnClick
które powoduje zatrzymanie lub uruchomienie zegara:
procedure TMainForm.btnAcceptClick(Sender: TObject);
begin
if not Timer.Enabled then // jezeli Timer jest wylaczony
begin
Timer.Interval := Wait.Value * 60000; // ustaw czas pomiedzy dzialaniami
Timer.Enabled := True; // wlacz timer
Caption := 'Klikacz - włączony!'; // zmien wlasciwosc okna
// licznik ktory bedzie odliczal do kolejnego klikniecia
iCountdown := Wait.Value * 60;
Countdown.Interval := 1000;
// wlaczenie licznika
Countdown.Enabled := True;
end else
begin
Timer.Enabled := False; // w przeciwnym wypadku - wylacz timer
Caption := 'Klikacz - wyłączony!'; // zmien wartosc
Countdown.Enabled := False;
end;
end;
Czas, który ma upłynąć jest pobierany z kontrolki i mnożony przez 60,000 milisekund. Tak
więc kliknięcie będzie nastąpywać conajmniej raz na minute.
Cały kod programu wygląda tak:
(****************************************************************)
(* *)
(* Copyright (c) 2002 by Adam Boduch *)
(* www.4programmers.net *)
(* adam@4programmers.net *)
(* *)
(****************************************************************)
unit MainFrm;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, jpeg, Spin, ComCtrls;
type
TMainForm = class(TForm)
gbHome: TGroupBox;
X: TLabel;
Y: TLabel;
Xedt: TEdit;
Yedt: TEdit;
btnAccept: TButton;
Timer: TTimer;
Image1: TImage;
Wait: TSpinEdit;
Label1: TLabel;
Label2: TLabel;
StatusBar: TStatusBar;
lblCountdown: TLabel;
Countdown: TTimer;
lblTitle: TLabel;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure btnAcceptClick(Sender: TObject);
procedure TimerTimer(Sender: TObject);
procedure CountdownTimer(Sender: TObject);
private
Foreground : HWND; // zmienna przechowuje uchwyt okna
procedure WMHOTKEY(var Msg : TMessage); message WM_HOTKEY; // przechwytuje skrot klawiaturowy
public
{ Public declarations }
end;
var
MainForm: TMainForm;
implementation
{$R *.DFM}
{ TMainForm }
var iCountdown : Integer; // czas pozostaly do kolejnego klikniecia
var Counter : Integer = 0; // licznik klikniec w banner u gorze
procedure TMainForm.WMHOTKEY(var Msg: TMessage);
var
MousePos : TPoint;
Buffer : array[0..255] of char;
begin
{
procedura ta wykonywana jest w momencie, gdy uzytkownik wcisnie kombinacje
klawiszy Ctrl+Enter. Wtedy pobierana jest pozycja ekranu, a do zmiennej przypisuje
sie uchwyt aktywnego okna
}
if Msg.WParam = $0001 then
begin
GetCursorPos(MousePos); // pobierz pozycje kursora
Xedt.Text := IntToStr(MousePos.X); // przypisz do kontrolek
Yedt.Text := IntToStr(MousePos.Y);
Foreground := GetForegroundwindow; // pobierz uchwyt okna
// pobierz tytul aktywnego okna
GetWindowText(Foreground, Buffer, SizeOf(Buffer));
lblTitle.Caption := Buffer;
end;
end;
procedure TMainForm.FormCreate(Sender: TObject);
begin
{ Ta funkcja rejestruje skrót: Ctrl + Enter dla naszej aplikacji }
RegisterHotKey(Handle, $0001, MOD_CONTROL, VK_Return);
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
{ zwolnienie skrotu w systemi }
UnregisterHotKey(Handle, $0001);
end;
procedure TMainForm.btnAcceptClick(Sender: TObject);
begin
if not Timer.Enabled then // jezeli Timer jest wylaczony
begin
Timer.Interval := Wait.Value * 60000; // ustaw czas pomiedzy dzialaniami
Timer.Enabled := True; // wlacz timer
Caption := 'Klikacz - włączony!'; // zmien wlasciwosc okna
// licznik ktory bedzie odliczal do kolejnego klikniecia
iCountdown := Wait.Value * 60;
Countdown.Interval := 1000;
// wlaczenie licznika
Countdown.Enabled := True;
end else
begin
Timer.Enabled := False; // w przeciwnym wypadku - wylacz timer
Caption := 'Klikacz - wyłączony!'; // zmien wartosc
Countdown.Enabled := False;
end;
end;
procedure TMainForm.TimerTimer(Sender: TObject);
var
CurrentPos : TPoint;
CurrentWindow : HWND;
begin
CurrentWindow := GetForegroundWindow; // pobierz uchwyt aktywnego okna
GetCursorPos(CurrentPos); // pobierz tymczasowa pozycje ekranu
ShowWindow(Foreground, SW_SHOWNA); // pokaż okno
BringWindowToTop(Foreground); // dla pewnosci - wysun na wierzch
SetForegroundwindow(Foreground); // ustaw aktywne okno
SetCursorPos(StrToInt(Xedt.Text), StrToInt(Yedt.Text)); // ustaw w wybranej pozycji
{ kliknij na pozycje }
mouse_event(MOUSEEVENTF_LEFTDOWN, StrToInt(Xedt.Text), StrToInt(Yedt.Text), 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, StrToInt(Xedt.Text), StrToInt(Yedt.Text), 0, 0);
ShowWindow(Currentwindow, SW_SHOWNA); // pokaż okno
SetForegroundWindow(Currentwindow); // ustaw aktywne okno
SetCursorPos(CurrentPos.X, CurrentPos.Y); // ustaw ponownie na poprzedniej pozycji
iCountdown := Wait.Value * 60;
Inc(Counter); // zwieksz licznik
StatusBar.SimpleText := 'Kliknięto... poraz ' + IntToStr(Counter);
end;
procedure TMainForm.CountdownTimer(Sender: TObject);
begin
lblCountdown.Caption := 'Czas pozostały do kolejnego kliknięcia: ' + IntToStr(iCountdown);
Dec(iCountdown);
end;
end.
Kod źródłowy programu:
Witam,
Super artykuł. Mam jednak problem.. Co należy zrobić, aby program wykonywał np. 4 kliknięcia pod rząd w różne miejsca?
//BTW. Na moim Windowsie 98 wogóle nie zalicza tych kliknięć..
nie da sie sciagnąć
i omów dokładniej
mouse_event(MOUSEEVENTF_LEFTDOWN, StrToInt(Xedt.Text), StrToInt(Yedt.Text), 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, StrToInt(Xedt.Text), StrToInt(Yedt.Text), 0, 0);
co to są te zera??