mouse 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
- TODO :P
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 => :install
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
- desc 'Run tests'
17
- task :test do
18
- # @todo
19
- ruby 'test/helper.rb'
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 self, VALUE point)
66
+ rb_mouse_move_to(int argc, VALUE *argv, VALUE self)
65
67
  {
66
- mouse_move_to(rb_mouse_unwrap_point(point));
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 point [CGPoint,Array(Number,Number),#to_point]
87
+ * @param (see #move_to)
74
88
  * @return [CGPoint]
75
89
  */
76
90
  static
77
91
  VALUE
78
- rb_mouse_drag_to(VALUE self, VALUE point)
92
+ rb_mouse_drag_to(int argc, VALUE *argv, VALUE self)
79
93
  {
80
- mouse_drag_to(rb_mouse_unwrap_point(point));
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 self, VALUE amount)
128
+ rb_mouse_scroll(int argc, VALUE *argv, VALUE self)
95
129
  {
96
- amount = rb_funcall(amount, sel_to_i, 0);
97
- mouse_scroll(NUM2SIZET(amount));
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 at the current position
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
- mouse_click_down();
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 at the current position
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
- mouse_click_up();
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 at the current mouse position
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
- mouse_click();
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 at the current mouse position
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
- mouse_secondary_click();
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 at the current position
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 self, VALUE button)
295
+ rb_mouse_arbitrary_click(int argc, VALUE *argv, VALUE self)
181
296
  {
182
- button = rb_funcall(button, sel_to_i, 0);
183
- mouse_arbitrary_click(NUM2UINT(button));
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 at the current position
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
- mouse_middle_click();
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 self, VALUE num_clicks)
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(num_clicks, sel_to_i, 0);
217
- mouse_multi_click(NUM2SIZET(num_clicks));
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
- mouse_double_click();
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
- mouse_triple_click();
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
- * Herp Derp TODO
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, 0);
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, 0);
284
- rb_define_method(rb_mMouse, "click_up", rb_mouse_click_up, 0);
285
- rb_define_method(rb_mMouse, "click", rb_mouse_click, 0);
286
- rb_define_method(rb_mMouse, "secondary_click", rb_mouse_secondary_click, 0);
287
- rb_define_method(rb_mMouse, "arbitrary_click", rb_mouse_arbitrary_click, 1);
288
- rb_define_method(rb_mMouse, "middle_click", rb_mouse_middle_click, 0);
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, 0);
291
- rb_define_method(rb_mMouse, "triple_click", rb_mouse_triple_click, 0);
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 = 120;
13
- static const uint_t QUANTUM = 1000000 / 120; // should be FPS, but GCC sucks
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) ((pow(a.x-b.x,2)+pow(a.y-b.y,2)) <= 1.0)
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 = start_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
- if (CFDateGetTimeIntervalSinceDate(NOW, start) > 5.0)
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, enum MouseMovementUnit units, double duration)
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(1);
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, enum MouseMovementUnit units)
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, kMouseScrollByLine);
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
- // TODO: replace constant 12 with something more abstract
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
- // TODO: replace constant 12 with something more abstract
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, 12);
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, enum MouseMovementUnit units);
30
- void mouse_scroll3(size_t amount, enum MouseMovementUnit units, double duration);
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
@@ -1,4 +1,4 @@
1
1
  module Mouse
2
- VERSION = '0.1.0'
2
+ VERSION = '1.0.0'
3
3
  end
4
4
 
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
- framework '/System/Library/Frameworks/CoreGraphics.framework'
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[:x]} y=#{self[:y]}>"
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
@@ -1,3 +1,4 @@
1
1
  require 'minitest/autorun'
2
+ require 'mouse'
2
3
 
3
4
 
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: 0.1.0
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-03 00:00:00.000000000 Z
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