mouse 0.0.1
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/.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
|