1# X11::GUITest ($Id: GUITest.pm 243 2014-03-17 12:09:14Z ctrondlp $)
2#
3# Copyright (c) 2003-2014  Dennis K. Paulsen, All Rights Reserved.
4# Email: ctrondlp@cpan.org
5#
6# This program is free software; you can redistribute it and/or
7# modify it under the terms of the GNU General Public License as
8# published by the Free Software Foundation; either version 2 of
9# the License, or (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, see <http://www.gnu.org/licenses>.
18#
19#
20
21=head1 NAME
22
23B<X11::GUITest> - Provides GUI testing/interaction routines.
24
25=head1 VERSION
26
270.28
28
29Updates are made available at the following sites:
30
31  http://sourceforge.net/projects/x11guitest
32  http://www.cpan.org
33
34Please consult 'docs/Changes' for the list of changes between
35module revisions.
36
37=head1 DESCRIPTION
38
39This Perl package is intended to facilitate the testing of GUI applications
40by means of user emulation.  It can be used to test/interact with GUI
41applications; which have been built upon the X library or toolkits
42(i.e., GTK+, Xt, Qt, Motif, etc.) that "wrap" the X library's functionality.
43
44A basic recorder (x11guirecord) is also available, and can be found in
45the source code repository.
46
47=head1 DEPENDENCIES
48
49An X server with the XTest extensions enabled.  This seems to be the
50norm.  If it is not enabled, it usually can be by modifying the X
51server configuration (i.e., XF86Config).
52
53The standard DISPLAY environment variable is utilized to determine
54the host, display, and screen to work with.  By default it is usually set
55to ":0.0" for the localhost.  However, by altering this variable one can
56interact with applications under a remote host's X server.  To change this
57from a terminal window, one can utilize the following basic syntax:
58export DISPLAY=<hostname-or-ipaddress>:<display>.<screen>  Please note that
59under most circumstances, xhost will need to be executed properly on the remote
60host as well.
61
62There is a known incompatibility between the XTest and Xinerama extensions,
63which causes the XTestFakeMotionEvent() function to misbehave.  When the
64Xinerama (X server) extension is turned on, this (Perl) extension has been
65modified to allow one to invoke an alternative function.  See Makefile.PL for
66details.
67
68=head1 INSTALLATION
69
70  perl Makefile.PL
71  make
72  make test
73  make install
74
75  # If the build has errors, you may need to install the following dependencies:
76  #    libxt-dev, libxtst-dev
77
78  # If you'd like to install the recorder, use these steps:
79  cd recorder
80  ./autogen.sh
81  ./configure
82  make
83  make install
84  x11guirecord --help
85
86=head1 SYNOPSIS
87
88For additional examples, please look under the 'eg/'
89sub-directory from the installation folder.
90
91  use X11::GUITest qw/
92    StartApp
93    WaitWindowViewable
94    SendKeys
95  /;
96
97  # Start gedit application
98  StartApp('gedit');
99
100  # Wait for application window to come up and become viewable.
101  my ($GEditWinId) = WaitWindowViewable('gedit');
102  if (!$GEditWinId) {
103    die("Couldn't find gedit window in time!");
104  }
105
106  # Send text to it
107  SendKeys("Hello, how are you?\n");
108
109  # Close Application (Alt-f, q).
110  SendKeys('%(f)q');
111
112  # Handle gedit's Question window if it comes up when closing.  Wait
113  # at most 5 seconds for it.
114  if (WaitWindowViewable('Question', undef, 5)) {
115    # DoN't Save (Alt-n)
116    SendKeys('%(n)');
117  }
118
119=cut
120
121package X11::GUITest;
122
123use strict;
124use warnings;
125use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
126
127require Exporter;
128require DynaLoader;
129#require AutoLoader;
130
131@ISA = qw(Exporter DynaLoader);
132# Items to export into callers namespace by default. Note: do not export
133# names by default without a very good reason. Use EXPORT_OK instead.
134# Do not simply export all your public functions/methods/constants.
135@EXPORT = qw(
136
137);
138
139@EXPORT_OK = qw(
140	ClickMouseButton
141	ClickWindow
142	DefaultScreen
143	FindWindowLike
144	GetChildWindows
145	GetEventSendDelay
146	GetInputFocus
147	GetKeySendDelay
148	GetMousePos
149	GetParentWindow
150	GetRootWindow
151	GetScreenDepth
152	GetScreenRes
153	GetWindowFromPoint
154	GetWindowName
155	GetWindowPid
156	GetWindowPos
157	GetWindowsFromPid
158	IconifyWindow
159	IsChild
160	IsKeyPressed
161	IsMouseButtonPressed
162	IsWindow
163	IsWindowCursor
164	IsWindowViewable
165	LowerWindow
166	MoveMouseAbs
167	MoveWindow
168	PressKey
169	PressMouseButton
170	PressReleaseKey
171	QSfSK
172	QuoteStringForSendKeys
173	RaiseWindow
174	ReleaseKey
175	ReleaseMouseButton
176	ResizeWindow
177	RunApp
178	ScreenCount
179	SendKeys
180	SetEventSendDelay
181	SetInputFocus
182	SetKeySendDelay
183	SetWindowName
184	StartApp
185	UnIconifyWindow
186	WaitSeconds
187	WaitWindowClose
188	WaitWindowLike
189	WaitWindowViewable
190);
191
192# Tags (:ALL, etc.)
193%EXPORT_TAGS = (
194	'ALL' => \@EXPORT_OK,
195	'CONST' => [qw(DEF_WAIT M_LEFT M_MIDDLE M_RIGHT M_UP M_DOWN M_BTN1 M_BTN2 M_BTN3 M_BTN4 M_BTN5 XC_X_CURSOR XC_ARROW XC_BASED_ARROW_DOWN XC_BASED_ARROW_UP XC_BOAT XC_BOGOSITY XC_BOTTOM_LEFT_CORNER XC_BOTTOM_RIGHT_CORNER XC_BOTTOM_SIDE XC_BOTTOM_TEE XC_BOX_SPIRAL XC_CENTER_PTR XC_CIRCLE XC_CLOCK XC_COFFEE_MUG XC_CROSS XC_CROSS_REVERSE XC_CROSSHAIR XC_DIAMOND_CROSS XC_DOT XC_DOTBOX XC_DOUBLE_ARROW XC_DRAFT_LARGE XC_DRAFT_SMALL XC_DRAPED_BOX XC_EXCHANGE XC_FLEUR XC_GOBBLER XC_GUMBY XC_HAND1 XC_HAND2 XC_HEART XC_ICON XC_IRON_CROSS XC_LEFT_PTR XC_LEFT_SIDE XC_LEFT_TEE XC_LEFTBUTTON XC_LL_ANGLE XC_LR_ANGLE XC_MAN XC_MIDDLEBUTTON XC_MOUSE XC_PENCIL XC_PIRATE XC_PLUS XC_QUESTION_ARROW XC_RIGHT_PTR XC_RIGHT_SIDE XC_RIGHT_TEE XC_RIGHTBUTTON XC_RTL_LOGO XC_SAILBOAT XC_SB_DOWN_ARROW XC_SB_H_DOUBLE_ARROW XC_SB_LEFT_ARROW XC_SB_RIGHT_ARROW XC_SB_UP_ARROW XC_SB_V_DOUBLE_ARROW XC_SHUTTLE XC_SIZING XC_SPIDER XC_SPRAYCAN XC_STAR XC_TARGET XC_TCROSS XC_TOP_LEFT_ARROW XC_TOP_LEFT_CORNER XC_TOP_RIGHT_CORNER XC_TOP_SIDE XC_TOP_TEE XC_TREK XC_UL_ANGLE XC_UMBRELLA XC_UR_ANGLE XC_WATCH XC_XTERM)],
196);
197
198Exporter::export_ok_tags(keys %EXPORT_TAGS);
199
200$VERSION = '0.28';
201
202# Module Constants
203sub DEF_WAIT() { 10; }
204# Mouse Buttons
205sub M_BTN1() { 1; }
206sub M_BTN2() { 2; }
207sub M_BTN3() { 3; }
208sub M_BTN4() { 4; }
209sub M_BTN5() { 5; }
210sub M_LEFT() { M_BTN1; }
211sub M_MIDDLE() { M_BTN2; }
212sub M_RIGHT() { M_BTN3; }
213sub M_UP() { M_BTN4; }
214sub M_DOWN() { M_BTN5; }
215# Cursors
216sub XC_X_CURSOR() { 0 };
217sub XC_ARROW() { 2 };
218sub XC_BASED_ARROW_DOWN() { 4 };
219sub XC_BASED_ARROW_UP() { 6 };
220sub XC_BOAT() { 8 };
221sub XC_BOGOSITY() { 10 };
222sub XC_BOTTOM_LEFT_CORNER() { 12 };
223sub XC_BOTTOM_RIGHT_CORNER() { 14 };
224sub XC_BOTTOM_SIDE() { 16 };
225sub XC_BOTTOM_TEE() { 18 };
226sub XC_BOX_SPIRAL() { 20 };
227sub XC_CENTER_PTR() { 22 };
228sub XC_CIRCLE() { 24 };
229sub XC_CLOCK() { 26 };
230sub XC_COFFEE_MUG() { 28 };
231sub XC_CROSS() { 30 };
232sub XC_CROSS_REVERSE() { 32 };
233sub XC_CROSSHAIR() { 34 };
234sub XC_DIAMOND_CROSS() { 36 };
235sub XC_DOT() { 38 };
236sub XC_DOTBOX() { 40 };
237sub XC_DOUBLE_ARROW() { 42 };
238sub XC_DRAFT_LARGE() { 44 };
239sub XC_DRAFT_SMALL() { 46 };
240sub XC_DRAPED_BOX() { 48 };
241sub XC_EXCHANGE() { 50 };
242sub XC_FLEUR() { 52 };
243sub XC_GOBBLER() { 54 };
244sub XC_GUMBY() { 56 };
245sub XC_HAND1() { 58 };
246sub XC_HAND2() { 60 };
247sub XC_HEART() { 62 };
248sub XC_ICON() { 64 };
249sub XC_IRON_CROSS() { 66 };
250sub XC_LEFT_PTR() { 68 };
251sub XC_LEFT_SIDE() { 70 };
252sub XC_LEFT_TEE() { 72 };
253sub XC_LEFTBUTTON() { 74 };
254sub XC_LL_ANGLE() { 76 };
255sub XC_LR_ANGLE() { 78 };
256sub XC_MAN() { 80 };
257sub XC_MIDDLEBUTTON() { 82 };
258sub XC_MOUSE() { 84 };
259sub XC_PENCIL() { 86 };
260sub XC_PIRATE() { 88 };
261sub XC_PLUS() { 90 };
262sub XC_QUESTION_ARROW() { 92 };
263sub XC_RIGHT_PTR() { 94 };
264sub XC_RIGHT_SIDE() { 96 };
265sub XC_RIGHT_TEE() { 98 };
266sub XC_RIGHTBUTTON() { 100 };
267sub XC_RTL_LOGO() { 102 };
268sub XC_SAILBOAT() { 104 };
269sub XC_SB_DOWN_ARROW() { 106 };
270sub XC_SB_H_DOUBLE_ARROW() { 108 };
271sub XC_SB_LEFT_ARROW() { 110 };
272sub XC_SB_RIGHT_ARROW() { 112 };
273sub XC_SB_UP_ARROW() { 114 };
274sub XC_SB_V_DOUBLE_ARROW() { 116 };
275sub XC_SHUTTLE() { 118 };
276sub XC_SIZING() { 120 };
277sub XC_SPIDER() { 122 };
278sub XC_SPRAYCAN() { 124 };
279sub XC_STAR() { 126 };
280sub XC_TARGET() { 128 };
281sub XC_TCROSS() { 130 };
282sub XC_TOP_LEFT_ARROW() { 132 };
283sub XC_TOP_LEFT_CORNER() { 134 };
284sub XC_TOP_RIGHT_CORNER() { 136 };
285sub XC_TOP_SIDE() { 138 };
286sub XC_TOP_TEE() { 140 };
287sub XC_TREK() { 142 };
288sub XC_UL_ANGLE() { 144 };
289sub XC_UMBRELLA() { 146 };
290sub XC_UR_ANGLE() { 148 };
291sub XC_WATCH() { 150 };
292sub XC_XTERM() { 152 };
293
294# Module Variables
295
296
297bootstrap X11::GUITest $VERSION;
298
299=head1 FUNCTIONS
300
301Parameters enclosed within [] are optional.
302
303If there are multiple optional parameters available for a function
304and you would like to specify the last one, for example, you can
305utilize undef for those parameters you don't specify.
306
307REGEX in the documentation below denotes an item that is treated as
308a regular expression.  For example, the regex "^OK$" would look for
309an exact match for the word OK.
310
311
312=over 8
313
314=item FindWindowLike TITLEREGEX [, WINDOWIDSTARTUNDER]
315
316Finds the window Ids of the windows matching the specified title regex.
317Optionally one can specify the window to start under; which would allow
318one to constrain the search to child windows of that window.
319
320An array of window Ids is returned for the matches found.  An empty
321array is returned if no matches were found.
322
323  my @WindowIds = FindWindowLike('gedit');
324  # Only worry about first window found
325  my ($WindowId) = FindWindowLike('gedit');
326
327=back
328
329=cut
330
331my $FindWindowLikeAux =
332sub {
333	my $titlerx = shift;
334	my $start = shift;
335	my $winname = '';
336	my @wins = ();
337
338	# Match the starting window???
339	$winname = GetWindowName($start);
340	if (defined $winname && $winname =~ /$titlerx/i) {
341		push @wins, $start;
342	}
343
344	# Match a child window?
345	foreach my $child (GetChildWindows($start)) {
346		$winname = GetWindowName($child);
347		if (defined $winname && $winname =~ /$titlerx/i) {
348			push @wins, $child;
349		}
350	}
351	return(@wins);
352};
353
354sub FindWindowLike {
355	my $titlerx = shift;
356	my $start = shift;
357
358	if (defined $start) {
359		return &$FindWindowLikeAux($titlerx, $start);
360	}
361	else {
362		my @wins = ();
363		for (my $i = ScreenCount() - 1; $i >= 0 ; --$i) {
364			push @wins, &$FindWindowLikeAux($titlerx,
365							GetRootWindow($i));
366		}
367		return(@wins);
368	}
369}
370
371
372=over 8
373
374=item WaitWindowLike TITLEREGEX [, WINDOWIDSTARTUNDER] [, MAXWAITINSECONDS]
375
376Waits for a window to come up that matches the specified title regex.
377Optionally one can specify the window to start under; which would allow
378one to constrain the search to child windows of that window.
379
380One can optionally specify an alternative wait amount in seconds.  A
381window will keep being looked for that matches the specified title regex
382until this amount of time has been reached.  The default amount is defined
383in the DEF_WAIT constant available through the :CONST export tag.
384
385If a window is going to be manipulated by input, WaitWindowViewable is the
386more robust solution to utilize.
387
388An array of window Ids is returned for the matches found.  An empty
389array is returned if no matches were found.
390
391  my @WindowIds = WaitWindowLike('gedit');
392  # Only worry about first window found
393  my ($WindowId) = WaitWindowLike('gedit');
394
395  WaitWindowLike('gedit') or die("gedit window not found!");
396
397=back
398
399=cut
400
401sub WaitWindowLike {
402	my $titlerx = shift;
403	my $start = shift;
404	my $wait = shift || DEF_WAIT;
405	my @wins = ();
406
407	# For each second we $wait, look for window title once.
408	for (my $i = 0; $i < $wait; $i++) {
409		my @wins = FindWindowLike($titlerx, $start);
410		if (@wins) {
411			return(@wins);
412		}
413		# Wait 1 sec in order not to bog down the system
414		select(undef, undef, undef, 1);
415	}
416	# Nothing
417	return(@wins);
418}
419
420
421=over 8
422
423=item WaitWindowViewable TITLEREGEX [, WINDOWIDSTARTUNDER] [, MAXWAITINSECONDS]
424
425Similar to WaitWindow, but only recognizes windows that are viewable.  When GUI
426applications are started, their window isn't necessarily viewable yet, let alone
427available for input, so this function is very useful.
428
429Likewise, this function will only return an array of the matching window Ids for
430those windows that are viewable.  An empty array is returned if no matches were
431found.
432
433=back
434
435=cut
436
437sub WaitWindowViewable {
438	my $titlerx = shift;
439	my $start = shift;
440	my $wait = shift || DEF_WAIT;
441	my @wins = ();
442
443	# For each second we $wait, look for window title once.
444	for (my $i = 0; $i < $wait; $i++) {
445		# Find windows, but recognize only those that are viewable
446		foreach my $win (FindWindowLike($titlerx, $start)) {
447			if (IsWindowViewable($win)) {
448				push @wins, $win;
449			}
450		}
451		if (@wins) {
452			return(@wins);
453		}
454		# Wait 1 sec in order not to bog down the system.
455		select(undef, undef, undef, 1);
456	}
457	# Nothing
458	return(@wins);
459}
460
461
462=over 8
463
464=item WaitWindowClose WINDOWID [, MAXWAITINSECONDS]
465
466Waits for the specified window to close.
467
468One can optionally specify an alternative wait amount in seconds. The
469window will keep being checked to see if it has closed until this amount
470of time has been reached.  The default amount is defined in the DEF_WAIT
471constant available through the :CONST export tag.
472
473zero is returned if window is not gone, non-zero if it is gone.
474
475=back
476
477=cut
478
479sub WaitWindowClose {
480	my $win = shift;
481	my $wait = shift || DEF_WAIT;
482
483	# For each second we $wait, check window Id
484	# twice (2 lookups * 500ms = ~1 second).
485	for (my $i = 0; $i < ($wait * 2); $i++) {
486		if (not IsWindow($win)) {
487			# Success, window isn't recognized
488			return(1);
489		}
490		# Wait 500 ms in order not to bog down the system.  If one
491		# changes this, the ($wait * 2) above will want to be changed
492		# in order to represent seconds correctly.
493		select(undef, undef, undef, 0.50);
494	}
495	# Failure
496	return(0);
497}
498
499=over 8
500
501=item WaitSeconds SECONDS
502
503Pauses execution for the specified amount of seconds.
504
505  WaitSeconds(0.5); # Wait 1/2 second
506  WaitSeconds(3); # Wait 3 seconds
507
508=back
509
510=cut
511
512sub WaitSeconds {
513	select(undef, undef, undef, shift);
514}
515
516=over 8
517
518=item ClickWindow WINDOWID [, X Offset] [, Y Offset] [, Button]
519
520Clicks on the specified window with the mouse.
521
522Optionally one can specify the X offset and Y offset.  By default,
523the top left corner of the window is clicked on, with these two
524parameters one can specify a different position to be clicked on.
525
526One can also specify an alternative button.  The default button is
527M_LEFT, but M_MIDDLE and M_RIGHT may be specified too.  Also,
528you could use the logical Id for the button: M_BTN1, M_BTN2, M_BTN3,
529M_BTN4, M_BTN5.  These are all available through the :CONST export
530tag.
531
532zero is returned on failure, non-zero for success
533
534=back
535
536=cut
537
538sub ClickWindow {
539	my $win = shift;
540	my $x_offset = shift || 0;
541	my $y_offset = shift || 0;
542	my $button = shift || M_LEFT;
543
544	my ($x, $y, $scr);
545	($x, $y, undef, undef, undef, $scr) = GetWindowPos($win);
546	if (!defined($x) or !defined($y)) {
547		return(0);
548	}
549	if (!MoveMouseAbs($x + $x_offset, $y + $y_offset, $scr)) {
550		return(0);
551	}
552	if (!ClickMouseButton($button)) {
553		return(0);
554	}
555	return(1);
556}
557
558=over 8
559
560=item GetWindowsFromPid
561
562Returns a list of window ids discovered for the specified process id (pid).
563
564undef is returned on error.
565
566=back
567
568=cut
569
570sub GetWindowsFromPid {
571	my $pid = shift;
572	my @wins = ();
573
574	if ($pid <= 0) {
575		return(undef);
576	}
577
578	my @all_wins = FindWindowLike('.*');
579	foreach my $aw (@all_wins) {
580		my $aw_pid = GetWindowPid($aw);
581		if ($aw_pid == $pid) {
582			push @wins, $aw;
583		}
584	}
585	return(@wins);
586}
587
588=over 8
589
590=item GetWindowFromPoint X, Y [, SCREEN]
591
592Returns the window that is at the specified point.  If no screen is given, it
593is taken from the value given when opening the X display.
594
595zero is returned if there are no matches (i.e., off screen).
596
597=back
598
599=cut
600
601sub GetWindowFromPoint {
602	my $x = shift;
603	my $y = shift;
604	my $scr = shift;
605	my $lastmatch = 0;
606
607	if ( ! defined $scr) {
608		$scr = DefaultScreen();
609	}
610
611	# Note: Windows are returned in current stacking order, therefore
612	# the last match should be the top-most window.
613	foreach my $win ( GetChildWindows(GetRootWindow($scr)) ) {
614		my ($w_x1, $w_y1, $w_w, $w_h, $w_b) = GetWindowPos($win);
615		# Is window position invalid?
616		if (!defined $w_x1) {
617			next;
618		}
619		my $w_x2 = ($w_x1 + $w_w + ($w_b << 1));
620		my $w_y2 = ($w_y1 + $w_h + ($w_b << 1));
621		# Does window match our point?
622		if ($x >= $w_x1 && $x < $w_x2 && $y >= $w_y1 && $y < $w_y2) {
623			$lastmatch = $win;
624		}
625	}
626	return($lastmatch);
627}
628
629
630=over 8
631
632=item IsChild PARENTWINDOWID, WINDOWID
633
634Determines if the specified window is a child of the
635specified parent.
636
637zero is returned for false, non-zero for true.
638
639=back
640
641=cut
642
643sub IsChild {
644	my $parent = shift;
645	my $win = shift;
646
647	foreach my $child ( GetChildWindows($parent) ) {
648		if ($child == $win && $child != $parent) {
649			return(1);
650		}
651	}
652	return(0);
653}
654
655
656=over 8
657
658=item QuoteStringForSendKeys STRING
659
660Quotes {} characters in the specified string that would be interpreted
661as having special meaning if sent to SendKeys directly.  This function
662would be useful if you had a text file in which you wanted to use each
663line of the file as input to the SendKeys function, but didn't want
664any special interpretation of the characters in the file.
665
666Returns the quoted string, undef is returned on error.
667
668  # Quote  ~, %, etc.  as  {~}, {%}, etc for literal use in SendKeys.
669  SendKeys( QuoteStringForSendKeys('Hello: ~%^(){}+#') );
670  SendKeys( QSfSK('#+#') );
671
672The international AltGr key - modifier character (&) is not escaped by
673this function.  Escape this character manually ("{&}"), if used/needed.
674
675=back
676
677=cut
678
679sub QuoteStringForSendKeys {
680	my $str = shift;
681	if (!defined($str)) {
682		return(undef);
683	}
684
685	# Quote {} special characters (^, %, (, {, etc.)
686	$str =~ s/(\^|\%|\+|\~|\(|\)|\{|\})/\{$1\}/gm;
687
688	return($str);
689}
690
691sub QSfSK {
692	return QuoteStringForSendKeys(shift);
693}
694
695=over 8
696
697=item StartApp COMMANDLINE
698
699Uses the shell to execute a program.  This function returns as
700soon as the program is called.  Useful for starting GUI
701/applications and then going on to work with them.
702
703zero is returned on failure, non-zero for success
704
705  StartApp('gedit');
706
707=back
708
709=cut
710
711sub StartApp {
712	my @cmd = @_;
713	my $pid = fork;
714	if ($pid) {
715		use POSIX qw(WNOHANG);
716		sleep 1;
717		waitpid($pid, WNOHANG) != $pid
718			and kill(0, $pid) == 1
719			and return $pid;
720	} elsif (defined $pid) {
721		use POSIX qw(_exit);
722		exec @cmd or _exit(1);
723	}
724	return;
725}
726
727
728=over 8
729
730=item RunApp COMMANDLINE
731
732Uses the shell to execute a program until its completion.
733
734Return value will be application specific, however -1 is returned
735to indicate a failure in starting the program.
736
737  RunApp('/work/myapp');
738
739=back
740
741=cut
742
743sub RunApp {
744	my $cmdline = shift;
745	return( system($cmdline) );
746}
747
748
749=over 8
750
751=item ClickMouseButton BUTTON
752
753Clicks the specified mouse button.  Available mouse buttons
754are: M_LEFT, M_MIDDLE, M_RIGHT, M_DOWN, M_UP.  Also, you could
755use the logical Id for the button: M_BTN1, M_BTN2, M_BTN3,
756M_BTN4, M_BTN5.  These are all available through the :CONST
757export tag.
758
759zero is returned on failure, non-zero for success.
760
761=back
762
763=cut
764
765sub ClickMouseButton {
766	my $button = shift;
767
768	if (!PressMouseButton($button) ||
769		!ReleaseMouseButton($button)) {
770		return(0);
771	}
772	return(1);
773}
774
775# Subroutine: INIT
776# Description: Used to initialize the underlying mechanisms
777#			   that this package utilizes.
778# Note: Perl idiom not to return values for this subroutine.
779sub INIT {
780	if (!defined($ENV{'AUTOMATED_TESTING'}) || $ENV{'AUTOMATED_TESTING'} ne 1) {
781		InitGUITest();
782	}
783}
784
785# Subroutine: END
786# Description: Used to deinitialize the underlying mechanisms
787#			   that this package utilizes.
788# Note: Perl idiom not to return values for this subroutine.
789sub END {
790	DeInitGUITest();
791}
792
793=over 8
794
795=item DefaultScreen
796
797Returns the screen number specified in the X display value used to open the
798display.
799
800Leverages the Xlib macro of the same name.
801
802=back
803
804=cut
805
806=over 8
807
808=item ScreenCount
809
810Returns the number of screens in the X display specified when opening it.
811
812Leverages the Xlib macro of the same name.
813
814=back
815
816=cut
817
818=over 8
819
820=item SetEventSendDelay DELAYINMILLISECONDS
821
822Sets the milliseconds of delay between events being sent to the
823X display.  It is usually not a good idea to set this to 0.
824
825Please note that this delay will also affect SendKeys.
826
827Returns the old delay amount in milliseconds.
828
829=back
830
831=cut
832
833=over 8
834
835=item GetEventSendDelay
836
837Returns the current event sending delay amount in milliseconds.
838
839=back
840
841=cut
842
843=over 8
844
845=item SetKeySendDelay DELAYINMILLISECONDS
846
847Sets the milliseconds of delay between keystrokes.
848
849Returns the old delay amount in milliseconds.
850
851=back
852
853=cut
854
855=over 8
856
857=item GetKeySendDelay
858
859Returns the current keystroke sending delay amount in milliseconds.
860
861=back
862
863=cut
864
865=over 8
866
867=item GetWindowName WINDOWID
868
869Returns the window name for the specified window Id.  undef
870is returned if name could not be obtained.
871
872  # Return the name of the window that has the input focus.
873  my $WinName = GetWindowName(GetInputFocus());
874
875=back
876
877=cut
878
879=over 8
880
881=item GetWindowPid WINDOWID
882
883Returns the process id (pid) associated with the specified
884window.  0 is returned if the pid is not available.
885
886  # Return the pid of the window that has the input focus.
887  my $pid = GetWindowPid(GetInputFocus());
888
889=back
890
891=cut
892
893=over 8
894
895=item SetWindowName WINDOWID, NAME
896
897Sets the window name for the specified window Id.
898
899zero is returned on failure, non-zero for success.
900
901=back
902
903=cut
904
905=over 8
906
907=item GetRootWindow [SCREEN]
908
909Returns the Id of the root window of the screen.  This is the top/root level
910window that all other windows are under.  If no screen is given, it is taken
911from the value given when opening the X display.
912
913=back
914
915=cut
916
917=over 8
918
919=item GetChildWindows WINDOWID
920
921Returns an array of the child windows for the specified
922window Id.  If it detects that the window hierarchy
923is in transition, it will wait half a second and try
924again.
925
926=back
927
928=cut
929
930=over 8
931
932=item MoveMouseAbs X, Y [, SCREEN]
933
934Moves the mouse cursor to the specified absolute position in the optionally
935given screen.  If no screen is given, it is taken from the value given when
936opening the X display.
937
938Zero is returned on failure, non-zero for success.
939
940=back
941
942=cut
943
944=over 8
945
946=item GetMousePos
947
948Returns an array containing the position and the screen (number) of the mouse
949cursor.
950
951  my ($x, $y, $scr_num) = GetMousePos();
952
953=back
954
955=cut
956
957=over 8
958
959=item PressMouseButton BUTTON
960
961Presses the specified mouse button.  Available mouse buttons
962are: M_LEFT, M_MIDDLE, M_RIGHT, M_DOWN, M_UP.  Also, you could
963use the logical Id for the button: M_BTN1, M_BTN2, M_BTN3, M_BTN4,
964M_BTN5.  These are all available through the :CONST export tag.
965
966zero is returned on failure, non-zero for success.
967
968=back
969
970=cut
971
972=over 8
973
974=item ReleaseMouseButton BUTTON
975
976Releases the specified mouse button.  Available mouse buttons
977are: M_LEFT, M_MIDDLE, M_RIGHT, M_DOWN, M_UP.  Also, you could
978use the logical Id for the button: M_BTN1, M_BTN2, M_BTN3, M_BTN4,
979M_BTN5.  These are all available through the :CONST export tag.
980
981zero is returned on failure, non-zero for success.
982
983=back
984
985=cut
986
987=over 8
988
989=item SendKeys KEYS
990
991Sends keystrokes to the window that has the input focus.
992
993The keystrokes to send are those specified in KEYS parameter.  Some characters
994have special meaning, they are:
995
996        Modifier Keys:
997        ^    	CTRL
998        %    	ALT
999        +    	SHIFT
1000        #       META
1001        &       ALTGR
1002
1003        Other Keys:
1004        ~    	ENTER
1005        \n   	ENTER
1006        \t  	TAB
1007        ( and ) MODIFIER GROUPING
1008        { and } QUOTE / ESCAPE CHARACTERS
1009
1010Simply, one can send a text string like so:
1011
1012        SendKeys('Hello, how are you today?');
1013
1014Parenthesis allow a modifier to work on one or more characters.  For example:
1015
1016        SendKeys('%(f)q'); # Alt-f, then press q
1017        SendKeys('%(fa)^(m)'); # Alt-f, Alt-a, Ctrl-m
1018        SendKeys('+(abc)'); # Uppercase ABC using shift modifier
1019        SendKeys('^(+(l))'); # Ctrl-Shift-l
1020        SendKeys('+'); # Press shift
1021
1022Braces are used to quote special characters, for utilizing aliased key
1023names, or for special functionality. Multiple characters can be specified
1024in a brace by space delimiting the entries.  Characters can be repeated using
1025a number that is space delimited after the preceding key.
1026
1027Quote Special Characters
1028
1029        SendKeys('{{}'); # {
1030        SendKeys('{+}'); # +
1031        SendKeys('{#}'); # #
1032
1033        You can also use QuoteStringForSendKeys (QSfSK) to perform quoting.
1034
1035Aliased Key Names
1036
1037        SendKeys('{BAC}'); # Backspace
1038        SendKeys('{F1 F2 F3}'); # F1, F2, F3
1039        SendKeys('{TAB 3}'); # Press TAB 3 times
1040        SendKeys('{SPC 3 a b c}'); # Space 3 times, a, b, c
1041
1042Special Functionality
1043
1044        # Pause execution for 500 milliseconds
1045        SendKeys('{PAUSE 500}');
1046
1047Combinations
1048
1049        SendKeys('abc+(abc){TAB PAUSE 500}'); # a, b, c, A, B, C, Tab, Pause 500
1050        SendKeys('+({a b c})'); # A, B, C
1051
1052The following abbreviated key names are currently recognized within a brace set.  If you
1053don't see the desired key, you can still use the unabbreviated name for the key.  If you
1054are unsure of this name, utilize the xev (X event view) tool, press the key you
1055want and look at the tools output for the name of that key.  Names that are in the list
1056below can be utilized regardless of case.  Ones that aren't in this list are going to be
1057case sensitive and also not abbreviated.  For example, using 'xev' you will find that the
1058name of the backspace key is BackSpace, so you could use {BackSpace} in place of {bac}
1059if you really wanted to.
1060
1061        Name    Action
1062        -------------------
1063        BAC     BackSpace
1064        BS      BackSpace
1065        BKS     BackSpace
1066        BRE     Break
1067        CAN     Cancel
1068        CAP     Caps_Lock
1069        DEL     Delete
1070        DOWN    Down
1071        END     End
1072        ENT     Return
1073        ESC     Escape
1074        F1      F1
1075        ...     ...
1076        F12     F12
1077        HEL     Help
1078        HOM     Home
1079        INS     Insert
1080        LAL     Alt_L
1081        LMA     Meta_L
1082        LCT     Control_L
1083        LEF     Left
1084        LSH     Shift_L
1085        LSK     Super_L
1086        MNU     Menu
1087        NUM     Num_Lock
1088        PGD     Page_Down
1089        PGU     Page_Up
1090        PRT     Print
1091        RAL     Alt_R
1092        RMA     Meta_R
1093        RCT     Control_R
1094        RIG     Right
1095        RSH     Shift_R
1096        RSK     Super_R
1097        SCR     Scroll_Lock
1098        SPA     Space
1099        SPC     Space
1100        TAB     Tab
1101        UP      Up
1102
1103zero is returned on failure, non-zero for success.  For configurations (Xvfb)
1104that don't support Alt_Left, Meta_Left is automatically used in its place.
1105
1106=back
1107
1108=cut
1109
1110=over 8
1111
1112=item PressKey KEY
1113
1114Presses the specified key.
1115
1116One can utilize the abbreviated key names from the table
1117listed above as outlined in the following example:
1118
1119  # Alt-n
1120  PressKey('LAL'); # Left Alt
1121  PressKey('n');
1122  ReleaseKey('n');
1123  ReleaseKey('LAL');
1124
1125  # Uppercase a
1126  PressKey('LSH'); # Left Shift
1127  PressKey('a');
1128  ReleaseKey('a');
1129  ReleaseKey('LSH');
1130
1131The ReleaseKey calls in the above example are there to set
1132both key states back.
1133
1134zero is returned on failure, non-zero for success.
1135
1136=back
1137
1138=cut
1139
1140=over 8
1141
1142=item ReleaseKey KEY
1143
1144Releases the specified key.  Normally follows a PressKey call.
1145
1146One can utilize the abbreviated key names from the table
1147listed above.
1148
1149  ReleaseKey('n');
1150
1151zero is returned on failure, non-zero for success.
1152
1153=back
1154
1155=cut
1156
1157=over 8
1158
1159=item PressReleaseKey KEY
1160
1161Presses and releases the specified key.
1162
1163One can utilize the abbreviated key names from the table
1164listed above.
1165
1166  PressReleaseKey('n');
1167
1168This function is affected by the key send delay.
1169
1170zero is returned on failure, non-zero for success.
1171
1172=back
1173
1174=cut
1175
1176=over 8
1177
1178=item IsKeyPressed KEY
1179
1180Determines if the specified key is currently being pressed.
1181
1182You can specify such things as 'bac' or the unabbreviated form 'BackSpace' as
1183covered in the SendKeys information.  Brace forms such as '{bac}' are
1184unsupported.  A '{' is taken literally and letters are case sensitive.
1185
1186  if (IsKeyPressed('esc')) {  # Is Escape pressed?
1187  if (IsKeyPressed('a')) { # Is a pressed?
1188  if (IsKeyPressed('A')) { # Is A pressed?
1189
1190Returns non-zero for true, zero for false.
1191
1192=back
1193
1194=cut
1195
1196=over 8
1197
1198=item IsMouseButtonPressed BUTTON
1199
1200Determines if the specified mouse button is currently being pressed.
1201
1202Available mouse buttons are: M_LEFT, M_MIDDLE, M_RIGHT.  Also, you
1203could use the logical Id for the button: M_BTN1, M_BTN2, M_BTN3,
1204M_BTN4, M_BTN5.  These are all available through the :CONST export
1205tag.
1206
1207  if (IsMouseButtonPressed(M_LEFT)) { # Is left button pressed?
1208
1209Returns non-zero for true, zero for false.
1210
1211=back
1212
1213=cut
1214
1215=over 8
1216
1217=item IsWindow WINDOWID
1218
1219zero is returned if the specified window Id is not for something
1220that can be recognized as a window.  non-zero is returned if it
1221looks like a window.
1222
1223=back
1224
1225=cut
1226
1227=over 8
1228
1229=item IsWindowViewable WINDOWID
1230
1231zero is returned if the specified window Id is for a window that
1232isn't viewable.  non-zero is returned if the window is viewable.
1233
1234=back
1235
1236=cut
1237
1238=over 8
1239
1240=item IsWindowCursor WINDOWID CURSOR
1241
1242Determines if the specified window has the specified cursor.
1243
1244zero is returned for false, non-zero for true.
1245
1246The following cursors are available through the :CONST export tag.
1247
1248    Name
1249    -------------------
1250	XC_NUM_GLYPHS
1251	XC_X_CURSOR
1252	XC_ARROW
1253	XC_BASED_ARROW_DOWN
1254	XC_BASED_ARROW_UP
1255	XC_BOAT
1256	XC_BOGOSITY
1257	XC_BOTTOM_LEFT_CORNER
1258	XC_BOTTOM_RIGHT_CORNER
1259	XC_BOTTOM_SIDE
1260	XC_BOTTOM_TEE
1261	XC_BOX_SPIRAL
1262	XC_CENTER_PTR
1263	XC_CIRCLE
1264	XC_CLOCK
1265	XC_COFFEE_MUG
1266	XC_CROSS
1267	XC_CROSS_REVERSE
1268	XC_CROSSHAIR
1269	XC_DIAMOND_CROSS
1270	XC_DOT
1271	XC_DOTBOX
1272	XC_DOUBLE_ARROW
1273	XC_DRAFT_LARGE
1274	XC_DRAFT_SMALL
1275	XC_DRAPED_BOX
1276	XC_EXCHANGE
1277	XC_FLEUR
1278	XC_GOBBLER
1279	XC_GUMBY
1280	XC_HAND1
1281	XC_HAND2
1282	XC_HEART
1283	XC_ICON
1284	XC_IRON_CROSS
1285	XC_LEFT_PTR
1286	XC_LEFT_SIDE
1287	XC_LEFT_TEE
1288	XC_LEFTBUTTON
1289	XC_LL_ANGLE
1290	XC_LR_ANGLE
1291	XC_MAN
1292	XC_MIDDLEBUTTON
1293	XC_MOUSE
1294	XC_PENCIL
1295	XC_PIRATE
1296	XC_PLUS
1297	XC_QUESTION_ARROW
1298	XC_RIGHT_PTR
1299	XC_RIGHT_SIDE
1300	XC_RIGHT_TEE
1301	XC_RIGHTBUTTON
1302	XC_RTL_LOGO
1303	XC_SAILBOAT
1304	XC_SB_DOWN_ARROW
1305	XC_SB_H_DOUBLE_ARROW
1306	XC_SB_LEFT_ARROW
1307	XC_SB_RIGHT_ARROW
1308	XC_SB_UP_ARROW
1309	XC_SB_V_DOUBLE_ARROW
1310	XC_SHUTTLE
1311	XC_SIZING
1312	XC_SPIDER
1313	XC_SPRAYCAN
1314	XC_STAR
1315	XC_TARGET
1316	XC_TCROSS
1317	XC_TOP_LEFT_ARROW
1318	XC_TOP_LEFT_CORNER
1319	XC_TOP_RIGHT_CORNER
1320	XC_TOP_SIDE
1321	XC_TOP_TEE
1322	XC_TREK
1323	XC_UL_ANGLE
1324	XC_UMBRELLA
1325	XC_UR_ANGLE
1326	XC_WATCH
1327	XC_XTERM
1328
1329=back
1330
1331=cut
1332
1333=over 8
1334
1335=item MoveWindow WINDOWID, X, Y
1336
1337Moves the window to the specified location.
1338
1339zero is returned on failure, non-zero for success.
1340
1341=back
1342
1343=cut
1344
1345=over 8
1346
1347=item ResizeWindow WINDOWID, WIDTH, HEIGHT
1348
1349Resizes the window to the specified size.
1350
1351zero is returned on failure, non-zero for success.
1352
1353=back
1354
1355=cut
1356
1357=over 8
1358
1359=item IconifyWindow WINDOWID
1360
1361Minimizes (Iconifies) the specified window.
1362
1363zero is returned on failure, non-zero for success.
1364
1365=back
1366
1367=cut
1368
1369=over 8
1370
1371=item UnIconifyWindow WINDOWID
1372
1373Unminimizes (UnIconifies) the specified window.
1374
1375zero is returned on failure, non-zero for success.
1376
1377=back
1378
1379=cut
1380
1381=over 8
1382
1383=item RaiseWindow WINDOWID
1384
1385Raises the specified window to the top of the stack, so
1386that no other windows cover it.
1387
1388zero is returned on failure, non-zero for success.
1389
1390=back
1391
1392=cut
1393
1394=over 8
1395
1396=item LowerWindow WINDOWID
1397
1398Lowers the specified window to the bottom of the stack, so
1399other existing windows will cover it.
1400
1401zero is returned on failure, non-zero for success.
1402
1403=back
1404
1405=cut
1406
1407=over 8
1408
1409=item GetInputFocus
1410
1411Returns the window that currently has the input focus.
1412
1413=back
1414
1415=cut
1416
1417=over 8
1418
1419=item SetInputFocus WINDOWID
1420
1421Sets the specified window to be the one that has the input focus.
1422
1423zero is returned on failure, non-zero for success.
1424
1425=back
1426
1427=cut
1428
1429=over 8
1430
1431=item GetWindowPos WINDOWID
1432
1433Returns an array containing the position information for the specified
1434window.  It also returns size information (including border width) and the
1435number of the screen where the window resides.
1436
1437  my ($x, $y, $width, $height, $borderWidth, $screen) =
1438        GetWindowPos(GetRootWindow());
1439
1440=back
1441
1442=cut
1443
1444=over 8
1445
1446=item GetParentWindow WINDOWID
1447
1448Returns the parent of the specified window.
1449
1450zero is returned if parent couldn't be determined (i.e., root window).
1451
1452=back
1453
1454=cut
1455
1456=over 8
1457
1458=item GetScreenDepth [SCREEN]
1459
1460Returns the color depth for the screen.  If no screen is specified, it is taken
1461from the value given when opening the X display.  If the screen (number) is
1462invalid, -1 will be returned.
1463
1464Value is represented as bits, i.e. 16.
1465
1466  my $depth = GetScreenDepth();
1467
1468=back
1469
1470=cut
1471
1472=over 8
1473
1474=item GetScreenRes [SCREEN]
1475
1476Returns the screen resolution.  If no screen is specified, it is taken from the
1477value given when opening the X display.  If the screen (number) is invalid, the
1478returned list will be empty.
1479
1480  my ($x, $y) = GetScreenRes();
1481
1482=back
1483
1484=cut
1485
1486=head1 OTHER DOCUMENTATION
1487
1488
1489=begin html
1490
1491<a href='../Changes'>Module Changes</a><br>
1492<a href='CodingStyle'>Coding-Style Guidelines</a><br>
1493<a href='../ToDo'>ToDo List</a><br>
1494<a href='Copying'>Copy of the GPL License</a><br>
1495
1496=end html
1497
1498
1499=begin text
1500
1501  Available under the docs sub-directory.
1502    CodingStyle (Coding-Style Guidelines)
1503    Copying (Copy of the GPL License)
1504
1505=end text
1506
1507=begin man
1508
1509Not installed.
1510
1511=end man
1512
1513
1514=head1 COPYRIGHT
1515
1516Copyright(c) 2003-2014 Dennis K. Paulsen, All Rights Reserved.  This
1517program is free software; you can redistribute it and/or modify it
1518under the terms of the GNU General Public License.
1519
1520=head1 AUTHOR
1521
1522Dennis K. Paulsen <ctrondlp@cpan.org> (Iowa USA)
1523
1524=head1 CONTRIBUTORS
1525
1526Paulo E. Castro <pauloedgarcastro tata gmail.com>
1527
1528=head1 CREDITS
1529
1530Thanks to everyone; including those specifically mentioned below for patches,
1531suggestions, etc.:
1532
1533  David Dick
1534  Alexey Tourbin
1535  Richard Clamp
1536  Gustav Larsson
1537  Nelson D. Caro
1538
1539=cut
1540
1541
1542# Autoload methods go after __END__, and are processed by the autosplit program.
1543
1544# Return success
15451;
1546__END__
1547