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