mouse 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +9 -0
- data/History.markdown +10 -0
- data/README.markdown +38 -0
- data/Rakefile +37 -0
- data/ext/mouse/extconf.rb +23 -0
- data/ext/mouse/mouse.c +116 -0
- data/ext/mouse/mouser.c +347 -0
- data/ext/mouse/mouser.h +58 -0
- data/lib/mouse.rb +48 -0
- data/lib/mouse/version.rb +4 -0
- data/test/helper.rb +3 -0
- metadata +113 -0
data/.yardopts
ADDED
data/History.markdown
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# 0.0.1 - Initial Release
|
2
|
+
|
3
|
+
* CRuby and MacRuby compatible
|
4
|
+
|
5
|
+
* Added Mouse.current_position
|
6
|
+
* Added Mouse.move_to
|
7
|
+
* Added Mouse.drag_to
|
8
|
+
* Added Mouse.scroll
|
9
|
+
* Added CGPoint on CRuby to mimic CGPoint in MacRuby
|
10
|
+
* Added Array#to_point to mimic MacRuby allowing Arrays for structs
|
data/README.markdown
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# MRMouse
|
2
|
+
|
3
|
+
A port of mouse.rb from [AXElements](http://github.com/Marketcircle/AXElements),
|
4
|
+
but cleaned up and rewritten in C to be more portable across languages and
|
5
|
+
runtimes.
|
6
|
+
|
7
|
+
Not much to see right now.
|
8
|
+
|
9
|
+
## Copyright
|
10
|
+
|
11
|
+
Copyright (c) 2012, Mark Rada
|
12
|
+
All rights reserved.
|
13
|
+
|
14
|
+
Redistribution and use in source and binary forms, with or without
|
15
|
+
modification, are permitted provided that the following conditions are met:
|
16
|
+
|
17
|
+
* Redistributions of source code must retain the above copyright
|
18
|
+
notice, this list of conditions and the following disclaimer.
|
19
|
+
* Redistributions in binary form must reproduce the above copyright
|
20
|
+
notice, this list of conditions and the following disclaimer in the
|
21
|
+
documentation and/or other materials provided with the distribution.
|
22
|
+
* Neither the name of Mark Rada nor the names of its
|
23
|
+
contributors may be used to endorse or promote products derived
|
24
|
+
from this software without specific prior written permission.
|
25
|
+
|
26
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
27
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
28
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
29
|
+
DISCLAIMED. IN NO EVENT SHALL Mark Rada BE LIABLE FOR ANY
|
30
|
+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
31
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
32
|
+
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
33
|
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
34
|
+
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
35
|
+
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
36
|
+
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
37
|
+
|
38
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
task :default => :install
|
2
|
+
|
3
|
+
require 'rake/clean'
|
4
|
+
CLEAN.include '*.plist', '*.gch'
|
5
|
+
|
6
|
+
desc 'Run the Clang static analyzer'
|
7
|
+
task :analyze do
|
8
|
+
sh "clang --analyze ext/mouse/mouser.c"
|
9
|
+
end
|
10
|
+
|
11
|
+
desc 'Startup an IRb console with Mouse loaded'
|
12
|
+
task :console => [:compile] do
|
13
|
+
sh 'irb -Ilib -rmouse'
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Run tests'
|
17
|
+
task :test do
|
18
|
+
# @todo
|
19
|
+
ruby 'test/helper.rb'
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
# Gem stuff
|
24
|
+
|
25
|
+
require 'rubygems/package_task'
|
26
|
+
mouse_spec = Gem::Specification.load('mouse.gemspec')
|
27
|
+
|
28
|
+
Gem::PackageTask.new(mouse_spec) { }
|
29
|
+
|
30
|
+
desc 'Build and install gem (not including deps)'
|
31
|
+
task :install => :gem do
|
32
|
+
require 'rubygems/installer'
|
33
|
+
Gem::Installer.new("pkg/#{mouse_spec.file_name}").install
|
34
|
+
end
|
35
|
+
|
36
|
+
require 'rake/extensiontask'
|
37
|
+
Rake::ExtensionTask.new('mouse', mouse_spec)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
$CFLAGS << ' -std=c99 -Wall -Werror -pedantic'
|
4
|
+
$LIBS << ' -framework Foundation -framework ApplicationServices -framework CoreGraphics'
|
5
|
+
|
6
|
+
if RUBY_ENGINE == 'macruby'
|
7
|
+
$LIBS << ' -framework Cocoa'
|
8
|
+
$CFLAGS << ' -ObjC -fobjc-gc'
|
9
|
+
else
|
10
|
+
unless RbConfig::CONFIG["CC"].match /clang/
|
11
|
+
clang = `which clang`.chomp
|
12
|
+
if clang.empty?
|
13
|
+
$stdout.puts "Clang not installed. Cannot build C extension"
|
14
|
+
raise "Clang not installed. Cannot build C extension"
|
15
|
+
else
|
16
|
+
RbConfig::MAKEFILE_CONFIG["CC"] = clang
|
17
|
+
RbConfig::MAKEFILE_CONFIG["CXX"] = clang
|
18
|
+
end
|
19
|
+
end
|
20
|
+
$CFLAGS << ' -DNOT_MACRUBY'
|
21
|
+
end
|
22
|
+
|
23
|
+
create_makefile 'mouse/mouse'
|
data/ext/mouse/mouse.c
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
#include "mouser.h"
|
2
|
+
#include "ruby.h"
|
3
|
+
|
4
|
+
static VALUE rb_mMouse;
|
5
|
+
static VALUE rb_cCGPoint;
|
6
|
+
static ID sel_x;
|
7
|
+
static ID sel_y;
|
8
|
+
static ID sel_to_point;
|
9
|
+
static ID sel_to_i;
|
10
|
+
static ID sel_new;
|
11
|
+
|
12
|
+
#define CURRENT_POSITION rb_mouse_wrap_point(mouse_current_position())
|
13
|
+
|
14
|
+
static
|
15
|
+
VALUE
|
16
|
+
rb_mouse_wrap_point(CGPoint point)
|
17
|
+
{
|
18
|
+
#if NOT_MACRUBY
|
19
|
+
return rb_struct_new(rb_cCGPoint, DBL2NUM(point.x), DBL2NUM(point.y));
|
20
|
+
#else
|
21
|
+
return rb_funcall(rb_cCGPoint, sel_new, 2, DBL2NUM(point.x), DBL2NUM(point.y));
|
22
|
+
#endif
|
23
|
+
}
|
24
|
+
|
25
|
+
static
|
26
|
+
CGPoint
|
27
|
+
rb_mouse_unwrap_point(VALUE point)
|
28
|
+
{
|
29
|
+
point = rb_funcall(point, sel_to_point, 0);
|
30
|
+
|
31
|
+
#if NOT_MACRUBY
|
32
|
+
double x = NUM2DBL(rb_struct_getmember(point, sel_x));
|
33
|
+
double y = NUM2DBL(rb_struct_getmember(point, sel_y));
|
34
|
+
return CGPointMake(x, y);
|
35
|
+
|
36
|
+
#else
|
37
|
+
CGPoint* ptr;
|
38
|
+
Data_Get_Struct(point, CGPoint, ptr);
|
39
|
+
return *ptr;
|
40
|
+
|
41
|
+
#endif
|
42
|
+
}
|
43
|
+
|
44
|
+
/***
|
45
|
+
* Returns the current co-ordinates of the Mouse
|
46
|
+
*
|
47
|
+
* @return [CGPoint]
|
48
|
+
*/
|
49
|
+
static
|
50
|
+
VALUE
|
51
|
+
rb_mouse_current_position(VALUE self)
|
52
|
+
{
|
53
|
+
return CURRENT_POSITION;
|
54
|
+
}
|
55
|
+
|
56
|
+
/***
|
57
|
+
* Move the cursor to the given co-ordinates
|
58
|
+
*
|
59
|
+
* @param point [CGPoint,Array(Number,Number),#to_point]
|
60
|
+
* @return [CGPoint]
|
61
|
+
*/
|
62
|
+
static
|
63
|
+
VALUE
|
64
|
+
rb_mouse_move_to(VALUE self, VALUE point)
|
65
|
+
{
|
66
|
+
mouse_move_to(rb_mouse_unwrap_point(point));
|
67
|
+
return CURRENT_POSITION;
|
68
|
+
}
|
69
|
+
|
70
|
+
/***
|
71
|
+
* Drag the cursor to the given co-ordinates
|
72
|
+
*
|
73
|
+
* @param point [CGPoint,Array(Number,Number),#to_point]
|
74
|
+
* @return [CGPoint]
|
75
|
+
*/
|
76
|
+
static
|
77
|
+
VALUE
|
78
|
+
rb_mouse_drag_to(VALUE self, VALUE point)
|
79
|
+
{
|
80
|
+
mouse_drag_to(rb_mouse_unwrap_point(point));
|
81
|
+
return CURRENT_POSITION;
|
82
|
+
}
|
83
|
+
|
84
|
+
/***
|
85
|
+
* Generate `amount` scroll events at the current cursor position
|
86
|
+
*
|
87
|
+
* @param amount [Number]
|
88
|
+
* @return [CGPoint]
|
89
|
+
*/
|
90
|
+
static
|
91
|
+
VALUE
|
92
|
+
rb_mouse_scroll(VALUE self, VALUE amount)
|
93
|
+
{
|
94
|
+
amount = rb_funcall(amount, sel_to_i, 0);
|
95
|
+
mouse_scroll(NUM2SIZET(amount));
|
96
|
+
return CURRENT_POSITION;
|
97
|
+
}
|
98
|
+
|
99
|
+
void
|
100
|
+
Init_mouse()
|
101
|
+
{
|
102
|
+
rb_cCGPoint = rb_const_get(rb_cObject, rb_intern("CGPoint"));
|
103
|
+
sel_x = rb_intern("x");
|
104
|
+
sel_y = rb_intern("y");
|
105
|
+
sel_to_point = rb_intern("to_point");
|
106
|
+
sel_to_i = rb_intern("to_i");
|
107
|
+
sel_new = rb_intern("new");
|
108
|
+
|
109
|
+
rb_mMouse = rb_define_module("Mouse");
|
110
|
+
rb_funcall(rb_mMouse, rb_intern("extend"), 1, rb_mMouse);
|
111
|
+
|
112
|
+
rb_define_method(rb_mMouse, "current_position", rb_mouse_current_position, 0);
|
113
|
+
rb_define_method(rb_mMouse, "move_to", rb_mouse_move_to, 1);
|
114
|
+
rb_define_method(rb_mMouse, "drag_to", rb_mouse_drag_to, 1);
|
115
|
+
rb_define_method(rb_mMouse, "scroll", rb_mouse_scroll, 1);
|
116
|
+
}
|
data/ext/mouse/mouser.c
ADDED
@@ -0,0 +1,347 @@
|
|
1
|
+
//
|
2
|
+
// Mouser.c
|
3
|
+
// MRMouse
|
4
|
+
//
|
5
|
+
// Created by Mark Rada on 12-03-17.
|
6
|
+
// Copyright (c) 2012 Mark Rada. All rights reserved.
|
7
|
+
//
|
8
|
+
|
9
|
+
#include <ApplicationServices/ApplicationServices.h>
|
10
|
+
#include "mouser.h"
|
11
|
+
|
12
|
+
static const double FPS = 120.0;
|
13
|
+
static const double QUANTUM = 1 / 120; // Should be (1 / FPS), but gcc sucks
|
14
|
+
static const double DEFAULT_DURATION = 0.2; // seconds
|
15
|
+
|
16
|
+
#define NEW_EVENT(type,point,button) CGEventCreateMouseEvent(nil,type,point,button)
|
17
|
+
#define POST(event) CGEventPost(kCGHIDEventTap, event)
|
18
|
+
#define CHANGE(event,type) CGEventSetType(event, type)
|
19
|
+
|
20
|
+
#define CLOSE_ENOUGH(a,b) ((pow(a.x-b.x,2)+pow(a.y-b.y,2)) <= 1.0)
|
21
|
+
#define NOW (CFDateCreate(nil,CFAbsoluteTimeGetCurrent()))
|
22
|
+
|
23
|
+
#ifdef NOT_MACRUBY
|
24
|
+
#define RELEASE(x) CFRelease(x)
|
25
|
+
#else
|
26
|
+
#define RELEASE(x) CFMakeCollectable(x)
|
27
|
+
#endif
|
28
|
+
|
29
|
+
#define POSTRELEASE(x) do { \
|
30
|
+
CGEventRef event = x; \
|
31
|
+
POST(event); \
|
32
|
+
RELEASE(event); \
|
33
|
+
} while(false);
|
34
|
+
|
35
|
+
|
36
|
+
static
|
37
|
+
void
|
38
|
+
mouse_sleep(size_t quanta)
|
39
|
+
{
|
40
|
+
sleep(quanta * QUANTUM);
|
41
|
+
}
|
42
|
+
|
43
|
+
CGPoint
|
44
|
+
mouse_current_position()
|
45
|
+
{
|
46
|
+
CGEventRef event = CGEventCreate(nil);
|
47
|
+
CGPoint point = CGEventGetLocation(event);
|
48
|
+
RELEASE(event);
|
49
|
+
return point;
|
50
|
+
}
|
51
|
+
|
52
|
+
// Executes a linear mouse movement animation. It can be a simple cursor
|
53
|
+
// move or a drag depending on what is passed to `type`.
|
54
|
+
static
|
55
|
+
void
|
56
|
+
mouse_animate(
|
57
|
+
CGEventType type,
|
58
|
+
CGMouseButton button,
|
59
|
+
CGPoint start_point,
|
60
|
+
CGPoint end_point,
|
61
|
+
double duration
|
62
|
+
)
|
63
|
+
{
|
64
|
+
CFDateRef current_time = NULL;
|
65
|
+
CGPoint current_point = start_point;
|
66
|
+
double xstep = (end_point.x - start_point.x) / (duration * FPS);
|
67
|
+
double ystep = (end_point.y - start_point.y) / (duration * FPS);
|
68
|
+
CFDateRef start = NOW;
|
69
|
+
double remaining = 0.0;
|
70
|
+
|
71
|
+
while (!CLOSE_ENOUGH(current_point, end_point)) {
|
72
|
+
remaining = end_point.x - current_point.x;
|
73
|
+
current_point.x += abs(xstep) > abs(remaining) ? remaining : xstep;
|
74
|
+
|
75
|
+
remaining = end_point.y - current_point.y;
|
76
|
+
current_point.y += abs(ystep) > abs(remaining) ? remaining : ystep;
|
77
|
+
|
78
|
+
POSTRELEASE(NEW_EVENT(type, current_point, button));
|
79
|
+
|
80
|
+
mouse_sleep(1);
|
81
|
+
current_time = NOW;
|
82
|
+
if (CFDateGetTimeIntervalSinceDate(NOW, start) > 5.0)
|
83
|
+
break;
|
84
|
+
RELEASE(current_time);
|
85
|
+
current_time = NULL;
|
86
|
+
|
87
|
+
current_point = mouse_current_position();
|
88
|
+
}
|
89
|
+
|
90
|
+
RELEASE(start);
|
91
|
+
if (current_time)
|
92
|
+
RELEASE(current_time);
|
93
|
+
}
|
94
|
+
|
95
|
+
|
96
|
+
void
|
97
|
+
mouse_move_to2(CGPoint point, double duration)
|
98
|
+
{
|
99
|
+
mouse_animate(
|
100
|
+
kCGEventMouseMoved,
|
101
|
+
kCGMouseButtonLeft,
|
102
|
+
mouse_current_position(),
|
103
|
+
point,
|
104
|
+
duration
|
105
|
+
);
|
106
|
+
}
|
107
|
+
|
108
|
+
void
|
109
|
+
mouse_move_to(CGPoint point)
|
110
|
+
{
|
111
|
+
mouse_move_to2(point, DEFAULT_DURATION);
|
112
|
+
}
|
113
|
+
|
114
|
+
|
115
|
+
void
|
116
|
+
mouse_drag_to2(CGPoint point, double duration)
|
117
|
+
{
|
118
|
+
POSTRELEASE(NEW_EVENT(
|
119
|
+
kCGEventLeftMouseDown,
|
120
|
+
mouse_current_position(),
|
121
|
+
kCGMouseButtonLeft
|
122
|
+
));
|
123
|
+
|
124
|
+
|
125
|
+
mouse_animate(
|
126
|
+
kCGEventLeftMouseDragged,
|
127
|
+
kCGMouseButtonLeft,
|
128
|
+
mouse_current_position(),
|
129
|
+
point,
|
130
|
+
duration
|
131
|
+
);
|
132
|
+
|
133
|
+
POSTRELEASE(NEW_EVENT(
|
134
|
+
kCGEventLeftMouseUp,
|
135
|
+
mouse_current_position(),
|
136
|
+
kCGMouseButtonLeft
|
137
|
+
));
|
138
|
+
}
|
139
|
+
|
140
|
+
void
|
141
|
+
mouse_drag_to(CGPoint point)
|
142
|
+
{
|
143
|
+
mouse_drag_to2(point, DEFAULT_DURATION);
|
144
|
+
}
|
145
|
+
|
146
|
+
|
147
|
+
void
|
148
|
+
mouse_scroll3(size_t amount, enum MouseMovementUnit units, double duration)
|
149
|
+
{
|
150
|
+
size_t steps = round(FPS * duration);
|
151
|
+
double current = 0.0;
|
152
|
+
double done = 0;
|
153
|
+
int32_t scroll = 0;
|
154
|
+
|
155
|
+
for (size_t step = 0; step < steps; step++) {
|
156
|
+
done = (double)(step+1) / (double)steps;
|
157
|
+
scroll = round((done - current) * amount);
|
158
|
+
POSTRELEASE(CGEventCreateScrollWheelEvent(nil, units, 1, scroll));
|
159
|
+
mouse_sleep(1);
|
160
|
+
current += (double)scroll / (double)amount;
|
161
|
+
}
|
162
|
+
}
|
163
|
+
|
164
|
+
void
|
165
|
+
mouse_scroll2(size_t amount, enum MouseMovementUnit units)
|
166
|
+
{
|
167
|
+
mouse_scroll3(amount, units, DEFAULT_DURATION);
|
168
|
+
}
|
169
|
+
|
170
|
+
void
|
171
|
+
mouse_scroll(size_t amount)
|
172
|
+
{
|
173
|
+
mouse_scroll2(amount, kMouseScrollByLine);
|
174
|
+
}
|
175
|
+
|
176
|
+
|
177
|
+
void
|
178
|
+
mouse_click_down3(CGPoint point, size_t sleep_quanta)
|
179
|
+
{
|
180
|
+
POSTRELEASE(NEW_EVENT(kCGEventLeftMouseDown, point, kCGMouseButtonLeft));
|
181
|
+
mouse_sleep(sleep_quanta);
|
182
|
+
}
|
183
|
+
|
184
|
+
void
|
185
|
+
mouse_click_down2(CGPoint point)
|
186
|
+
{
|
187
|
+
// TODO: replace constant 12 with something more abstract
|
188
|
+
mouse_click_down3(point, 12);
|
189
|
+
}
|
190
|
+
|
191
|
+
void
|
192
|
+
mouse_click_down()
|
193
|
+
{
|
194
|
+
mouse_click_down2(mouse_current_position());
|
195
|
+
}
|
196
|
+
|
197
|
+
|
198
|
+
void
|
199
|
+
mouse_click_up2(CGPoint point)
|
200
|
+
{
|
201
|
+
POSTRELEASE(NEW_EVENT(kCGEventLeftMouseUp, point, kCGMouseButtonLeft));
|
202
|
+
}
|
203
|
+
|
204
|
+
void
|
205
|
+
mouse_click_up()
|
206
|
+
{
|
207
|
+
mouse_click_up2(mouse_current_position());
|
208
|
+
}
|
209
|
+
|
210
|
+
|
211
|
+
void
|
212
|
+
mouse_click2(CGPoint point)
|
213
|
+
{
|
214
|
+
mouse_click_down2(point);
|
215
|
+
mouse_click_up2(point);
|
216
|
+
}
|
217
|
+
|
218
|
+
void
|
219
|
+
mouse_click()
|
220
|
+
{
|
221
|
+
mouse_click2(mouse_current_position());
|
222
|
+
}
|
223
|
+
|
224
|
+
|
225
|
+
void
|
226
|
+
mouse_secondary_click3(CGPoint point, size_t sleep_quanta)
|
227
|
+
{
|
228
|
+
CGEventRef base_event = NEW_EVENT(
|
229
|
+
kCGEventRightMouseDown,
|
230
|
+
point,
|
231
|
+
kCGMouseButtonRight
|
232
|
+
);
|
233
|
+
POST(base_event);
|
234
|
+
mouse_sleep(sleep_quanta);
|
235
|
+
|
236
|
+
CHANGE(base_event, kCGEventRightMouseUp);
|
237
|
+
POSTRELEASE(base_event);
|
238
|
+
}
|
239
|
+
|
240
|
+
void
|
241
|
+
mouse_secondary_click2(CGPoint point)
|
242
|
+
{
|
243
|
+
// TODO: replace constant 12 with something more abstract
|
244
|
+
mouse_secondary_click3(point, 12);
|
245
|
+
}
|
246
|
+
|
247
|
+
void
|
248
|
+
mouse_secondary_click()
|
249
|
+
{
|
250
|
+
mouse_secondary_click2(mouse_current_position());
|
251
|
+
}
|
252
|
+
|
253
|
+
|
254
|
+
void
|
255
|
+
mouse_arbitrary_click3(CGEventMouseSubtype button, CGPoint point, size_t sleep_quanta)
|
256
|
+
{
|
257
|
+
CGEventRef base_event = NEW_EVENT(
|
258
|
+
kCGEventOtherMouseDown,
|
259
|
+
point,
|
260
|
+
button
|
261
|
+
);
|
262
|
+
POST(base_event);
|
263
|
+
mouse_sleep(sleep_quanta);
|
264
|
+
CHANGE(base_event, kCGEventOtherMouseUp);
|
265
|
+
POSTRELEASE(base_event);
|
266
|
+
}
|
267
|
+
|
268
|
+
void
|
269
|
+
mouse_arbitrary_click2(CGEventMouseSubtype button, CGPoint point)
|
270
|
+
{
|
271
|
+
mouse_arbitrary_click3(button, point, 12);
|
272
|
+
}
|
273
|
+
|
274
|
+
void
|
275
|
+
mouse_arbitrary_click(CGEventMouseSubtype button)
|
276
|
+
{
|
277
|
+
mouse_arbitrary_click2(button, mouse_current_position());
|
278
|
+
}
|
279
|
+
|
280
|
+
|
281
|
+
void
|
282
|
+
mouse_middle_click2(CGPoint point)
|
283
|
+
{
|
284
|
+
mouse_arbitrary_click2(kCGMouseButtonCenter, point);
|
285
|
+
}
|
286
|
+
|
287
|
+
void
|
288
|
+
mouse_middle_click()
|
289
|
+
{
|
290
|
+
mouse_middle_click2(mouse_current_position());
|
291
|
+
}
|
292
|
+
|
293
|
+
|
294
|
+
void
|
295
|
+
mouse_multi_click2(size_t num_clicks, CGPoint point)
|
296
|
+
{
|
297
|
+
CGEventRef base_event = NEW_EVENT(
|
298
|
+
kCGEventLeftMouseDown,
|
299
|
+
point,
|
300
|
+
kCGMouseButtonLeft
|
301
|
+
);
|
302
|
+
CGEventSetIntegerValueField(base_event, kCGMouseEventClickState, num_clicks);
|
303
|
+
|
304
|
+
CHANGE(base_event, kCGEventLeftMouseDown);
|
305
|
+
POST(base_event);
|
306
|
+
|
307
|
+
CHANGE(base_event, kCGEventLeftMouseUp);
|
308
|
+
POSTRELEASE(base_event);
|
309
|
+
}
|
310
|
+
|
311
|
+
void
|
312
|
+
mouse_multi_click(size_t num_clicks)
|
313
|
+
{
|
314
|
+
mouse_multi_click2(num_clicks, mouse_current_position());
|
315
|
+
}
|
316
|
+
|
317
|
+
|
318
|
+
void
|
319
|
+
mouse_double_click2(CGPoint point)
|
320
|
+
{
|
321
|
+
// some apps still expect to receive the single click event first
|
322
|
+
// and then the double click event
|
323
|
+
mouse_multi_click2(1, point);
|
324
|
+
mouse_multi_click2(2, point);
|
325
|
+
}
|
326
|
+
|
327
|
+
void
|
328
|
+
mouse_double_click()
|
329
|
+
{
|
330
|
+
mouse_double_click2(mouse_current_position());
|
331
|
+
}
|
332
|
+
|
333
|
+
|
334
|
+
void
|
335
|
+
mouse_triple_click2(CGPoint point)
|
336
|
+
{
|
337
|
+
// some apps still expect to receive the single click event first
|
338
|
+
// and then the double and triple click events
|
339
|
+
mouse_double_click2(point);
|
340
|
+
mouse_multi_click2(3, point);
|
341
|
+
}
|
342
|
+
|
343
|
+
void
|
344
|
+
mouse_triple_click()
|
345
|
+
{
|
346
|
+
mouse_triple_click2(mouse_current_position());
|
347
|
+
}
|
data/ext/mouse/mouser.h
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
//
|
2
|
+
// Mouser.h
|
3
|
+
// MRMouse
|
4
|
+
//
|
5
|
+
// Created by Mark Rada on 12-03-17.
|
6
|
+
// Copyright (c) 2012 Mark Rada. All rights reserved.
|
7
|
+
//
|
8
|
+
|
9
|
+
#include <ApplicationServices/ApplicationServices.h>
|
10
|
+
|
11
|
+
enum MouseMovementUnit {
|
12
|
+
kMouseScrollByLine = kCGScrollEventUnitLine,
|
13
|
+
// TODO: might not be real pixels, might be Cocoa co-ords, need to investigate
|
14
|
+
kMouseScrollByPixel = kCGScrollEventUnitPixel
|
15
|
+
};
|
16
|
+
|
17
|
+
|
18
|
+
CGPoint mouse_current_position();
|
19
|
+
|
20
|
+
void mouse_move_to(CGPoint point);
|
21
|
+
void mouse_move_to2(CGPoint point, double duration);
|
22
|
+
|
23
|
+
void mouse_drag_to(CGPoint point);
|
24
|
+
void mouse_drag_to2(CGPoint point, double duration);
|
25
|
+
|
26
|
+
void mouse_scroll(size_t amount);
|
27
|
+
void mouse_scroll2(size_t amount, enum MouseMovementUnit units);
|
28
|
+
void mouse_scroll3(size_t amount, enum MouseMovementUnit units, double duration);
|
29
|
+
|
30
|
+
void mouse_click_down();
|
31
|
+
void mouse_click_down2(CGPoint point);
|
32
|
+
void mouse_click_down3(CGPoint point, size_t sleep_quanta);
|
33
|
+
|
34
|
+
void mouse_click_up();
|
35
|
+
void mouse_click_up2(CGPoint point);
|
36
|
+
|
37
|
+
void mouse_click();
|
38
|
+
void mouse_click2(CGPoint point);
|
39
|
+
|
40
|
+
void mouse_secondary_click();
|
41
|
+
void mouse_secondary_click2(CGPoint point);
|
42
|
+
void mouse_secondary_click3(CGPoint point, size_t sleep_quanta);
|
43
|
+
|
44
|
+
void mouse_arbitrary_click(CGEventMouseSubtype button);
|
45
|
+
void mouse_arbitrary_click2(CGEventMouseSubtype button, CGPoint point);
|
46
|
+
void mouse_arbitrary_click3(CGEventMouseSubtype button, CGPoint point, size_t sleep_quanta);
|
47
|
+
|
48
|
+
void mouse_middle_click();
|
49
|
+
void mouse_middle_click2(CGPoint point);
|
50
|
+
|
51
|
+
void mouse_multi_click(size_t num_clicks);
|
52
|
+
void mouse_multi_click2(size_t num_clicks, CGPoint point);
|
53
|
+
|
54
|
+
void mouse_double_click();
|
55
|
+
void mouse_double_click2(CGPoint point);
|
56
|
+
|
57
|
+
void mouse_triple_click();
|
58
|
+
void mouse_triple_click2(CGPoint point);
|
data/lib/mouse.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
if RUBY_ENGINE == 'macruby'
|
2
|
+
|
3
|
+
framework '/System/Library/Frameworks/CoreGraphics.framework'
|
4
|
+
|
5
|
+
else
|
6
|
+
|
7
|
+
##
|
8
|
+
#
|
9
|
+
class CGPoint < Struct.new(:x, :y)
|
10
|
+
##
|
11
|
+
# Return a nice string representation of the point
|
12
|
+
#
|
13
|
+
# Overrides `Object#inspect` to more closely mimic MacRuby `Boxed#inspect`.
|
14
|
+
#
|
15
|
+
# @return [String]
|
16
|
+
def inspect
|
17
|
+
"#<CGPoint x=#{self[:x]} y=#{self[:y]}>"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
##
|
25
|
+
# Mouse extensions to `CGPoint`
|
26
|
+
class CGPoint
|
27
|
+
##
|
28
|
+
# Returns the receiver, since the receiver is already a {CGPoint}
|
29
|
+
#
|
30
|
+
# @return [CGPoint]
|
31
|
+
def to_point
|
32
|
+
self
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Mouse extensions to `Array`
|
38
|
+
class Array
|
39
|
+
##
|
40
|
+
# Coerce the first two elements of the receiver into a {CGPoint}
|
41
|
+
#
|
42
|
+
# @return [CGPoint]
|
43
|
+
def to_point
|
44
|
+
CGPoint.new self[0], self[1]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
require 'mouse.bundle'
|
data/test/helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mouse
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Mark Rada
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-02 00:00:00 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: yard
|
16
|
+
prerelease: false
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.8.3
|
23
|
+
type: :development
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.8.3
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: kramdown
|
32
|
+
prerelease: false
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ~>
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: 0.14.1
|
39
|
+
type: :development
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.14.1
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake-compiler
|
48
|
+
prerelease: false
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.8.1
|
55
|
+
type: :development
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.8.1
|
62
|
+
description: 'mouse is a rich, high level wrapper around OS X CGEvent APIs that allow
|
63
|
+
|
64
|
+
programmatic manipulation of the mouse cursor.
|
65
|
+
|
66
|
+
|
67
|
+
Originally extracted from the AXElements project.
|
68
|
+
|
69
|
+
'
|
70
|
+
email: markrada26@gmail.com
|
71
|
+
executables: []
|
72
|
+
extensions:
|
73
|
+
- ext/mouse/extconf.rb
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- lib/mouse/version.rb
|
77
|
+
- lib/mouse.rb
|
78
|
+
- ext/mouse/mouse.c
|
79
|
+
- ext/mouse/mouser.c
|
80
|
+
- ext/mouse/mouser.h
|
81
|
+
- ext/mouse/extconf.rb
|
82
|
+
- Rakefile
|
83
|
+
- README.markdown
|
84
|
+
- History.markdown
|
85
|
+
- .yardopts
|
86
|
+
- test/helper.rb
|
87
|
+
homepage: http://github.com/ferrous26/MRMouse
|
88
|
+
licenses:
|
89
|
+
- BSD 3-clause
|
90
|
+
post_install_message:
|
91
|
+
rdoc_options: []
|
92
|
+
require_paths:
|
93
|
+
- lib
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - '>='
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: "0"
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
none: false
|
102
|
+
requirements:
|
103
|
+
- - '>='
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: "0"
|
106
|
+
requirements: []
|
107
|
+
rubyforge_project:
|
108
|
+
rubygems_version: 1.8.24
|
109
|
+
signing_key:
|
110
|
+
specification_version: 3
|
111
|
+
summary: A library for automating the mouse
|
112
|
+
test_files:
|
113
|
+
- test/helper.rb
|