imitator_x 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING.LESSER.rdoc +169 -0
- data/COPYING.rdoc +678 -0
- data/README.rdoc +70 -0
- data/Rakefile.rb +99 -0
- data/TODO.rdoc +8 -0
- data/ext/clipboard.c +429 -0
- data/ext/clipboard.h +61 -0
- data/ext/extconf.rb +55 -0
- data/ext/keyboard.c +711 -0
- data/ext/keyboard.h +29 -0
- data/ext/mouse.c +456 -0
- data/ext/mouse.h +28 -0
- data/ext/x.c +84 -0
- data/ext/x.h +48 -0
- data/ext/xwindow.c +1434 -0
- data/ext/xwindow.h +38 -0
- data/lib/imitator/x/drive.rb +179 -0
- data/lib/imitator/x.rb +29 -0
- data/lib/imitator_x_special_chars.yml +179 -0
- data/test/test_clipboard.rb +46 -0
- data/test/test_keyboard.rb +117 -0
- data/test/test_mouse.rb +40 -0
- data/test/test_xdrive.rb +47 -0
- data/test/test_xwindow.rb +106 -0
- metadata +123 -0
data/ext/keyboard.h
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
/*********************************************************************************
|
2
|
+
Imitator for X is a library allowing you to fake input to systems using X11.
|
3
|
+
Copyright � 2010 Marvin G�lker
|
4
|
+
|
5
|
+
This file is part of Imitator for X.
|
6
|
+
|
7
|
+
Imitator for X is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the GNU Lesser General Public License as published by
|
9
|
+
the Free Software Foundation, either version 3 of the License, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
Imitator for X is distributed in the hope that it will be useful,
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
GNU Lesser General Public License for more details.
|
16
|
+
|
17
|
+
You should have received a copy of the GNU Lesser General Public License
|
18
|
+
along with Imitator for X. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
*********************************************************************************/
|
20
|
+
#ifndef IMITATOR_KEYBOARD_HEADER
|
21
|
+
#define IMITATOR_KEYBOARD_HEADER
|
22
|
+
|
23
|
+
#define RUBY_UTF8_STR(str) rb_enc_str_new(str, strlen(str), rb_utf8_encoding())
|
24
|
+
|
25
|
+
VALUE Keyboard;
|
26
|
+
|
27
|
+
void Init_keyboard(void);
|
28
|
+
|
29
|
+
#endif
|
data/ext/mouse.c
ADDED
@@ -0,0 +1,456 @@
|
|
1
|
+
/*********************************************************************************
|
2
|
+
Imitator for X is a library allowing you to fake input to systems using X11.
|
3
|
+
Copyright � 2010 Marvin G�lker
|
4
|
+
|
5
|
+
This file is part of Imitator for X.
|
6
|
+
|
7
|
+
Imitator for X is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the GNU Lesser General Public License as published by
|
9
|
+
the Free Software Foundation, either version 3 of the License, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
Imitator for X is distributed in the hope that it will be useful,
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
GNU Lesser General Public License for more details.
|
16
|
+
|
17
|
+
You should have received a copy of the GNU Lesser General Public License
|
18
|
+
along with Imitator for X. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
*********************************************************************************/
|
20
|
+
#include "x.h"
|
21
|
+
#include "mouse.h"
|
22
|
+
|
23
|
+
/*
|
24
|
+
*Document-module: Imitator::X::Mouse
|
25
|
+
*This module allows you to interact with the mouse pointer. You can do funny things
|
26
|
+
*with this, but make sure, it's *useful* for your users.
|
27
|
+
*
|
28
|
+
*Every method besides Mouse.move that claims to move the cursor to a specified
|
29
|
+
*position uses Mouse.move internally; so make sure you've read Mouse.move's documentation.
|
30
|
+
*/
|
31
|
+
|
32
|
+
/*
|
33
|
+
*Retrieves the current mouse cursor position.
|
34
|
+
*===Return value
|
35
|
+
*The cursor position as a 2-element array of form <tt>[x, y]</tt>.
|
36
|
+
*===Example
|
37
|
+
* p Imitator::X::Mouse.position #=> [464, 620]
|
38
|
+
*/
|
39
|
+
static VALUE m_pos(VALUE self)
|
40
|
+
{
|
41
|
+
Display * p_display;
|
42
|
+
Window root, child_win;
|
43
|
+
int rx, ry, wx, wy;
|
44
|
+
unsigned int mask;
|
45
|
+
VALUE pos = rb_ary_new();
|
46
|
+
|
47
|
+
p_display = XOpenDisplay(NULL);
|
48
|
+
XSetErrorHandler(handle_x_errors);
|
49
|
+
|
50
|
+
root = XDefaultRootWindow(p_display);
|
51
|
+
if (XQueryPointer(p_display, root, &root, &child_win, &rx, &ry, &wx, &wy, &mask) == False)
|
52
|
+
rb_raise(XError, "Could not query the pointer's position!");
|
53
|
+
rb_ary_push(pos, INT2NUM(rx));
|
54
|
+
rb_ary_push(pos, INT2NUM(ry));
|
55
|
+
|
56
|
+
XSetErrorHandler(NULL);
|
57
|
+
XCloseDisplay(p_display);
|
58
|
+
|
59
|
+
return pos;
|
60
|
+
}
|
61
|
+
|
62
|
+
/*
|
63
|
+
*call-seq:
|
64
|
+
* Mouse.move(x, y [, step = 1 [, set = false ] ] ) ==> anArray
|
65
|
+
*
|
66
|
+
*Moves the mouse cursor to the specified position.
|
67
|
+
*===Parameters
|
68
|
+
*[+x+] The goal X coordinate.
|
69
|
+
*[+y+] The goal Y coordinate.
|
70
|
+
*[+step+] (1) This specifies the move amount per computation. Higher values make the movement faster, but more inaccurate. Anyway, the cursor will be exactly at your specified position.
|
71
|
+
*[+set+] (+false+) If this is +true+, the cursor isn't moved to the goal position, but directly set to it. Ignores +step+ if set to +true+.
|
72
|
+
*===Return value
|
73
|
+
*The new position.
|
74
|
+
*===Raises
|
75
|
+
*[ArgumentError] Besides the normal meanings of this error, it may also indicate that the +step+ parameter has to be greater than 0.
|
76
|
+
*===Example
|
77
|
+
* #Move to (100|100)
|
78
|
+
* Imitator::X::Mouse.move(100, 100) #| [100, 100]
|
79
|
+
* #Move to (0|0), only executing every 3rd movement;
|
80
|
+
* #Altough this would never trigger the origin, the cursor
|
81
|
+
* #will be there.
|
82
|
+
* Imitator::X::Mouse.move(0, 0, 3) #| [0, 0]
|
83
|
+
* #Don't move, directly set the cursor. The step parameter (1 here) is ignored.
|
84
|
+
* Imitator::X::Mouse.move(100, 100, 1, true) #| [100, 100]
|
85
|
+
* #If you move off the screen, the cursor will stop at the edge.
|
86
|
+
* Imitator::X::Mouse.move(-100, 100) #| [0, 100]
|
87
|
+
*===Remarks
|
88
|
+
*If you specify a +step+ parameter that is greater than the difference of the actual cursor position to
|
89
|
+
*the goal position, you'll get an infinite loop here, so be careful. If you're in doubt on how high
|
90
|
+
*you should set +step+, just stick to the directly setting variant.
|
91
|
+
*/
|
92
|
+
static VALUE m_move(int argc, VALUE argv[], VALUE self)
|
93
|
+
{
|
94
|
+
VALUE rx, ry, rstep, rset, temp;
|
95
|
+
VALUE args[4];
|
96
|
+
Display * p_display;
|
97
|
+
int goal_x, goal_y, step, ix, iy, dir;
|
98
|
+
|
99
|
+
rb_scan_args(argc, argv, "22", &rx, &ry, &rstep, &rset);
|
100
|
+
|
101
|
+
if (NIL_P(rstep))
|
102
|
+
step = 1;
|
103
|
+
else
|
104
|
+
step = NUM2INT(rstep);
|
105
|
+
goal_x = NUM2INT(rx);
|
106
|
+
goal_y = NUM2INT(ry);
|
107
|
+
|
108
|
+
p_display = XOpenDisplay(NULL);
|
109
|
+
XSetErrorHandler(handle_x_errors);
|
110
|
+
|
111
|
+
/*Ignore the rest of the function if we only want to set the cursor*/
|
112
|
+
if (RTEST(rset))
|
113
|
+
{
|
114
|
+
XTestFakeMotionEvent(p_display, 0, goal_x, goal_y, CurrentTime);
|
115
|
+
XSetErrorHandler(NULL);
|
116
|
+
XCloseDisplay(p_display);
|
117
|
+
return m_pos(self);
|
118
|
+
}
|
119
|
+
|
120
|
+
temp = m_pos(self); /*Get actual position, since we don't want to move off (0|0).*/
|
121
|
+
ix = NUM2INT(rb_ary_entry(temp, 0));
|
122
|
+
iy = NUM2INT(rb_ary_entry(temp, 1));
|
123
|
+
|
124
|
+
if (step <= 0)
|
125
|
+
rb_raise(rb_eArgError, "The step parameter has to be greater than 0!");
|
126
|
+
|
127
|
+
/*Get the move direction, which indicates wheather we will increment or decrement the X and Y coordinates. */
|
128
|
+
if (ix < goal_x)
|
129
|
+
{
|
130
|
+
if (iy < goal_y)
|
131
|
+
dir = 0; /*Right-down*/
|
132
|
+
else
|
133
|
+
dir = 1; /*Right-up*/
|
134
|
+
}
|
135
|
+
else
|
136
|
+
{
|
137
|
+
if (iy < goal_y)
|
138
|
+
dir = 2; /*Left-down*/
|
139
|
+
else
|
140
|
+
dir = 3; /*Left-up*/
|
141
|
+
}
|
142
|
+
|
143
|
+
/*Perform the Y movement*/
|
144
|
+
while ((iy < goal_y - step) || (iy > goal_y + step)) /*Got as near as possible to the goal Y*/
|
145
|
+
{
|
146
|
+
args[0] = INT2NUM(ix);
|
147
|
+
args[1] = INT2NUM(iy);
|
148
|
+
args[2] = rstep;
|
149
|
+
args[3] = Qtrue;
|
150
|
+
m_move(4, args, self); /*Needed, since even a sleep() call here doesn't cause X to update the cursor position when trying to use XTestFakeMotionEvent here*/
|
151
|
+
if (dir == 0 || dir == 2)
|
152
|
+
iy += step;
|
153
|
+
else
|
154
|
+
iy -= step;
|
155
|
+
}
|
156
|
+
/*Perform the X movement*/
|
157
|
+
while ((ix < goal_x - step) || (ix > goal_x + step)) /*Got as near as possible to the goal X*/
|
158
|
+
{
|
159
|
+
args[0] = INT2NUM(ix);
|
160
|
+
args[1] = INT2NUM(iy);
|
161
|
+
args[2] = rstep;
|
162
|
+
args[3] = Qtrue;
|
163
|
+
m_move(4, args, self); /*Needed, since even a sleep() call here doesn't cause X to update the cursor position when trying to use XTestFakeMotionEvent here*/
|
164
|
+
if (dir == 0 || dir == 1)
|
165
|
+
ix += step;
|
166
|
+
else
|
167
|
+
ix -= step;
|
168
|
+
}
|
169
|
+
|
170
|
+
/*Ensure that the cursor is really at the correct position*/
|
171
|
+
XTestFakeMotionEvent(p_display, 0, goal_x, goal_y, CurrentTime);
|
172
|
+
|
173
|
+
XSetErrorHandler(NULL);
|
174
|
+
XCloseDisplay(p_display);
|
175
|
+
return m_pos(self);
|
176
|
+
}
|
177
|
+
|
178
|
+
/*
|
179
|
+
*call-seq:
|
180
|
+
* Mouse.click(hsh = {:button => :left}) ==> anArray
|
181
|
+
*
|
182
|
+
*Executes a mouse click at the current or a given position.
|
183
|
+
*===Parameters
|
184
|
+
*This method takes a hash as it's only argument. You may pass the following keys and values:
|
185
|
+
*[:x] (Current X) The X coordinate where you want to click.
|
186
|
+
*[:y] (Current Y) The Y coordinate where you want to click.
|
187
|
+
*[:button] (:left) The mouse button you want to click with. One of :left, :right and :middle.
|
188
|
+
*[:step] (1) +step+ parameter for Mouse.move.
|
189
|
+
*[:set] (false) +set+ parameter for Mouse.move.
|
190
|
+
*===Return value
|
191
|
+
*The position where the click was executed.
|
192
|
+
*===Example
|
193
|
+
* #Click at current position
|
194
|
+
* Imitator::X::Mouse.click #| [376, 509]
|
195
|
+
* #Click at (100|100)
|
196
|
+
* Imitator::X::Mouse.click(:x => 100, :y => 100) #| [100, 100]
|
197
|
+
* #Click at current position with right mouse button
|
198
|
+
* Imitator::X::Mouse.click(:button => :right)
|
199
|
+
*/
|
200
|
+
static VALUE m_click(int argc, VALUE argv[], VALUE self)
|
201
|
+
{
|
202
|
+
VALUE hsh, rbutton, rbutton2;
|
203
|
+
VALUE args[4];
|
204
|
+
int button;
|
205
|
+
Display * p_display;
|
206
|
+
|
207
|
+
rb_scan_args(argc, argv, "01", &hsh);
|
208
|
+
|
209
|
+
if (NIL_P(hsh))
|
210
|
+
hsh = rb_hash_new();
|
211
|
+
|
212
|
+
rbutton = rb_hash_lookup(hsh, ID2SYM(rb_intern("button")));
|
213
|
+
|
214
|
+
if (NIL_P(rbutton))
|
215
|
+
rbutton = ID2SYM(rb_intern("left")); /*No button specified, defaulting to left*/
|
216
|
+
rbutton2 = rb_hash_lookup(rb_const_get(Mouse, rb_intern("BUTTONS")), rbutton);
|
217
|
+
if (NIL_P(rbutton2))
|
218
|
+
rb_raise(rb_eArgError, "Invalid button specified!");
|
219
|
+
button = FIX2INT(rbutton2);
|
220
|
+
|
221
|
+
p_display = XOpenDisplay(NULL);
|
222
|
+
XSetErrorHandler(handle_x_errors);
|
223
|
+
|
224
|
+
/*Move the cursor if wanted before clicking*/
|
225
|
+
args[0] = rb_hash_lookup(hsh, ID2SYM(rb_intern("x")));
|
226
|
+
args[1] = rb_hash_lookup(hsh, ID2SYM(rb_intern("y")));
|
227
|
+
args[2] = rb_hash_lookup(hsh, ID2SYM(rb_intern("step")));
|
228
|
+
args[3] = rb_hash_lookup(hsh, ID2SYM(rb_intern("set")));
|
229
|
+
if (!NIL_P(args[0]) && !NIL_P(args[1]))
|
230
|
+
m_move(4, args, self);
|
231
|
+
|
232
|
+
XTestFakeButtonEvent(p_display, (unsigned int)button, True, CurrentTime);
|
233
|
+
XTestFakeButtonEvent(p_display, (unsigned int)button, False, CurrentTime);
|
234
|
+
|
235
|
+
XSetErrorHandler(NULL);
|
236
|
+
XCloseDisplay(p_display);
|
237
|
+
return m_pos(self);
|
238
|
+
}
|
239
|
+
|
240
|
+
/*
|
241
|
+
*call-seq:
|
242
|
+
* Mouse.down( [ button = :left ] ) ==> nil
|
243
|
+
*
|
244
|
+
*Holds the given mouse button down. Don't forget to release it sometime.
|
245
|
+
*===Parameters
|
246
|
+
*[+button+] (:left) The button to hold down.
|
247
|
+
*===Return value
|
248
|
+
*nil.
|
249
|
+
*===Example
|
250
|
+
* Imitator::X::Mouse.down
|
251
|
+
* Imitator::X::Mouse.up #Never forget to...
|
252
|
+
* Imitator::X::Mouse.down(:right)
|
253
|
+
* Imitator::X::Mouse.up(:right) #...Release a pressed button.
|
254
|
+
*/
|
255
|
+
static VALUE m_down(int argc, VALUE argv[], VALUE self)
|
256
|
+
{
|
257
|
+
VALUE rbutton;
|
258
|
+
int button;
|
259
|
+
Display * p_display;
|
260
|
+
|
261
|
+
rb_scan_args(argc, argv, "01", &rbutton);
|
262
|
+
if (NIL_P(rbutton))
|
263
|
+
rbutton = ID2SYM(rb_intern("left"));
|
264
|
+
rbutton = rb_hash_lookup(rb_const_get(Mouse, rb_intern("BUTTONS")), rbutton);
|
265
|
+
if (NIL_P(rbutton))
|
266
|
+
rb_raise(rb_eArgError, "Invalid button specified!");
|
267
|
+
button = FIX2INT(rbutton);
|
268
|
+
|
269
|
+
p_display = XOpenDisplay(NULL);
|
270
|
+
XSetErrorHandler(handle_x_errors);
|
271
|
+
|
272
|
+
XTestFakeButtonEvent(p_display, (unsigned int)button, True, CurrentTime);
|
273
|
+
|
274
|
+
XSetErrorHandler(NULL);
|
275
|
+
XCloseDisplay(p_display);
|
276
|
+
return Qnil;
|
277
|
+
}
|
278
|
+
|
279
|
+
/*
|
280
|
+
*call-seq:
|
281
|
+
* Mouse.up( [ button = :left ] ) ==> nil
|
282
|
+
*
|
283
|
+
*Releases the given mouse button. This doesn't have any effect if
|
284
|
+
*you didn't call Mouse.down before.
|
285
|
+
*===Parameters
|
286
|
+
*[+button+] (:left) The button to release.
|
287
|
+
*===Return value
|
288
|
+
*nil.
|
289
|
+
*===Example
|
290
|
+
* Imitator::X::Mouse.down
|
291
|
+
* Imitator::X::Mouse.up
|
292
|
+
* Imitator::X::Mouse.down(:right)
|
293
|
+
* Imitator::X::Mouse.up(:right)
|
294
|
+
*/
|
295
|
+
static VALUE m_up(int argc, VALUE argv[], VALUE self)
|
296
|
+
{
|
297
|
+
VALUE rbutton;
|
298
|
+
int button;
|
299
|
+
Display * p_display;
|
300
|
+
|
301
|
+
rb_scan_args(argc, argv, "01", &rbutton);
|
302
|
+
if (NIL_P(rbutton))
|
303
|
+
rbutton = ID2SYM(rb_intern("left"));
|
304
|
+
rbutton = rb_hash_lookup(rb_const_get(Mouse, rb_intern("BUTTONS")), rbutton);
|
305
|
+
if (NIL_P(rbutton))
|
306
|
+
rb_raise(rb_eArgError, "Invalid button specified!");
|
307
|
+
button = FIX2INT(rbutton);
|
308
|
+
|
309
|
+
p_display = XOpenDisplay(NULL);
|
310
|
+
XSetErrorHandler(handle_x_errors);
|
311
|
+
|
312
|
+
XTestFakeButtonEvent(p_display, (unsigned int)button, False, CurrentTime);
|
313
|
+
|
314
|
+
XSetErrorHandler(NULL);
|
315
|
+
XCloseDisplay(p_display);
|
316
|
+
return Qnil;
|
317
|
+
}
|
318
|
+
|
319
|
+
/*
|
320
|
+
*call-seq:
|
321
|
+
* Mouse.drag(hsh) ==> anArray
|
322
|
+
*
|
323
|
+
*Executes a drag&drop operation.
|
324
|
+
*===Parameters
|
325
|
+
*This method takes a hash as it's only parameter. You may pass in one of the following keys:
|
326
|
+
*[+x1+] (Current X) Start X coordinate.
|
327
|
+
*[+y1+] (Current Y) Start Y coordinate.
|
328
|
+
*[+x2+] (*Required*) Goal X coordinate.
|
329
|
+
*[+y2+] (*Required*) Goal Y coordinate.
|
330
|
+
*[+button+] (<tt>:left</tt>) The button to hold down during the movement.
|
331
|
+
*[+step+] +step+ parameter to Mouse.move.
|
332
|
+
*[+set+] +set+ parameter to Mouse.move. Use not recommanded here.
|
333
|
+
*===Return value
|
334
|
+
*Returns the new cursor position as a two-element array of form <tt>[x, y]</tt>.
|
335
|
+
*===Example
|
336
|
+
* #From current to (200|200)
|
337
|
+
* Imitator::X::Mouse.drag(:x2 => 200, :y2 => 200)
|
338
|
+
* #From current to (200|200), dragging with the right mouse button
|
339
|
+
* Imitator::X::Mouse.drag(:x2 => 200, :y2 => 200, :button => :right)
|
340
|
+
* #From (300|300) to (200|200)
|
341
|
+
* Imitator::X::Mouse.drag(:x1 => 300, :y1 => 300, :x2 => 200, :y2 => 200)
|
342
|
+
* #From (CURRENT X|300) to (200|200)
|
343
|
+
* Imitator::X::Mouse.drag(:y1 => 300, :x2 => 200, :y2 => 200)
|
344
|
+
*/
|
345
|
+
static VALUE m_drag(VALUE self, VALUE hsh)
|
346
|
+
{
|
347
|
+
VALUE rx1, ry1, rx2, ry2, rbutton, rstep, rset, temp;
|
348
|
+
VALUE args[4];
|
349
|
+
|
350
|
+
rx1 = rb_hash_lookup(hsh, ID2SYM(rb_intern("x1")));
|
351
|
+
ry1 = rb_hash_lookup(hsh, ID2SYM(rb_intern("y1")));
|
352
|
+
rx2 = rb_hash_lookup(hsh, ID2SYM(rb_intern("x2")));
|
353
|
+
ry2 = rb_hash_lookup(hsh, ID2SYM(rb_intern("y2")));
|
354
|
+
rbutton = rb_hash_lookup(hsh, ID2SYM(rb_intern("button")));
|
355
|
+
rstep = rb_hash_lookup(hsh, ID2SYM(rb_intern("step")));
|
356
|
+
rset = rb_hash_lookup(hsh, ID2SYM(rb_intern("set")));
|
357
|
+
|
358
|
+
temp = m_pos(self);
|
359
|
+
if (NIL_P(rx1))
|
360
|
+
rx1 = rb_ary_entry(temp, 0);
|
361
|
+
if (NIL_P(ry1))
|
362
|
+
ry1 = rb_ary_entry(temp, 1);
|
363
|
+
if (NIL_P(rx2))
|
364
|
+
rb_raise(rb_eArgError, "No goal X coordinate specified!");
|
365
|
+
if (NIL_P(ry2))
|
366
|
+
rb_raise(rb_eArgError, "No goal Y coordinate specified!");
|
367
|
+
if (NIL_P(rbutton))
|
368
|
+
rbutton = ID2SYM(rb_intern("left"));
|
369
|
+
/*If rstep or rset is ommited, it's nil, and this is OK*/
|
370
|
+
|
371
|
+
args[0] = rx1;
|
372
|
+
args[1] = ry1;
|
373
|
+
args[2] = rstep;
|
374
|
+
args[3] = rset;
|
375
|
+
m_move(4, args, self);
|
376
|
+
args[0] = rbutton;
|
377
|
+
args[1] = 0;
|
378
|
+
args[2] = 0;
|
379
|
+
args[3] = 0;
|
380
|
+
m_down(1, args, self);
|
381
|
+
args[0] = rx2;
|
382
|
+
args[1] = ry2;
|
383
|
+
args[2] = rstep;
|
384
|
+
args[3] = rset;
|
385
|
+
m_move(4, args, self);
|
386
|
+
args[0] = rbutton;
|
387
|
+
args[1] = 0;
|
388
|
+
args[2] = 0;
|
389
|
+
args[3] = 0;
|
390
|
+
m_up(1, args, self);
|
391
|
+
|
392
|
+
return m_pos(self);
|
393
|
+
}
|
394
|
+
|
395
|
+
/*
|
396
|
+
*call-seq:
|
397
|
+
* Mouse.wheel(direction [, amount = 1 ] ) ==> nil
|
398
|
+
*
|
399
|
+
*Rolls the mouse wheel.
|
400
|
+
*===Parameters
|
401
|
+
*[+direction+] The direction in which to roll the mouse wheel, either <tt>:up</tt> or <tt>:down</tt>.
|
402
|
+
*[+amount+] (1) The amount of roll steps. This <b>does not</b> mean full turns!
|
403
|
+
*===Return value
|
404
|
+
*nil.
|
405
|
+
*===Example
|
406
|
+
* #1 roll step up.
|
407
|
+
* Imitator::X::Mouse.wheel(:up)
|
408
|
+
* #2 roll steps down.
|
409
|
+
* Imitator::X::Mouse.wheel(:down, 2)
|
410
|
+
*/
|
411
|
+
static VALUE m_wheel(int argc, VALUE argv[], VALUE self)
|
412
|
+
{
|
413
|
+
VALUE rdir, ramount;
|
414
|
+
VALUE args[1];
|
415
|
+
int amount, i;
|
416
|
+
|
417
|
+
rb_scan_args(argc, argv, "11", &rdir, &ramount);
|
418
|
+
if (NIL_P(ramount))
|
419
|
+
ramount = INT2FIX(1);
|
420
|
+
if ( (SYM2ID(rdir) != rb_intern("up")) && (SYM2ID(rdir) != rb_intern("down")) )
|
421
|
+
rb_raise(rb_eArgError, "Invalid wheel direction specified!");
|
422
|
+
amount = NUM2INT(ramount);
|
423
|
+
|
424
|
+
args[0] = rb_hash_new();
|
425
|
+
rb_hash_aset(args[0], ID2SYM(rb_intern("button")), rdir);
|
426
|
+
|
427
|
+
for(i = 0; i < amount; i++)
|
428
|
+
m_click(1, args, self);
|
429
|
+
|
430
|
+
return Qnil;
|
431
|
+
}
|
432
|
+
|
433
|
+
/******************************Init-Function*********************************/
|
434
|
+
|
435
|
+
void Init_mouse(void)
|
436
|
+
{
|
437
|
+
VALUE hsh;
|
438
|
+
Mouse = rb_define_module_under(X, "Mouse");
|
439
|
+
hsh = rb_hash_new();
|
440
|
+
rb_hash_aset(hsh, ID2SYM(rb_intern("left")), INT2FIX(1));
|
441
|
+
rb_hash_aset(hsh, ID2SYM(rb_intern("middle")), INT2FIX(2));
|
442
|
+
rb_hash_aset(hsh, ID2SYM(rb_intern("right")), INT2FIX(3));
|
443
|
+
rb_hash_aset(hsh, ID2SYM(rb_intern("up")), INT2FIX(4)); /*Yeah, the two wheel directions... */
|
444
|
+
rb_hash_aset(hsh, ID2SYM(rb_intern("down")), INT2FIX(5)); /*...are handled as buttons by X. */
|
445
|
+
/*A hash mapping button names to internal numbers. */
|
446
|
+
rb_define_const(Mouse, "BUTTONS", hsh);
|
447
|
+
|
448
|
+
rb_define_module_function(Mouse, "position", m_pos, 0);
|
449
|
+
rb_define_module_function(Mouse, "pos", m_pos, 0);
|
450
|
+
rb_define_module_function(Mouse, "move", m_move, -1);
|
451
|
+
rb_define_module_function(Mouse, "click", m_click, -1);
|
452
|
+
rb_define_module_function(Mouse, "down", m_down, -1);
|
453
|
+
rb_define_module_function(Mouse, "up", m_up, -1);
|
454
|
+
rb_define_module_function(Mouse, "drag", m_drag, 1);
|
455
|
+
rb_define_module_function(Mouse, "wheel", m_wheel, -1);
|
456
|
+
}
|
data/ext/mouse.h
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
/*********************************************************************************
|
2
|
+
Imitator for X is a library allowing you to fake input to systems using X11.
|
3
|
+
Copyright � 2010 Marvin G�lker
|
4
|
+
|
5
|
+
This file is part of Imitator for X.
|
6
|
+
|
7
|
+
Imitator for X is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the GNU Lesser General Public License as published by
|
9
|
+
the Free Software Foundation, either version 3 of the License, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
Imitator for X is distributed in the hope that it will be useful,
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
GNU Lesser General Public License for more details.
|
16
|
+
|
17
|
+
You should have received a copy of the GNU Lesser General Public License
|
18
|
+
along with Imitator for X. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
*********************************************************************************/
|
20
|
+
#ifndef IMITATOR_XMOUSE_HEADER
|
21
|
+
#define IMITATOR_XMOUSE_HEADER
|
22
|
+
|
23
|
+
/*Imitator::X::Mouse*/
|
24
|
+
VALUE Mouse;
|
25
|
+
/*Mouse initialization function*/
|
26
|
+
void Init_mouse(void);
|
27
|
+
|
28
|
+
#endif
|
data/ext/x.c
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
/*********************************************************************************
|
2
|
+
Imitator for X is a library allowing you to fake input to systems using X11.
|
3
|
+
Copyright � 2010 Marvin G�lker
|
4
|
+
|
5
|
+
This file is part of Imitator for X.
|
6
|
+
|
7
|
+
Imitator for X is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the GNU Lesser General Public License as published by
|
9
|
+
the Free Software Foundation, either version 3 of the License, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
Imitator for X is distributed in the hope that it will be useful,
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
GNU Lesser General Public License for more details.
|
16
|
+
|
17
|
+
You should have received a copy of the GNU Lesser General Public License
|
18
|
+
along with Imitator for X. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
*********************************************************************************/
|
20
|
+
#include "x.h"
|
21
|
+
#include "xwindow.h"
|
22
|
+
#include "mouse.h"
|
23
|
+
#include "keyboard.h"
|
24
|
+
#include "clipboard.h"
|
25
|
+
|
26
|
+
VALUE Imitator;
|
27
|
+
VALUE X;
|
28
|
+
VALUE ProtocolError;
|
29
|
+
VALUE XError;
|
30
|
+
|
31
|
+
/*
|
32
|
+
*Document-module: Imitator
|
33
|
+
*Toplevel namespace of the Imitator libraries.
|
34
|
+
*/
|
35
|
+
|
36
|
+
/*
|
37
|
+
*Document-module: Imitator::X
|
38
|
+
*The namespace of this library.
|
39
|
+
*/
|
40
|
+
|
41
|
+
/*
|
42
|
+
*Document-class: Imitator::X::XProtocolError
|
43
|
+
*A Protocol Error as thrown by X. This class uses X's error messages.
|
44
|
+
*/
|
45
|
+
|
46
|
+
/*
|
47
|
+
*Document-class: Imitator::X::XError
|
48
|
+
*Miscellaneous error messages caused by unexpected behaviour of X.
|
49
|
+
*/
|
50
|
+
|
51
|
+
/***********************Helper functions***************************/
|
52
|
+
/*
|
53
|
+
*This function handles X server protocol errors. That allows us to throw Ruby
|
54
|
+
*exceptions instead of having X terminate the program and print it's
|
55
|
+
*own error message.
|
56
|
+
*/
|
57
|
+
int handle_x_errors(Display *p_display, XErrorEvent *x_errevt)
|
58
|
+
{
|
59
|
+
char msg[1000];
|
60
|
+
|
61
|
+
XGetErrorText(p_display, x_errevt->error_code, msg, 1000);
|
62
|
+
XCloseDisplay(p_display); /*Ensure the X Server connection is closed*/
|
63
|
+
rb_raise(ProtocolError, msg); /*This is OK, I get the error message from X*/
|
64
|
+
return 1;
|
65
|
+
}
|
66
|
+
|
67
|
+
/************************Init-Function****************************/
|
68
|
+
|
69
|
+
void Init_x(void)
|
70
|
+
{
|
71
|
+
Imitator = rb_define_module("Imitator");
|
72
|
+
X = rb_define_module_under(Imitator, "X");
|
73
|
+
ProtocolError = rb_define_class_under(X, "XProtocolError", rb_eStandardError);
|
74
|
+
XError = rb_define_class_under(X, "XError", rb_eStandardError);
|
75
|
+
|
76
|
+
/*The version of this library. */
|
77
|
+
rb_define_const(X, "VERSION", rb_str_new2("0.0.1"));
|
78
|
+
|
79
|
+
/*Load the parts of Imitator for X*/
|
80
|
+
Init_xwindow();
|
81
|
+
Init_mouse();
|
82
|
+
Init_keyboard();
|
83
|
+
Init_clipboard();
|
84
|
+
}
|
data/ext/x.h
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
/*********************************************************************************
|
2
|
+
Imitator for X is a library allowing you to fake input to systems using X11.
|
3
|
+
Copyright � 2010 Marvin G�lker
|
4
|
+
|
5
|
+
This file is part of Imitator for X.
|
6
|
+
|
7
|
+
Imitator for X is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the GNU Lesser General Public License as published by
|
9
|
+
the Free Software Foundation, either version 3 of the License, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
Imitator for X is distributed in the hope that it will be useful,
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
GNU Lesser General Public License for more details.
|
16
|
+
|
17
|
+
You should have received a copy of the GNU Lesser General Public License
|
18
|
+
along with Imitator for X. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
*********************************************************************************/
|
20
|
+
#include <stdio.h>
|
21
|
+
#include <stdlib.h>
|
22
|
+
#include <string.h>
|
23
|
+
#include <unistd.h>
|
24
|
+
#include <signal.h>
|
25
|
+
#include <X11/Xlib.h>
|
26
|
+
#include <X11/Xutil.h>
|
27
|
+
#include <X11/Xatom.h>
|
28
|
+
#include <X11/extensions/XTest.h>
|
29
|
+
#include "ruby.h"
|
30
|
+
#include "ruby/encoding.h"
|
31
|
+
|
32
|
+
#ifndef IMITATOR_X_HEADER
|
33
|
+
#define IMITATOR_X_HEADER
|
34
|
+
|
35
|
+
/*Maps XProtocolErrors to Ruby errors*/
|
36
|
+
int handle_x_errors(Display *p_display, XErrorEvent *x_errevt);
|
37
|
+
/*Main initialization function*/
|
38
|
+
void Init_x(void);
|
39
|
+
/*Imitator module*/
|
40
|
+
VALUE Imitator;
|
41
|
+
/*Imitator::X*/
|
42
|
+
VALUE X;
|
43
|
+
/*Imitator::X::XProtocolError*/
|
44
|
+
VALUE ProtocolError;
|
45
|
+
/*Imitator::X::XError*/
|
46
|
+
VALUE XError;
|
47
|
+
|
48
|
+
#endif
|