mouse 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.markdown +6 -0
- data/README.markdown +50 -1
- data/Rakefile +6 -5
- data/ext/mouse/mouse.c +250 -49
- data/ext/mouse/mouser.c +15 -14
- data/ext/mouse/mouser.h +2 -9
- data/lib/mouse/version.rb +1 -1
- data/lib/mouse.rb +13 -2
- data/test/helper.rb +1 -0
- metadata +2 -8
data/History.markdown
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
# 1.0.0 - Port Completed
|
2
|
+
|
3
|
+
* Added optional `point` argument to all `Mouse` click methods
|
4
|
+
* Added duration argument to all `Mouse` methods that are animated
|
5
|
+
* Fix differences between MRI CGPoint and MacRuby CGPoint
|
6
|
+
|
1
7
|
# 0.1.0 - The basic API
|
2
8
|
|
3
9
|
* Fixed animation timing (sleep(3) type coercion issue)
|
data/README.markdown
CHANGED
@@ -4,9 +4,58 @@ A port of mouse.rb from [AXElements](http://github.com/Marketcircle/AXElements),
|
|
4
4
|
but cleaned up and rewritten in C to be more portable across languages and
|
5
5
|
runtimes.
|
6
6
|
|
7
|
+
By itself, the `mouse` gem is not that useful; but in combination
|
8
|
+
with a gem for discovering the positions of things (like buttons) on
|
9
|
+
the screen, this gem is very powerful and can be used for tasks such
|
10
|
+
as automated functional
|
11
|
+
testing; this is the purpose of the
|
12
|
+
[AXElements](http://github.com/Marketcircle/AXElements) project.
|
13
|
+
|
14
|
+
[Documentation](http://rdoc.info/gems/mouse/frames)
|
15
|
+
|
16
|
+
|
7
17
|
## Examples
|
8
18
|
|
9
|
-
|
19
|
+
require 'mouse'
|
20
|
+
|
21
|
+
Mouse.current_position # => #<CGPoint x=873.2 y=345.0>
|
22
|
+
|
23
|
+
# positions can be given as a an array with two points, or a CGPoint
|
24
|
+
Mouse.move_to [10, 10]
|
25
|
+
Mouse.move_to CGPoint.new(10, 10)
|
26
|
+
|
27
|
+
# optionally specify how long it should take the mouse to move
|
28
|
+
Mouse.move_to [800, 300], 0.2
|
29
|
+
|
30
|
+
Mouse.click
|
31
|
+
Mouse.double_click
|
32
|
+
Mouse.triple_click
|
33
|
+
|
34
|
+
# secondary_click and right_click are aliases to the same method
|
35
|
+
Mouse.secondary_click
|
36
|
+
Mouse.right_click
|
37
|
+
|
38
|
+
# positive number scrolls up, negative number scrolls down
|
39
|
+
Mouse.scroll 10
|
40
|
+
Mouse.scroll -10
|
41
|
+
|
42
|
+
# optionally specify units for scroll amount, :pixel or :line
|
43
|
+
Mouse.scroll 10, :pixels
|
44
|
+
Mouse.scroll -10, :pixels
|
45
|
+
|
46
|
+
See the [Mouse Documentation](http://rdoc.info/gems/mouse/Mouse) for
|
47
|
+
more details.
|
48
|
+
|
49
|
+
You may have noticed that when you ask the mouse to move to a specific
|
50
|
+
location that it may not end up at the exact co-ordinates, but it will
|
51
|
+
be close (distance of less than 1). This is by design, but that may
|
52
|
+
change in the future if there are enough complaints.
|
53
|
+
|
54
|
+
|
55
|
+
## TODO
|
56
|
+
|
57
|
+
* Support for mouse gestures
|
58
|
+
* Make animation duration accurate (currently naiveté has a bit of error)
|
10
59
|
|
11
60
|
## Copyright
|
12
61
|
|
data/Rakefile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
task :default => :
|
1
|
+
task :default => :test
|
2
2
|
|
3
3
|
require 'rake/clean'
|
4
4
|
CLEAN.include '*.plist', '*.gch'
|
@@ -13,11 +13,12 @@ task :console => [:compile] do
|
|
13
13
|
sh 'irb -Ilib -rmouse'
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
require 'rake/testtask'
|
17
|
+
Rake::TestTask.new do |t|
|
18
|
+
t.libs << '.'
|
19
|
+
t.pattern = 'test/*_test.rb'
|
20
20
|
end
|
21
|
+
task :test => :compile
|
21
22
|
|
22
23
|
|
23
24
|
# Gem stuff
|
data/ext/mouse/mouse.c
CHANGED
@@ -8,6 +8,7 @@ static ID sel_y;
|
|
8
8
|
static ID sel_to_point;
|
9
9
|
static ID sel_to_i;
|
10
10
|
static ID sel_new;
|
11
|
+
static ID unit_pixel;
|
11
12
|
|
12
13
|
#define CURRENT_POSITION rb_mouse_wrap_point(mouse_current_position())
|
13
14
|
|
@@ -57,109 +58,219 @@ rb_mouse_current_position(VALUE self)
|
|
57
58
|
* Move the mouse cursor to the given co-ordinates
|
58
59
|
*
|
59
60
|
* @param point [CGPoint,Array(Number,Number),#to_point]
|
61
|
+
* @param duration [Number] animation time, in seconds (__optional__)
|
60
62
|
* @return [CGPoint]
|
61
63
|
*/
|
62
64
|
static
|
63
65
|
VALUE
|
64
|
-
rb_mouse_move_to(VALUE
|
66
|
+
rb_mouse_move_to(int argc, VALUE *argv, VALUE self)
|
65
67
|
{
|
66
|
-
|
68
|
+
switch (argc)
|
69
|
+
{
|
70
|
+
case 0:
|
71
|
+
rb_raise(rb_eArgError, "move_to requires at least a one arg");
|
72
|
+
break;
|
73
|
+
case 1:
|
74
|
+
mouse_move_to(rb_mouse_unwrap_point(argv[0]));
|
75
|
+
break;
|
76
|
+
case 2:
|
77
|
+
default:
|
78
|
+
mouse_move_to2(rb_mouse_unwrap_point(argv[0]), NUM2DBL(argv[1]));
|
79
|
+
}
|
80
|
+
|
67
81
|
return CURRENT_POSITION;
|
68
82
|
}
|
69
83
|
|
70
84
|
/*
|
71
85
|
* Drag the mouse cursor to the given co-ordinates
|
72
86
|
*
|
73
|
-
* @param
|
87
|
+
* @param (see #move_to)
|
74
88
|
* @return [CGPoint]
|
75
89
|
*/
|
76
90
|
static
|
77
91
|
VALUE
|
78
|
-
rb_mouse_drag_to(VALUE
|
92
|
+
rb_mouse_drag_to(int argc, VALUE *argv, VALUE self)
|
79
93
|
{
|
80
|
-
|
94
|
+
switch (argc)
|
95
|
+
{
|
96
|
+
case 0:
|
97
|
+
rb_raise(rb_eArgError, "drag_to requires at least a one arg");
|
98
|
+
break;
|
99
|
+
case 1:
|
100
|
+
mouse_drag_to(rb_mouse_unwrap_point(argv[0]));
|
101
|
+
break;
|
102
|
+
case 2:
|
103
|
+
default:
|
104
|
+
mouse_drag_to2(rb_mouse_unwrap_point(argv[0]), NUM2DBL(argv[1]));
|
105
|
+
}
|
106
|
+
|
81
107
|
return CURRENT_POSITION;
|
82
108
|
}
|
83
109
|
|
84
110
|
/*
|
111
|
+
* @note Scrolling by `:pixel` may not actually be by real pixels, but instead
|
112
|
+
* correspond to Cocoa co-ords (I don't have a retina display, so I haven't
|
113
|
+
* checked it out yet).
|
114
|
+
*
|
85
115
|
* Generate `amount` scroll events at the current cursor position
|
86
116
|
*
|
87
|
-
* Returns number of lines scrolled.
|
117
|
+
* Returns number of lines scrolled. A positive `amount` will scroll up
|
118
|
+
* and a negative `amount` will scroll down.
|
119
|
+
*
|
120
|
+
* An invalid type of `units` will default to `:line`.
|
88
121
|
*
|
89
122
|
* @param amount [Number]
|
123
|
+
* @param units [Symbol] `:pixel` or `:line` (_default_: `:line` ) (__optional__)
|
90
124
|
* @return [Number]
|
91
125
|
*/
|
92
126
|
static
|
93
127
|
VALUE
|
94
|
-
rb_mouse_scroll(VALUE
|
128
|
+
rb_mouse_scroll(int argc, VALUE *argv, VALUE self)
|
95
129
|
{
|
96
|
-
|
97
|
-
|
130
|
+
if (argc == 0 || argc > 3)
|
131
|
+
rb_raise(rb_eArgError, "scroll requires 1..3 arguments, you gave %d", argc);
|
132
|
+
|
133
|
+
VALUE amount = rb_funcall(argv[0], sel_to_i, 0);
|
134
|
+
size_t amt = NUM2SIZET(amount);
|
135
|
+
|
136
|
+
if (argc == 1)
|
137
|
+
mouse_scroll(NUM2SIZET(amt));
|
138
|
+
|
139
|
+
ID units = rb_to_id(argv[1]);
|
140
|
+
|
141
|
+
if (argc == 2) {
|
142
|
+
if (units == unit_pixel)
|
143
|
+
mouse_scroll2(amt, kCGScrollEventUnitPixel);
|
144
|
+
else
|
145
|
+
mouse_scroll2(amt, kCGScrollEventUnitLine);
|
146
|
+
}
|
147
|
+
|
148
|
+
if (argc == 3) {
|
149
|
+
double duration = NUM2DBL(argv[2]);
|
150
|
+
|
151
|
+
if (units == unit_pixel)
|
152
|
+
mouse_scroll3(amt, kCGScrollEventUnitPixel, duration);
|
153
|
+
else
|
154
|
+
mouse_scroll3(amt, kCGScrollEventUnitLine, duration);
|
155
|
+
}
|
156
|
+
|
98
157
|
return amount;
|
99
158
|
}
|
100
159
|
|
101
160
|
/*
|
102
|
-
* Generate the down click part of a click event
|
161
|
+
* Generate the down click part of a click event
|
103
162
|
*
|
104
163
|
* This might be useful in concert with {Mouse.click_up} if you want
|
105
164
|
* to inject some behaviour between the down and up click events.
|
106
165
|
*
|
166
|
+
* You can optionally specify a point to click; the mouse cursor will
|
167
|
+
* instantly jump to the given point.
|
168
|
+
*
|
169
|
+
* @param point [CGPoint] (_default_: {#current_position}) (__optional__)
|
107
170
|
* @return [CGPoint]
|
108
171
|
*/
|
109
172
|
static
|
110
173
|
VALUE
|
111
|
-
rb_mouse_click_down(VALUE self)
|
174
|
+
rb_mouse_click_down(int argc, VALUE *argv, VALUE self)
|
112
175
|
{
|
113
|
-
|
176
|
+
switch (argc)
|
177
|
+
{
|
178
|
+
case 0:
|
179
|
+
mouse_click_down();
|
180
|
+
break;
|
181
|
+
case 1:
|
182
|
+
default:
|
183
|
+
mouse_click_down2(rb_mouse_unwrap_point(argv[0]));
|
184
|
+
}
|
185
|
+
|
114
186
|
return CURRENT_POSITION;
|
115
187
|
}
|
116
188
|
|
117
189
|
/*
|
118
|
-
* Generate the up click part of a click event
|
190
|
+
* Generate the up click part of a click event
|
119
191
|
*
|
120
192
|
* This might be useful in concert with {Mouse.click_down} if you want
|
121
193
|
* to inject some behaviour between the down and up click events.
|
122
194
|
*
|
195
|
+
* You can optionally specify a point to click; the mouse cursor will
|
196
|
+
* instantly jump to the given point.
|
197
|
+
*
|
198
|
+
* @param point [CGPoint] (_default_: {#current_position}) (__optional__)
|
123
199
|
* @return [CGPoint]
|
124
200
|
*/
|
125
201
|
static
|
126
202
|
VALUE
|
127
|
-
rb_mouse_click_up(VALUE self)
|
203
|
+
rb_mouse_click_up(int argc, VALUE *argv, VALUE self)
|
128
204
|
{
|
129
|
-
|
205
|
+
switch (argc)
|
206
|
+
{
|
207
|
+
case 0:
|
208
|
+
mouse_click_up();
|
209
|
+
break;
|
210
|
+
case 1:
|
211
|
+
default:
|
212
|
+
mouse_click_up(rb_mouse_unwrap_point(argv[0]));
|
213
|
+
}
|
214
|
+
|
130
215
|
return CURRENT_POSITION;
|
131
216
|
}
|
132
217
|
|
133
218
|
/*
|
134
|
-
* Generate a regular click event
|
219
|
+
* Generate a regular click event (both up and down events)
|
220
|
+
*
|
221
|
+
* You can optionally specify a point to click; the mouse cursor will
|
222
|
+
* instantly jump to the given point.
|
135
223
|
*
|
224
|
+
* @param point [CGPoint] (_default_: {#current_position}) (__optional__)
|
136
225
|
* @return [CGPoint]
|
137
226
|
*/
|
138
227
|
static
|
139
228
|
VALUE
|
140
|
-
rb_mouse_click(VALUE self)
|
229
|
+
rb_mouse_click(int argc, VALUE *argv, VALUE self)
|
141
230
|
{
|
142
|
-
|
231
|
+
switch (argc)
|
232
|
+
{
|
233
|
+
case 0:
|
234
|
+
mouse_click();
|
235
|
+
break;
|
236
|
+
case 1:
|
237
|
+
default:
|
238
|
+
mouse_click2(rb_mouse_unwrap_point(argv[0]));
|
239
|
+
}
|
240
|
+
|
143
241
|
return CURRENT_POSITION;
|
144
242
|
}
|
145
243
|
|
146
244
|
/*
|
147
|
-
* Generate a secondary click
|
245
|
+
* Generate a secondary click (both down and up events)
|
148
246
|
*
|
149
247
|
* Secondary click is often referred to as "right click".
|
150
248
|
*
|
249
|
+
* You can optionally specify a point to click; the mouse cursor will
|
250
|
+
* instantly jump to the given point.
|
251
|
+
*
|
252
|
+
* @param point [CGPoint] (_default_: {#current_position}) (__optional__)
|
151
253
|
* @return [CGPoint]
|
152
254
|
*/
|
153
255
|
static
|
154
256
|
VALUE
|
155
|
-
rb_mouse_secondary_click(VALUE self)
|
257
|
+
rb_mouse_secondary_click(int argc, VALUE *argv, VALUE self)
|
156
258
|
{
|
157
|
-
|
259
|
+
switch (argc)
|
260
|
+
{
|
261
|
+
case 0:
|
262
|
+
mouse_secondary_click();
|
263
|
+
break;
|
264
|
+
case 1:
|
265
|
+
default:
|
266
|
+
mouse_secondary_click2(rb_mouse_unwrap_point(argv[0]));
|
267
|
+
}
|
268
|
+
|
158
269
|
return CURRENT_POSITION;
|
159
270
|
}
|
160
271
|
|
161
272
|
/*
|
162
|
-
* Generate a click using an arbitrary mouse button
|
273
|
+
* Generate a click using an arbitrary mouse button (down and up events)
|
163
274
|
*
|
164
275
|
* Numbers are used to map the mouse buttons. At the time of writing,
|
165
276
|
* the documented values are:
|
@@ -172,30 +283,62 @@ rb_mouse_secondary_click(VALUE self)
|
|
172
283
|
* to figure out. See the `CGMouseButton` enum in the reference
|
173
284
|
* documentation for the most up to date list.
|
174
285
|
*
|
286
|
+
* You can optionally specify a point to click; the mouse cursor will
|
287
|
+
* instantly jump to the given point.
|
288
|
+
*
|
175
289
|
* @param button [Number,#to_i]
|
290
|
+
* @param point [CGPoint] (_default_: {#current_position}) (__optional__)
|
176
291
|
* @return [CGPoint]
|
177
292
|
*/
|
178
293
|
static
|
179
294
|
VALUE
|
180
|
-
rb_mouse_arbitrary_click(VALUE
|
295
|
+
rb_mouse_arbitrary_click(int argc, VALUE *argv, VALUE self)
|
181
296
|
{
|
182
|
-
|
183
|
-
|
297
|
+
if (argc == 0) {
|
298
|
+
rb_raise(rb_eArgError, "arbitrary_click requires at least one arg");
|
299
|
+
return Qnil;
|
300
|
+
}
|
301
|
+
|
302
|
+
uint_t button = NUM2INT(rb_funcall(argv[0], sel_to_i, 0));
|
303
|
+
|
304
|
+
switch (argc)
|
305
|
+
{
|
306
|
+
case 1:
|
307
|
+
mouse_arbitrary_click(button);
|
308
|
+
break;
|
309
|
+
case 2:
|
310
|
+
default:
|
311
|
+
mouse_arbitrary_click2(button, rb_mouse_unwrap_point(argv[1]));
|
312
|
+
}
|
313
|
+
|
184
314
|
return CURRENT_POSITION;
|
185
315
|
}
|
186
316
|
|
187
317
|
/*
|
188
|
-
* Generate a click event for the middle mouse button
|
318
|
+
* Generate a click event for the middle mouse button (down and up events)
|
189
319
|
*
|
190
320
|
* It doesn't matter if you don't have a middle mouse button.
|
191
321
|
*
|
322
|
+
* You can optionally specify a point to click; the mouse cursor will
|
323
|
+
* instantly jump to the given point.
|
324
|
+
*
|
325
|
+
* @param point [CGPoint] (_default_: {#current_position}) (__optional__)
|
192
326
|
* @return [CGPoint]
|
193
327
|
*/
|
194
328
|
static
|
195
329
|
VALUE
|
196
|
-
rb_mouse_middle_click(VALUE self)
|
330
|
+
rb_mouse_middle_click(int argc, VALUE *argv, VALUE self)
|
197
331
|
{
|
198
|
-
|
332
|
+
switch (argc)
|
333
|
+
{
|
334
|
+
case 0:
|
335
|
+
mouse_middle_click();
|
336
|
+
break;
|
337
|
+
case 1:
|
338
|
+
default:
|
339
|
+
mouse_middle_click(rb_mouse_unwrap_point(argv[0]));
|
340
|
+
}
|
341
|
+
|
199
342
|
return CURRENT_POSITION;
|
200
343
|
}
|
201
344
|
|
@@ -205,16 +348,36 @@ rb_mouse_middle_click(VALUE self)
|
|
205
348
|
* Unlike {Mouse.double_click} and {Mouse.triple_click} this will generate
|
206
349
|
* a single event with the given number of clicks.
|
207
350
|
*
|
351
|
+
* You can optionally specify a point to click; the mouse cursor will
|
352
|
+
* instantly jump to the given point.
|
353
|
+
*
|
208
354
|
* @param num_clicks [Number,#to_i]
|
355
|
+
* @param point [CGPoint] (_default_: {#current_position}) (__optional__)
|
209
356
|
* @return [CGPoint]
|
210
357
|
*/
|
211
358
|
static
|
212
359
|
VALUE
|
213
|
-
rb_mouse_multi_click(VALUE
|
360
|
+
rb_mouse_multi_click(int argc, VALUE *argv, VALUE self)
|
214
361
|
{
|
362
|
+
|
363
|
+
if (argc == 0) {
|
364
|
+
rb_raise(rb_eArgError, "multi_click requires at least one arg");
|
365
|
+
return Qnil;
|
366
|
+
}
|
367
|
+
|
215
368
|
// TODO: there has got to be a more idiomatic way to do this coercion
|
216
|
-
num_clicks = rb_funcall(
|
217
|
-
|
369
|
+
size_t num_clicks = NUM2SIZET(rb_funcall(argv[0], sel_to_i, 0));
|
370
|
+
|
371
|
+
switch (argc)
|
372
|
+
{
|
373
|
+
case 1:
|
374
|
+
mouse_multi_click(num_clicks);
|
375
|
+
break;
|
376
|
+
case 2:
|
377
|
+
default:
|
378
|
+
mouse_multi_click2(num_clicks, rb_mouse_unwrap_point(argv[1]));
|
379
|
+
}
|
380
|
+
|
218
381
|
return CURRENT_POSITION;
|
219
382
|
}
|
220
383
|
|
@@ -225,13 +388,26 @@ rb_mouse_multi_click(VALUE self, VALUE num_clicks)
|
|
225
388
|
* Apps seem to respond more consistently to this behaviour since that is
|
226
389
|
* how a human would have to generate a double click event.
|
227
390
|
*
|
391
|
+
* You can optionally specify a point to click; the mouse cursor will
|
392
|
+
* instantly jump to the given point.
|
393
|
+
*
|
394
|
+
* @param point [CGPoint] (_default_: {#current_position}) (__optional__)
|
228
395
|
* @return [CGPoint]
|
229
396
|
*/
|
230
397
|
static
|
231
398
|
VALUE
|
232
|
-
rb_mouse_double_click(VALUE self)
|
399
|
+
rb_mouse_double_click(int argc, VALUE *argv, VALUE self)
|
233
400
|
{
|
234
|
-
|
401
|
+
switch (argc)
|
402
|
+
{
|
403
|
+
case 0:
|
404
|
+
mouse_double_click();
|
405
|
+
break;
|
406
|
+
case 1:
|
407
|
+
default:
|
408
|
+
mouse_double_click2(rb_mouse_unwrap_point(argv[0]));
|
409
|
+
}
|
410
|
+
|
235
411
|
return CURRENT_POSITION;
|
236
412
|
}
|
237
413
|
|
@@ -243,13 +419,26 @@ rb_mouse_double_click(VALUE self)
|
|
243
419
|
* this behaviour since that is how a human would have to generate a
|
244
420
|
* triple click event.
|
245
421
|
*
|
422
|
+
* You can optionally specify a point to click; the mouse cursor will
|
423
|
+
* instantly jump to the given point.
|
424
|
+
*
|
425
|
+
* @param point [CGPoint] (_default_: {#current_position}) (__optional__)
|
246
426
|
* @return [CGPoint]
|
247
427
|
*/
|
248
428
|
static
|
249
429
|
VALUE
|
250
|
-
rb_mouse_triple_click(VALUE self)
|
430
|
+
rb_mouse_triple_click(int argc, VALUE *argv, VALUE self)
|
251
431
|
{
|
252
|
-
|
432
|
+
switch (argc)
|
433
|
+
{
|
434
|
+
case 0:
|
435
|
+
mouse_triple_click();
|
436
|
+
break;
|
437
|
+
case 1:
|
438
|
+
default:
|
439
|
+
mouse_triple_click2(rb_mouse_unwrap_point(argv[0]));
|
440
|
+
}
|
441
|
+
|
253
442
|
return CURRENT_POSITION;
|
254
443
|
}
|
255
444
|
|
@@ -265,10 +454,20 @@ Init_mouse()
|
|
265
454
|
sel_to_i = rb_intern("to_i");
|
266
455
|
sel_new = rb_intern("new");
|
267
456
|
|
457
|
+
unit_pixel = rb_intern("pixel");
|
458
|
+
|
268
459
|
/*
|
269
460
|
* Document-module: Mouse
|
270
461
|
*
|
271
|
-
*
|
462
|
+
* A module with methods that "tap" into the system input methods.
|
463
|
+
* This is done by wrapping wrapping around the CoreGraphics event
|
464
|
+
* taps API provided by OS X.
|
465
|
+
*
|
466
|
+
* The module provides a simple Ruby interface to performing mouse
|
467
|
+
* interactions such as moving and clicking.
|
468
|
+
*
|
469
|
+
* This module can be used in a stand alone fashion or you can mix
|
470
|
+
* it into another class.
|
272
471
|
*
|
273
472
|
* [Reference](http://developer.apple.com/library/mac/#documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html)
|
274
473
|
*/
|
@@ -276,17 +475,19 @@ Init_mouse()
|
|
276
475
|
|
277
476
|
rb_funcall(rb_mMouse, rb_intern("extend"), 1, rb_mMouse);
|
278
477
|
|
279
|
-
rb_define_method(rb_mMouse, "current_position", rb_mouse_current_position,
|
280
|
-
rb_define_method(rb_mMouse, "move_to", rb_mouse_move_to, 1);
|
281
|
-
rb_define_method(rb_mMouse, "drag_to", rb_mouse_drag_to, 1);
|
282
|
-
rb_define_method(rb_mMouse, "scroll", rb_mouse_scroll, 1);
|
283
|
-
rb_define_method(rb_mMouse, "click_down", rb_mouse_click_down,
|
284
|
-
rb_define_method(rb_mMouse, "click_up", rb_mouse_click_up,
|
285
|
-
rb_define_method(rb_mMouse, "click", rb_mouse_click,
|
286
|
-
rb_define_method(rb_mMouse, "secondary_click", rb_mouse_secondary_click,
|
287
|
-
rb_define_method(rb_mMouse, "
|
288
|
-
rb_define_method(rb_mMouse, "
|
289
|
-
rb_define_method(rb_mMouse, "multi_click", rb_mouse_multi_click, 1);
|
290
|
-
rb_define_method(rb_mMouse, "double_click", rb_mouse_double_click,
|
291
|
-
rb_define_method(rb_mMouse, "triple_click", rb_mouse_triple_click,
|
478
|
+
rb_define_method(rb_mMouse, "current_position", rb_mouse_current_position, 0);
|
479
|
+
rb_define_method(rb_mMouse, "move_to", rb_mouse_move_to, -1);
|
480
|
+
rb_define_method(rb_mMouse, "drag_to", rb_mouse_drag_to, -1);
|
481
|
+
rb_define_method(rb_mMouse, "scroll", rb_mouse_scroll, -1);
|
482
|
+
rb_define_method(rb_mMouse, "click_down", rb_mouse_click_down, -1);
|
483
|
+
rb_define_method(rb_mMouse, "click_up", rb_mouse_click_up, -1);
|
484
|
+
rb_define_method(rb_mMouse, "click", rb_mouse_click, -1);
|
485
|
+
rb_define_method(rb_mMouse, "secondary_click", rb_mouse_secondary_click, -1);
|
486
|
+
rb_define_method(rb_mMouse, "middle_click", rb_mouse_middle_click, -1);
|
487
|
+
rb_define_method(rb_mMouse, "arbitrary_click", rb_mouse_arbitrary_click, -1);
|
488
|
+
rb_define_method(rb_mMouse, "multi_click", rb_mouse_multi_click, -1);
|
489
|
+
rb_define_method(rb_mMouse, "double_click", rb_mouse_double_click, -1);
|
490
|
+
rb_define_method(rb_mMouse, "triple_click", rb_mouse_triple_click, -1);
|
491
|
+
|
492
|
+
rb_define_alias(rb_mMouse, "right_click", "secondary_click");
|
292
493
|
}
|
data/ext/mouse/mouser.c
CHANGED
@@ -9,15 +9,15 @@
|
|
9
9
|
#include <ApplicationServices/ApplicationServices.h>
|
10
10
|
#include "mouser.h"
|
11
11
|
|
12
|
-
static const uint_t FPS =
|
13
|
-
static const uint_t QUANTUM = 1000000 /
|
12
|
+
static const uint_t FPS = 240;
|
13
|
+
static const uint_t QUANTUM = 1000000 / 240; // should be FPS, but GCC sucks
|
14
14
|
static const double DEFAULT_DURATION = 0.2; // seconds
|
15
15
|
|
16
16
|
#define NEW_EVENT(type,point,button) CGEventCreateMouseEvent(nil,type,point,button)
|
17
17
|
#define POST(event) CGEventPost(kCGHIDEventTap, event)
|
18
18
|
#define CHANGE(event,type) CGEventSetType(event, type)
|
19
19
|
|
20
|
-
#define CLOSE_ENOUGH(a,b) ((
|
20
|
+
#define CLOSE_ENOUGH(a,b) ((abs(a.x - b.x) < 1.0) && (abs(a.y - b.y) < 1.0))
|
21
21
|
#define NOW (CFDateCreate(nil,CFAbsoluteTimeGetCurrent()))
|
22
22
|
|
23
23
|
#ifdef NOT_MACRUBY
|
@@ -62,7 +62,7 @@ mouse_animate(
|
|
62
62
|
)
|
63
63
|
{
|
64
64
|
CFDateRef current_time = NULL;
|
65
|
-
CGPoint current_point
|
65
|
+
CGPoint current_point = start_point;
|
66
66
|
double xstep = (end_point.x - start_point.x) / (duration * FPS);
|
67
67
|
double ystep = (end_point.y - start_point.y) / (duration * FPS);
|
68
68
|
CFDateRef start = NOW;
|
@@ -79,8 +79,11 @@ mouse_animate(
|
|
79
79
|
|
80
80
|
mouse_sleep(1);
|
81
81
|
current_time = NOW;
|
82
|
-
|
82
|
+
|
83
|
+
// this is a safety
|
84
|
+
if (CFDateGetTimeIntervalSinceDate(NOW, start) > (duration + 1))
|
83
85
|
break;
|
86
|
+
|
84
87
|
RELEASE(current_time);
|
85
88
|
current_time = NULL;
|
86
89
|
|
@@ -145,7 +148,7 @@ mouse_drag_to(CGPoint point)
|
|
145
148
|
|
146
149
|
|
147
150
|
void
|
148
|
-
mouse_scroll3(size_t amount,
|
151
|
+
mouse_scroll3(size_t amount, CGScrollEventUnit units, double duration)
|
149
152
|
{
|
150
153
|
size_t steps = round(FPS * duration);
|
151
154
|
double current = 0.0;
|
@@ -156,13 +159,13 @@ mouse_scroll3(size_t amount, enum MouseMovementUnit units, double duration)
|
|
156
159
|
done = (double)(step+1) / (double)steps;
|
157
160
|
scroll = round((done - current) * amount);
|
158
161
|
POSTRELEASE(CGEventCreateScrollWheelEvent(nil, units, 1, scroll));
|
159
|
-
mouse_sleep(
|
162
|
+
mouse_sleep(2);
|
160
163
|
current += (double)scroll / (double)amount;
|
161
164
|
}
|
162
165
|
}
|
163
166
|
|
164
167
|
void
|
165
|
-
mouse_scroll2(size_t amount,
|
168
|
+
mouse_scroll2(size_t amount, CGScrollEventUnit units)
|
166
169
|
{
|
167
170
|
mouse_scroll3(amount, units, DEFAULT_DURATION);
|
168
171
|
}
|
@@ -170,7 +173,7 @@ mouse_scroll2(size_t amount, enum MouseMovementUnit units)
|
|
170
173
|
void
|
171
174
|
mouse_scroll(size_t amount)
|
172
175
|
{
|
173
|
-
mouse_scroll2(amount,
|
176
|
+
mouse_scroll2(amount, kCGScrollEventUnitLine);
|
174
177
|
}
|
175
178
|
|
176
179
|
|
@@ -184,8 +187,7 @@ mouse_click_down3(CGPoint point, uint_t sleep_quanta)
|
|
184
187
|
void
|
185
188
|
mouse_click_down2(CGPoint point)
|
186
189
|
{
|
187
|
-
|
188
|
-
mouse_click_down3(point, 12);
|
190
|
+
mouse_click_down3(point, FPS / 10);
|
189
191
|
}
|
190
192
|
|
191
193
|
void
|
@@ -240,8 +242,7 @@ mouse_secondary_click3(CGPoint point, uint_t sleep_quanta)
|
|
240
242
|
void
|
241
243
|
mouse_secondary_click2(CGPoint point)
|
242
244
|
{
|
243
|
-
|
244
|
-
mouse_secondary_click3(point, 12);
|
245
|
+
mouse_secondary_click3(point, FPS / 10);
|
245
246
|
}
|
246
247
|
|
247
248
|
void
|
@@ -268,7 +269,7 @@ mouse_arbitrary_click3(CGEventMouseSubtype button, CGPoint point, uint_t sleep_q
|
|
268
269
|
void
|
269
270
|
mouse_arbitrary_click2(CGEventMouseSubtype button, CGPoint point)
|
270
271
|
{
|
271
|
-
mouse_arbitrary_click3(button, point,
|
272
|
+
mouse_arbitrary_click3(button, point, FPS / 10);
|
272
273
|
}
|
273
274
|
|
274
275
|
void
|
data/ext/mouse/mouser.h
CHANGED
@@ -10,13 +10,6 @@
|
|
10
10
|
|
11
11
|
typedef unsigned int uint_t;
|
12
12
|
|
13
|
-
enum MouseMovementUnit {
|
14
|
-
kMouseScrollByLine = kCGScrollEventUnitLine,
|
15
|
-
// TODO: might not be real pixels, might be Cocoa co-ords, need to investigate
|
16
|
-
kMouseScrollByPixel = kCGScrollEventUnitPixel
|
17
|
-
};
|
18
|
-
|
19
|
-
|
20
13
|
CGPoint mouse_current_position();
|
21
14
|
|
22
15
|
void mouse_move_to(CGPoint point);
|
@@ -26,8 +19,8 @@ void mouse_drag_to(CGPoint point);
|
|
26
19
|
void mouse_drag_to2(CGPoint point, double duration);
|
27
20
|
|
28
21
|
void mouse_scroll(size_t amount);
|
29
|
-
void mouse_scroll2(size_t amount,
|
30
|
-
void mouse_scroll3(size_t amount,
|
22
|
+
void mouse_scroll2(size_t amount, CGScrollEventUnit units);
|
23
|
+
void mouse_scroll3(size_t amount, CGScrollEventUnit units, double duration);
|
31
24
|
|
32
25
|
void mouse_click_down();
|
33
26
|
void mouse_click_down2(CGPoint point);
|
data/lib/mouse/version.rb
CHANGED
data/lib/mouse.rb
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
if RUBY_ENGINE == 'macruby'
|
2
2
|
|
3
|
+
framework 'AppKit'
|
4
|
+
|
3
5
|
# A workaround that guarantees that `CGPoint` is defined
|
4
|
-
|
6
|
+
MOUNTAIN_LION_APPKIT_VERSION = 1187
|
7
|
+
if NSAppKitVersionNumber >= MOUNTAIN_LION_APPKIT_VERSION
|
8
|
+
framework '/System/Library/Frameworks/CoreGraphics.framework'
|
9
|
+
end
|
5
10
|
|
6
11
|
else
|
7
12
|
|
@@ -9,6 +14,12 @@ else
|
|
9
14
|
# A structure that contains a point in a two-dimensional coordinate system
|
10
15
|
class CGPoint < Struct.new(:x, :y)
|
11
16
|
|
17
|
+
# @param x [Number]
|
18
|
+
# @param y [Number]
|
19
|
+
def initialize x = 0.0, y = 0.0
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
12
23
|
# @!attribute [rw] x
|
13
24
|
# The `x` co-ordinate of the screen point
|
14
25
|
# @return [Number]
|
@@ -24,7 +35,7 @@ else
|
|
24
35
|
#
|
25
36
|
# @return [String]
|
26
37
|
def inspect
|
27
|
-
"#<CGPoint x=#{self
|
38
|
+
"#<CGPoint x=#{self.x.to_f} y=#{self.y.to_f}>"
|
28
39
|
end
|
29
40
|
|
30
41
|
end
|
data/test/helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mouse
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-12-
|
12
|
+
date: 2012-12-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: yard
|
@@ -98,18 +98,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
98
98
|
- - ! '>='
|
99
99
|
- !ruby/object:Gem::Version
|
100
100
|
version: '0'
|
101
|
-
segments:
|
102
|
-
- 0
|
103
|
-
hash: 1024147063034037924
|
104
101
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
102
|
none: false
|
106
103
|
requirements:
|
107
104
|
- - ! '>='
|
108
105
|
- !ruby/object:Gem::Version
|
109
106
|
version: '0'
|
110
|
-
segments:
|
111
|
-
- 0
|
112
|
-
hash: 1024147063034037924
|
113
107
|
requirements: []
|
114
108
|
rubyforge_project:
|
115
109
|
rubygems_version: 1.8.24
|