File Coverage

blib/lib/X11/SendEvent.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             #
2             # Copyright (c) Erick Calder, 2002.
3             # All rights reserved.
4             #
5              
6             =head1 NAME
7              
8             X11::SendEvent - a module for sending events to X windows
9              
10             =head1 SYNOPSIS
11              
12             use X11::SendEvent;
13              
14             $win = X11::SendEvent->new(win => "MyWindowName");
15             $win->SendString("testing", ["Return"]);
16              
17             =head1 DESCRIPTION
18              
19             This module presents a simple interface for sending events, keycodes, keysyms and strings to an X window from a perl application.
20              
21             =cut
22              
23             package X11::SendEvent;
24              
25             # --- external modules --------------------------------------------------------
26              
27 1     1   14809 use warnings;
  1         2  
  1         27  
28 1     1   4 use strict;
  1         2  
  1         25  
29              
30 1     1   1187 use X11::Protocol;
  0            
  0            
31             use X11::Keyboard;
32              
33             # --- module variables --------------------------------------------------------
34              
35             use vars qw($VERSION);
36              
37             $VERSION = substr q$Revision: 1.3 $, 10;
38              
39             # --- module interface --------------------------------------------------------
40              
41             =head1 METHODS
42              
43             An object oriented interface is provided as follows:
44              
45             =head2 new [options-hash]
46              
47             Used to initialise the system and create a module instance. The optional hash may contain any of the following keys:
48              
49             =item disp
50              
51             Specifies X display to use. If this item is not provided, the environment variable B is used. If the aforementioned variable is not set the item defaults to C
52              
53             =item x
54              
55             The caller may pass an X connection independently generated using the B module. When both I and I are passed, I takes precedence.
56              
57             =item win => [criteria]
58              
59             Setting this item instructs the module to automatically find a window to be used for sending events to. The value passed must be an array reference of values which are handed "as is" to the I<-EFindWin()> method; for further information please refer to its description below.
60              
61             =item debug
62              
63             Turns debugging output on.
64              
65             =cut
66              
67             sub new {
68             my $proto = shift;
69             my $class = ref($proto) || $proto;
70             my $self = bless({}, $class);
71              
72             my %args = @_;
73            
74             $self->{disp} = $args{disp} || $ENV{DISPLAY} || "localhost:0.0";
75             $self->{x} = $args{x} || X11::Protocol->new($self->{disp});
76             $self->{kbd} = X11::Keyboard->new($self->{x});
77             $self->{debug} = $args{debug} || 0;
78              
79             if ($args{win} =~ /^\d+$/) {
80             $self->{win} = $args{win}; # window id passed
81             }
82             elsif ($args{win}) {
83             $self->FindWin( @{$args{win}} ); # autoload
84             }
85              
86             return $self;
87             }
88              
89             =head2 [win-ref] = FindWin [property = "WM_NAME"]
90              
91             This method can find a window by specifying certain criteria. The required string is used to compare against the selected window I which, if left unspecified, defaults as shown above.
92              
93             The the return value is an object reference which may be used to call methods. When multiple windows are found, any method called on the object will operate on all windows. If no windows are found the method returns I.
94              
95             I<- exempli gratia ->
96              
97             $win = $self->FindWin("x");
98             $win->SendString("HELLO");
99              
100             the code above finds all windows containing the string C in their names and sends them the string C.
101              
102             =cut
103              
104             sub FindWin {
105             my ($self, $val, $key) = @_;
106             return warn "No window name specified!" unless $val;
107             $key ||= "WM_NAME";
108             $self->debug("FindWin()");
109              
110             my @win;
111             my $x = $self->{x};
112             my $class = $x->atom($key);
113             for ($self->wins()) {
114             my ($wc) = $x->GetProperty($_, $class, "AnyPropertyType", 0, 256, 0);
115             push @win, $_ if $wc =~ /^$val/i;
116             $self->debug($wc, 2);
117             }
118            
119             $self->debug(sprintf("- %d [0x%x]", $_, $_)) for @win;
120             $self->{win} = \@win;
121             $self;
122             }
123              
124             =head2 SendEvent [args]
125              
126             Use this method to send generic events to a window. The arguments are passed as a hash, where valid keys are as follows:
127              
128             =item type
129              
130             A string containing the event type of event to send e.g. I, I etc.
131              
132             =item win
133              
134             The id of the window to which to send the event. If omitted, the window identified in the call to I<-Enew()> (if any is used), else the function warns and returns.
135              
136             =item detail, state
137              
138             For more information on both of these keys, please refer to the X11 protocol specification.
139              
140             =cut
141              
142             sub SendEvent {
143             my $self = shift;
144             my %args = (%$self, @_);
145             my $x = $self->{x};
146              
147             return warn "No window id specified!" unless @{$args{win}};
148              
149             my $event = $x->pack_event(
150             name => $args{type},
151             detail => $args{detail},
152             state => $args{state},
153             time => time(),
154             root => $x->root(),
155             same_screen => 1,
156             # event => 'Normal',
157             );
158              
159             my $mask = $x->pack_event_mask($args{type});
160             $x->SendEvent($_, 1, $mask, $event)
161             for @{$args{win}};
162             }
163              
164             =head2 SendKeycode [state = 0]
165              
166             Use this method to send a keycode to the window. A shift state may also be specified, defaulting to the value shown above.
167              
168             =head2 SendKeycode [list-ref = $_]
169              
170             Alternatively, the arguments may be passed as a list reference, which defaults to B<$_>.
171              
172             =cut
173              
174             sub SendKeycode {
175             my $self = shift;
176             my $args = shift || $_;
177             my $state = shift;
178              
179             ($args, $state) = @$args if ref($args) eq "ARRAY";
180             $state ||= 0;
181              
182             my %args = (detail => $args, state => $state);
183             $self->SendEvent(type => "KeyPress", %args);
184             $self->SendEvent(type => "KeyRelease", %args);
185             }
186              
187             =head2 SendKeysym
188              
189             This method translates the given keysym name into a keycode and sends it to the window.
190              
191             =cut
192              
193             sub SendKeysym {
194             my $self = shift;
195             my ($keysym, $kbd) = (shift, $self->{kbd});
196             $self->SendKeycode($kbd->KeysymToKeycode($keysym));
197             }
198              
199             =head2 SendString
200              
201             Use this method to send strings to a window. Keysyms and/or keycode/states may be interspersed in the parameter list via the inclusion of array references. The arrays passed may contain either a keysym name or a keycode and state (separated by a slash).
202              
203             I<- exempli gratia ->
204              
205             $win->SendString("user", ["Return"], "joe", ["9/1"]);
206              
207             In the above example, the string C is sent to the application, followed by a C key. Then the string C is sent, followed by the shifted keycode 9.
208              
209             =cut
210              
211             sub SendString {
212             my $self = shift;
213             my $k = $self->{kbd};
214              
215             my @keycodes;
216             for (@_) {
217             if (ref($_) eq "ARRAY") {
218             $_ = shift @$_;
219             push @keycodes, [ m|/| ? split "/" : $k->KeysymToKeycode() ];
220             }
221             else {
222             push @keycodes, [ $k->KeysymToKeycode() ] for split //;
223             }
224             }
225            
226             $self->SendKeycode() for @keycodes;
227              
228             #for (@keycodes) {
229             # print $_->[0], "/", $_->[1], "\n";
230             # $self->SendKeycode();
231             # }
232             }
233              
234             # --- internal functions ------------------------------------------------------
235              
236             # returns a list of all open X windows in no particular order
237             # including child windows
238              
239             sub wins {
240             my $self = shift;
241             my $win = shift || $_;
242             my $x = $self->{x};
243             my (undef, undef, @wins) = $x->QueryTree($win || $x->root());
244              
245             my @ret = @wins;
246             push @ret, $self->wins() for @wins;
247             @ret;
248             }
249              
250             sub debug {
251             my $self = shift;
252             my $arg = shift;
253             my $debug = shift || 1;
254             return unless $self->{debug} >= $debug;
255             local ($\, $,) = ("\n", " ");
256             print STDERR ">", "X11::SendEvent", "-", $arg;
257             }
258              
259             1; # :)
260              
261             __END__