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__ |