mac-event-monitor 0.1.0 → 0.2.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/README.md +14 -1
- data/ext/event_monitor/event_monitor.h +1 -1
- data/ext/event_monitor/event_monitor.m +18 -1
- data/lib/mac-event-monitor/event/keyboard_event.rb +6 -2
- data/lib/mac-event-monitor/event/mouse_event.rb +6 -9
- data/lib/mac-event-monitor/event.rb +33 -16
- data/lib/mac-event-monitor/location.rb +18 -0
- data/lib/mac-event-monitor/monitor.rb +15 -6
- data/lib/mac-event-monitor/serializable.rb +22 -0
- data/lib/mac-event-monitor/version.rb +1 -1
- data/lib/mac-event-monitor.rb +2 -0
- data/mac-event-monitor.gemspec +2 -0
- data/spec/mac-event-monitor/event_spec.rb +49 -14
- data/spec/mac-event-monitor/monitor_spec.rb +35 -1
- metadata +38 -4
data/README.md
CHANGED
@@ -9,13 +9,26 @@ A Library to Monitor User Interactions
|
|
9
9
|
## Usage
|
10
10
|
|
11
11
|
require 'mac-event-monitor'
|
12
|
-
|
12
|
+
|
13
13
|
monitor = Mac::EventMonitor::Monitor.new
|
14
|
+
|
15
|
+
### Monitor Mouse Event
|
16
|
+
|
14
17
|
monitor.add_listener(:mouse_down) do |event|
|
15
18
|
puts [event.location.x, event.location.y].join(',')
|
16
19
|
end
|
17
20
|
monitor.run
|
18
21
|
|
22
|
+
### Monitor Keyboard Event
|
23
|
+
|
24
|
+
You need to enable "Access to assistive devices" in the Universal Access preference pane to monitor keyboard event.
|
25
|
+
|
26
|
+
monitor.add_listener(:key_down) do |event|
|
27
|
+
p event.keycode
|
28
|
+
p event.shift_key?
|
29
|
+
end
|
30
|
+
monitor.run
|
31
|
+
|
19
32
|
## Contributing
|
20
33
|
|
21
34
|
1. Fork it
|
@@ -29,6 +29,7 @@ NSEventMask mask =
|
|
29
29
|
NSEvent *event;
|
30
30
|
|
31
31
|
[NSEvent removeMonitor:[timer userInfo]];
|
32
|
+
[timer invalidate];
|
32
33
|
[timer release];
|
33
34
|
|
34
35
|
[[NSApplication sharedApplication] stop:nil];
|
@@ -49,6 +50,22 @@ NSEventMask mask =
|
|
49
50
|
|
50
51
|
@end
|
51
52
|
|
53
|
+
double getScreenHeight()
|
54
|
+
{
|
55
|
+
NSScreen *mainScreen = [NSScreen mainScreen];
|
56
|
+
NSScreen *firstScreen = [[NSScreen screens] objectAtIndex:0];
|
57
|
+
|
58
|
+
NSRect screenRect = [mainScreen visibleFrame];
|
59
|
+
double screenHeight = NSHeight(screenRect);
|
60
|
+
|
61
|
+
// http://stackoverflow.com/questions/3163343/how-can-i-detemine-which-screen-holds-the-menubar
|
62
|
+
if(mainScreen == firstScreen) {
|
63
|
+
screenHeight += 22;
|
64
|
+
}
|
65
|
+
|
66
|
+
return screenHeight;
|
67
|
+
}
|
68
|
+
|
52
69
|
static VALUE rb_cMonitor;
|
53
70
|
|
54
71
|
static VALUE cMonitor_run_app(int argc, VALUE *argv, VALUE self)
|
@@ -66,7 +83,7 @@ static VALUE cMonitor_run_app(int argc, VALUE *argv, VALUE self)
|
|
66
83
|
|
67
84
|
eventMonitor = [NSEvent addGlobalMonitorForEventsMatchingMask:mask
|
68
85
|
handler:^(NSEvent *incomingEvent) {
|
69
|
-
rb_funcall(self, rb_intern("receive_event"),
|
86
|
+
rb_funcall(self, rb_intern("receive_event"), 2, rb_str_new2([[incomingEvent description] UTF8String]), rb_float_new(getScreenHeight()));
|
70
87
|
}];
|
71
88
|
|
72
89
|
if(stopAfter != Qnil) {
|
@@ -3,8 +3,8 @@ module Mac
|
|
3
3
|
class KeyboardEvent < Event
|
4
4
|
attr_reader :keycode, :flags
|
5
5
|
|
6
|
-
def initialize(type, keycode, flags)
|
7
|
-
super(type)
|
6
|
+
def initialize(type, time, location, keycode, flags)
|
7
|
+
super(type, time, location)
|
8
8
|
|
9
9
|
@keycode = keycode.to_i
|
10
10
|
@flags = flags.to_i(16)
|
@@ -38,6 +38,10 @@ module Mac
|
|
38
38
|
check_flag(23)
|
39
39
|
end
|
40
40
|
|
41
|
+
def data
|
42
|
+
super + [keycode, flags.to_s(16)]
|
43
|
+
end
|
44
|
+
|
41
45
|
private
|
42
46
|
|
43
47
|
def check_flag(shift)
|
@@ -1,19 +1,16 @@
|
|
1
1
|
module Mac
|
2
2
|
module EventMonitor
|
3
3
|
class MouseEvent < Event
|
4
|
-
attr_reader :
|
4
|
+
attr_reader :button
|
5
5
|
|
6
|
-
def initialize(type,
|
7
|
-
super(type)
|
6
|
+
def initialize(type, time, location, button)
|
7
|
+
super(type, time, location)
|
8
8
|
|
9
|
-
@
|
10
|
-
@button = button
|
9
|
+
@button = button && button.to_sym
|
11
10
|
end
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
def parse_location(location_as_str)
|
16
|
-
Struct.new(:x, :y).new(*location_as_str.scan(/[\d\.]+/).map {|v| v.to_f })
|
12
|
+
def data
|
13
|
+
super + [button]
|
17
14
|
end
|
18
15
|
end
|
19
16
|
end
|
@@ -1,10 +1,12 @@
|
|
1
1
|
module Mac
|
2
2
|
module EventMonitor
|
3
3
|
class Event
|
4
|
-
|
4
|
+
include JsonSerializable
|
5
|
+
|
6
|
+
attr_reader :type, :time, :location
|
5
7
|
|
6
8
|
class << self
|
7
|
-
def create_from_description(description)
|
9
|
+
def create_from_description(description, screen_height)
|
8
10
|
_, *atts_as_string = description.split(/ +/)
|
9
11
|
|
10
12
|
attrs = (atts_as_string.join(' ') + ' ').scan(/([^=]+)=([^=]+) (?=\w?)/).inject({}) do |result, pair|
|
@@ -13,37 +15,52 @@ module Mac
|
|
13
15
|
result
|
14
16
|
end
|
15
17
|
|
18
|
+
location = parse_location(attrs[:loc])
|
19
|
+
location.y = screen_height - location.y
|
20
|
+
|
21
|
+
time = attrs[:time].to_f
|
22
|
+
|
16
23
|
case attrs[:type]
|
17
24
|
when 'LMouseUp'
|
18
|
-
MouseEvent.new(:mouse_up,
|
25
|
+
MouseEvent.new(:mouse_up, time, location, :left)
|
19
26
|
when 'RMouseUp'
|
20
|
-
MouseEvent.new(:mouse_up,
|
27
|
+
MouseEvent.new(:mouse_up, time, location, :right)
|
21
28
|
when 'OMouseUp'
|
22
|
-
MouseEvent.new(:mouse_up,
|
29
|
+
MouseEvent.new(:mouse_up, time, location, :other)
|
23
30
|
when 'LMouseDown'
|
24
|
-
MouseEvent.new(:mouse_down,
|
31
|
+
MouseEvent.new(:mouse_down, time, location, :left)
|
25
32
|
when 'RMouseDown'
|
26
|
-
MouseEvent.new(:mouse_down,
|
33
|
+
MouseEvent.new(:mouse_down, time, location, :right)
|
27
34
|
when 'OMouseDown'
|
28
|
-
MouseEvent.new(:mouse_down,
|
35
|
+
MouseEvent.new(:mouse_down, time, location, :other)
|
29
36
|
when 'MouseMoved'
|
30
|
-
MouseEvent.new(:mouse_move,
|
37
|
+
MouseEvent.new(:mouse_move, time, location, nil)
|
31
38
|
when 'LMouseDragged'
|
32
|
-
MouseEvent.new(:mouse_drag,
|
39
|
+
MouseEvent.new(:mouse_drag, time, location, :left)
|
33
40
|
when 'RMouseDragged'
|
34
|
-
MouseEvent.new(:mouse_drag,
|
41
|
+
MouseEvent.new(:mouse_drag, time, location, :right)
|
35
42
|
when 'OMouseDragged'
|
36
|
-
MouseEvent.new(:mouse_drag,
|
43
|
+
MouseEvent.new(:mouse_drag, time, location, :other)
|
37
44
|
when 'KeyDown'
|
38
|
-
KeyboardEvent.new(:key_down, attrs[:keyCode], attrs[:flags])
|
45
|
+
KeyboardEvent.new(:key_down, time, location, attrs[:keyCode], attrs[:flags])
|
39
46
|
when 'KeyUp'
|
40
|
-
KeyboardEvent.new(:key_up, attrs[:keyCode], attrs[:flags])
|
47
|
+
KeyboardEvent.new(:key_up, time, location, attrs[:keyCode], attrs[:flags])
|
41
48
|
end
|
42
49
|
end
|
50
|
+
|
51
|
+
def parse_location(location_as_str)
|
52
|
+
Location.new(*location_as_str.scan(/[\d\.]+/).map {|v| v.to_f })
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize(type, time, location)
|
57
|
+
@type = type.to_sym
|
58
|
+
@time = time
|
59
|
+
@location = location
|
43
60
|
end
|
44
61
|
|
45
|
-
def
|
46
|
-
|
62
|
+
def data
|
63
|
+
[type, time, location]
|
47
64
|
end
|
48
65
|
end
|
49
66
|
end
|
@@ -2,24 +2,33 @@ module Mac
|
|
2
2
|
module EventMonitor
|
3
3
|
class Monitor
|
4
4
|
def initialize
|
5
|
-
@listeners
|
5
|
+
@listeners = {}
|
6
|
+
@any_listeners = []
|
6
7
|
end
|
7
8
|
|
8
|
-
def add_listener(type, &block)
|
9
|
-
|
10
|
-
|
9
|
+
def add_listener(type = nil, &block)
|
10
|
+
if type
|
11
|
+
@listeners[type] ||= []
|
12
|
+
@listeners[type] << block
|
13
|
+
else
|
14
|
+
@any_listeners << block
|
15
|
+
end
|
11
16
|
end
|
12
17
|
|
13
18
|
def run(stop_after = nil)
|
14
19
|
run_app(stop_after)
|
15
20
|
end
|
16
21
|
|
17
|
-
def receive_event(str)
|
18
|
-
event = Event.create_from_description(str)
|
22
|
+
def receive_event(str, screen_height)
|
23
|
+
event = Event.create_from_description(str, screen_height)
|
19
24
|
|
20
25
|
(@listeners[event.type] || []).each do |block|
|
21
26
|
block.call(event)
|
22
27
|
end
|
28
|
+
|
29
|
+
@any_listeners.each do |block|
|
30
|
+
block.call(event)
|
31
|
+
end
|
23
32
|
end
|
24
33
|
end
|
25
34
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Mac
|
4
|
+
module EventMonitor
|
5
|
+
module JsonSerializable
|
6
|
+
def self.included(klass)
|
7
|
+
klass.instance_eval do
|
8
|
+
def json_create(o)
|
9
|
+
new(*o['data'])
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_json(*a)
|
15
|
+
{
|
16
|
+
'json_class' => self.class.name,
|
17
|
+
'data' => data
|
18
|
+
}.to_json(*a)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/mac-event-monitor.rb
CHANGED
@@ -6,7 +6,9 @@ module Mac
|
|
6
6
|
end
|
7
7
|
|
8
8
|
require 'event_monitor'
|
9
|
+
require 'mac-event-monitor/serializable.rb'
|
9
10
|
require 'mac-event-monitor/monitor.rb'
|
10
11
|
require 'mac-event-monitor/event.rb'
|
11
12
|
require 'mac-event-monitor/event/mouse_event.rb'
|
12
13
|
require 'mac-event-monitor/event/keyboard_event.rb'
|
14
|
+
require 'mac-event-monitor/location.rb'
|
data/mac-event-monitor.gemspec
CHANGED
@@ -16,7 +16,9 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.require_paths = ["lib"]
|
17
17
|
gem.version = Mac::EventMonitor::VERSION
|
18
18
|
|
19
|
+
gem.add_dependency('json')
|
19
20
|
gem.add_development_dependency('rspec', ['~> 2.8.0'])
|
20
21
|
gem.add_development_dependency('mac-robot')
|
21
22
|
gem.add_development_dependency('eventmachine')
|
23
|
+
gem.add_development_dependency('rake')
|
22
24
|
end
|
@@ -1,24 +1,59 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
2
|
|
3
|
+
require 'json'
|
4
|
+
|
3
5
|
include Mac::EventMonitor
|
4
6
|
|
5
7
|
describe Event do
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
describe '.create_from_description' do
|
9
|
+
it 'should create event from description' do
|
10
|
+
event = Event.create_from_description('NSEvent: type=LMouseDown loc=(618,524) time=1136789.4 flags=0x100 win=0x0 winNum=17310 ctxt=0x0 evNum=14883 click=1 buttonNumber=0 pressure=1', 768)
|
11
|
+
|
12
|
+
event.should be_an_instance_of(MouseEvent)
|
13
|
+
event.type.should equal(:mouse_down)
|
14
|
+
event.button.should equal(:left)
|
15
|
+
event.location.x.should eql(618.0)
|
16
|
+
event.location.y.should eql(244.0)
|
17
|
+
event.time.should eql(1136789.4)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should create event from description with space' do
|
21
|
+
event = Event.create_from_description('NSEvent: type=KeyDown loc=(184,646) time=68067.5 flags=0x20104 win=0x0 winNum=0 ctxt=0x0 chars=" " unmodchars=" " repeat=0 keyCode=49', 768)
|
22
|
+
|
23
|
+
event.should be_an_instance_of(KeyboardEvent)
|
24
|
+
event.type.should equal(:key_down)
|
25
|
+
event.keycode.should equal(49)
|
26
|
+
event.shift_key?.should be_true
|
27
|
+
event.location.x.should eql(184.0)
|
28
|
+
event.location.y.should eql(122.0)
|
29
|
+
event.time.should eql(68067.5)
|
30
|
+
end
|
14
31
|
end
|
15
32
|
|
16
|
-
|
17
|
-
|
33
|
+
describe '#to_json' do
|
34
|
+
it 'serializes mouse event to json' do
|
35
|
+
event = Event.create_from_description('NSEvent: type=LMouseDown loc=(618,524) time=1136789.4 flags=0x100 win=0x0 winNum=17310 ctxt=0x0 evNum=14883 click=1 buttonNumber=0 pressure=1', 768)
|
36
|
+
event = JSON.parse(event.to_json)
|
37
|
+
|
38
|
+
event.should be_an_instance_of(MouseEvent)
|
39
|
+
event.type.should equal(:mouse_down)
|
40
|
+
event.button.should equal(:left)
|
41
|
+
event.location.x.should eql(618.0)
|
42
|
+
event.location.y.should eql(244.0)
|
43
|
+
event.time.should eql(1136789.4)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'serializes mouse event to json' do
|
47
|
+
event = Event.create_from_description('NSEvent: type=KeyDown loc=(184,646) time=68067.5 flags=0x20104 win=0x0 winNum=0 ctxt=0x0 chars=" " unmodchars=" " repeat=0 keyCode=49', 768)
|
48
|
+
event = JSON.parse(event.to_json)
|
18
49
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
50
|
+
event.should be_an_instance_of(KeyboardEvent)
|
51
|
+
event.type.should equal(:key_down)
|
52
|
+
event.keycode.should equal(49)
|
53
|
+
event.shift_key?.should be_true
|
54
|
+
event.location.x.should eql(184.0)
|
55
|
+
event.location.y.should eql(122.0)
|
56
|
+
event.time.should eql(68067.5)
|
57
|
+
end
|
23
58
|
end
|
24
59
|
end
|
@@ -50,7 +50,6 @@ describe Monitor do
|
|
50
50
|
[1, 1.5].each do |t|
|
51
51
|
EM.add_timer(t) do
|
52
52
|
robot.key_press(0x04)
|
53
|
-
#robot.key_release(0x04)
|
54
53
|
end
|
55
54
|
end
|
56
55
|
|
@@ -65,4 +64,39 @@ describe Monitor do
|
|
65
64
|
|
66
65
|
result.should be >= 2
|
67
66
|
end
|
67
|
+
|
68
|
+
it 'should monitor all' do
|
69
|
+
result = 0
|
70
|
+
robot = Mac::Robot.new
|
71
|
+
|
72
|
+
@monitor.add_listener do |event|
|
73
|
+
result += 1
|
74
|
+
end
|
75
|
+
|
76
|
+
result.should be_zero
|
77
|
+
|
78
|
+
EM.run do
|
79
|
+
[1, 1.5].each do |t|
|
80
|
+
EM.add_timer(t) do
|
81
|
+
robot.mouse_press
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
[2, 2.5].each do |t|
|
86
|
+
EM.add_timer(t) do
|
87
|
+
robot.key_press(0x04)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
EM.add_timer(3) do
|
92
|
+
EM.stop
|
93
|
+
end
|
94
|
+
|
95
|
+
EM.add_periodic_timer(0.1) do
|
96
|
+
@monitor.run(0.1)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
result.should be >= 4
|
101
|
+
end
|
68
102
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mac-event-monitor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-03-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: json
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
14
30
|
- !ruby/object:Gem::Dependency
|
15
31
|
name: rspec
|
16
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -59,6 +75,22 @@ dependencies:
|
|
59
75
|
- - ! '>='
|
60
76
|
- !ruby/object:Gem::Version
|
61
77
|
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rake
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
62
94
|
description: A Library to Monitor User Interactions
|
63
95
|
email:
|
64
96
|
- youpy@buycheapviagraonlinenow.com
|
@@ -81,7 +113,9 @@ files:
|
|
81
113
|
- lib/mac-event-monitor/event.rb
|
82
114
|
- lib/mac-event-monitor/event/keyboard_event.rb
|
83
115
|
- lib/mac-event-monitor/event/mouse_event.rb
|
116
|
+
- lib/mac-event-monitor/location.rb
|
84
117
|
- lib/mac-event-monitor/monitor.rb
|
118
|
+
- lib/mac-event-monitor/serializable.rb
|
85
119
|
- lib/mac-event-monitor/version.rb
|
86
120
|
- mac-event-monitor.gemspec
|
87
121
|
- spec/mac-event-monitor/event_spec.rb
|
@@ -101,7 +135,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
101
135
|
version: '0'
|
102
136
|
segments:
|
103
137
|
- 0
|
104
|
-
hash:
|
138
|
+
hash: 420514610567595612
|
105
139
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
140
|
none: false
|
107
141
|
requirements:
|
@@ -110,7 +144,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
110
144
|
version: '0'
|
111
145
|
segments:
|
112
146
|
- 0
|
113
|
-
hash:
|
147
|
+
hash: 420514610567595612
|
114
148
|
requirements: []
|
115
149
|
rubyforge_project:
|
116
150
|
rubygems_version: 1.8.24
|