AXElements 1.0.0.alpha8 → 1.0.0.alpha9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.markdown +7 -0
- data/README.markdown +4 -7
- data/lib/accessibility/core.rb +0 -3
- data/lib/accessibility/dsl.rb +5 -4
- data/lib/accessibility/version.rb +1 -1
- data/lib/ax/application.rb +49 -0
- data/lib/ax/systemwide.rb +27 -0
- data/lib/ax_elements/core_graphics_workaround.rb +1 -1
- metadata +36 -5
- data/lib/accessibility/screen_recorder.rb +0 -217
data/History.markdown
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
# 1.0.0
|
2
2
|
|
3
3
|
* Added History.markdown to track notable changes
|
4
|
+
* Added `Application.frontmost_application`
|
5
|
+
* Added `Application.menu_bar_owner`
|
6
|
+
* Added `SystemWide.status_bar_items`
|
7
|
+
* Added `SystemWide.desktop`
|
8
|
+
* Added `Application.finder`
|
9
|
+
* Added `Application.dock`
|
10
|
+
* Added `DSL#record` to run a screen recording of the given block
|
4
11
|
|
5
12
|
* Ported `mouse.rb` to C and moved code to [MRMouse](https://github.com/ferrous26/MRMouse)
|
6
13
|
|
data/README.markdown
CHANGED
@@ -64,13 +64,10 @@ The code from the demo video is right here:
|
|
64
64
|
|
65
65
|
## Getting Setup
|
66
66
|
|
67
|
-
You need
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
you should install MacRuby, version 0.12 or newer is required. If you
|
72
|
-
are on Snow Leopard, you will also need to install the
|
73
|
-
[Bridge Support Preview](http://www.macruby.org/blog/2010/10/08/bridgesupport-preview.html).
|
67
|
+
You will need a MacRuby nightly build for installation. You can get help setting
|
68
|
+
up by referencing the
|
69
|
+
[Setup MacRuby](https://github.com/MacRuby/MacRuby/wiki/Setting-up-MacRuby)
|
70
|
+
guide on Github.
|
74
71
|
|
75
72
|
You will also need to make sure you "enable access for assistive devices".
|
76
73
|
This can be done in System Preferences in the Universal Access section:
|
data/lib/accessibility/core.rb
CHANGED
@@ -914,9 +914,6 @@ class NSArray
|
|
914
914
|
def to_size; CGSize.new(first, at(1)) end
|
915
915
|
# @return [CGRect]
|
916
916
|
def to_rect; CGRectMake(*self[0..3]) end
|
917
|
-
##
|
918
|
-
# Override `super` to exploit trivial parallelism.
|
919
|
-
#
|
920
917
|
# @return [Array]
|
921
918
|
def to_ruby
|
922
919
|
map do |obj| obj.to_ruby end
|
data/lib/accessibility/dsl.rb
CHANGED
@@ -693,16 +693,17 @@ module Accessibility::DSL
|
|
693
693
|
alias_method :capture_screen, :screenshot
|
694
694
|
|
695
695
|
##
|
696
|
-
# See
|
696
|
+
# See (ScreenRecorder)[http://rdoc.info/gems/screen_recorder/frames]
|
697
|
+
# for details on the screen recording options
|
697
698
|
#
|
698
699
|
# @param file [String]
|
699
700
|
# @return [String]
|
700
701
|
def record file = nil, &block
|
701
|
-
require '
|
702
|
+
require 'screen_recorder'
|
702
703
|
if file
|
703
|
-
|
704
|
+
ScreenRecorder.record file, &block
|
704
705
|
else
|
705
|
-
|
706
|
+
ScreenRecorder.record &block
|
706
707
|
end
|
707
708
|
end
|
708
709
|
|
data/lib/ax/application.rb
CHANGED
@@ -23,6 +23,55 @@ class AX::Application < AX::Element
|
|
23
23
|
additionalEventParamDescriptor: nil,
|
24
24
|
launchIdentifier: nil
|
25
25
|
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Find and return the dock application
|
29
|
+
#
|
30
|
+
# @return [AX::Application]
|
31
|
+
def dock
|
32
|
+
new 'com.apple.dock'
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Find and return the dock application
|
37
|
+
#
|
38
|
+
# @return [AX::Application]
|
39
|
+
def finder
|
40
|
+
new 'com.apple.finder'
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Find and return the notification center UI app
|
45
|
+
#
|
46
|
+
# Obviously, this will only work on OS X 10.8+
|
47
|
+
#
|
48
|
+
# @return [AX::Application]
|
49
|
+
def notification_center
|
50
|
+
new 'com.apple.notificationcenterui'
|
51
|
+
end
|
52
|
+
|
53
|
+
##
|
54
|
+
# Find and return the application which is frontmost
|
55
|
+
#
|
56
|
+
# This is often, but not necessarily, the same as the app that
|
57
|
+
# owns the menu bar.
|
58
|
+
#
|
59
|
+
# @return [AX::Application]
|
60
|
+
def frontmost_application
|
61
|
+
new NSWorkspace.sharedWorkspace.frontmostApplication
|
62
|
+
end
|
63
|
+
alias_method :frontmost_app, :frontmost_application
|
64
|
+
|
65
|
+
##
|
66
|
+
# Find and return the application which owns the menu bar
|
67
|
+
#
|
68
|
+
# This is often, but not necessarily, the same as the app that
|
69
|
+
# is frontmost.
|
70
|
+
#
|
71
|
+
# @return [AX::Application]
|
72
|
+
def menu_bar_owner
|
73
|
+
new NSWorkspace.sharedWorkspace.menuBarOwningApplication
|
74
|
+
end
|
26
75
|
end
|
27
76
|
|
28
77
|
##
|
data/lib/ax/systemwide.rb
CHANGED
@@ -11,6 +11,33 @@ require 'accessibility/string'
|
|
11
11
|
class AX::SystemWide < AX::Element
|
12
12
|
include Accessibility::String
|
13
13
|
|
14
|
+
class << self
|
15
|
+
##
|
16
|
+
# Find and return the group that represents the dock
|
17
|
+
#
|
18
|
+
# @return [AX::Group]
|
19
|
+
def desktop
|
20
|
+
AX::Application.finder.scroll_areas.first.groups.first
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# @note This currently does not include spotlight or the
|
25
|
+
# notification center as they interact oddly with
|
26
|
+
# accessibility APIs and how AXElements handle errors
|
27
|
+
#
|
28
|
+
# Find and return menu bar items for the system
|
29
|
+
#
|
30
|
+
# That is, menu bar items that do not belong to the current
|
31
|
+
# app, but that belong to the system, such as the clock or
|
32
|
+
# wi-fi menu.
|
33
|
+
#
|
34
|
+
# @return [AX::MenuBarItem]
|
35
|
+
def status_items
|
36
|
+
AX::Application.new('SystemUIServer').menu_bar.children
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
14
41
|
##
|
15
42
|
# Overridden since there is only one way to get the element ref.
|
16
43
|
def initialize
|
metadata
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
name: AXElements
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease: 6
|
5
|
-
version: 1.0.0.
|
5
|
+
version: 1.0.0.alpha9
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Mark Rada
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-12-
|
12
|
+
date: 2012-12-11 00:00:00 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: mouse
|
@@ -19,14 +19,46 @@ dependencies:
|
|
19
19
|
requirements:
|
20
20
|
- - ~>
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 1.0.
|
22
|
+
version: 1.0.2
|
23
23
|
type: :runtime
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
none: false
|
26
26
|
requirements:
|
27
27
|
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 1.0.
|
29
|
+
version: 1.0.2
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: screen_recorder
|
32
|
+
prerelease: false
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ~>
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: 0.1.3
|
39
|
+
type: :runtime
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.1.3
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: minitest
|
48
|
+
prerelease: false
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "4.3"
|
55
|
+
type: :development
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "4.3"
|
30
62
|
- !ruby/object:Gem::Dependency
|
31
63
|
name: yard
|
32
64
|
prerelease: false
|
@@ -81,7 +113,6 @@ files:
|
|
81
113
|
- lib/accessibility/highlighter.rb
|
82
114
|
- lib/accessibility/pretty_printer.rb
|
83
115
|
- lib/accessibility/qualifier.rb
|
84
|
-
- lib/accessibility/screen_recorder.rb
|
85
116
|
- lib/accessibility/statistics.rb
|
86
117
|
- lib/accessibility/string.rb
|
87
118
|
- lib/accessibility/translator.rb
|
@@ -1,217 +0,0 @@
|
|
1
|
-
framework 'AVFoundation'
|
2
|
-
require 'accessibility/version'
|
3
|
-
require 'ax_elements/core_graphics_workaround'
|
4
|
-
|
5
|
-
##
|
6
|
-
# Screen recordings, easy as pie.
|
7
|
-
#
|
8
|
-
# Things that you need to be concerned about:
|
9
|
-
# - screen going to sleep
|
10
|
-
# - short recordings (~1 second) don't work too well; it looks like
|
11
|
-
# the last bit of the buffer does not get saved so the last ~0.5
|
12
|
-
# seconds are not saved to disk (we could add a 0.5 second sleep)
|
13
|
-
# - small memory leak when a recording starts on Mountain Lion (GC)
|
14
|
-
# - constantly leaking memory during recording on Lion (GC)
|
15
|
-
# - run loop hack is not needed if code is already being called from
|
16
|
-
# in a run loop
|
17
|
-
# - pausing is not working...not sure why
|
18
|
-
#
|
19
|
-
class Accessibility::ScreenRecorder
|
20
|
-
|
21
|
-
##
|
22
|
-
# Record the screen while executing the given block. The path to the
|
23
|
-
# recording will be returned.
|
24
|
-
#
|
25
|
-
# The recorder object is yielded.
|
26
|
-
#
|
27
|
-
# @yield
|
28
|
-
# @yieldparam recorder [ScreenRecorder]
|
29
|
-
# @return [String]
|
30
|
-
def self.record file_name = nil
|
31
|
-
raise 'block required' unless block_given?
|
32
|
-
|
33
|
-
recorder = new
|
34
|
-
file_name ? recorder.start(file_name) : recorder.start
|
35
|
-
yield recorder
|
36
|
-
recorder.file
|
37
|
-
|
38
|
-
ensure
|
39
|
-
recorder.stop
|
40
|
-
end
|
41
|
-
|
42
|
-
##
|
43
|
-
# Path to the screen recording. This is `nil` until the screen
|
44
|
-
# recording begins.
|
45
|
-
#
|
46
|
-
# @return [String]
|
47
|
-
attr_reader :file
|
48
|
-
|
49
|
-
##
|
50
|
-
# @todo Expose configuration options at initialie time
|
51
|
-
def initialize
|
52
|
-
@session = AVCaptureSession.alloc.init
|
53
|
-
|
54
|
-
@input = AVCaptureScreenInput.alloc.initWithDisplayID CGMainDisplayID()
|
55
|
-
@input.capturesMouseClicks = true
|
56
|
-
|
57
|
-
@output = AVCaptureMovieFileOutput.alloc.init
|
58
|
-
@output.setDelegate self
|
59
|
-
|
60
|
-
@session.addInput @input
|
61
|
-
@session.addOutput @output
|
62
|
-
|
63
|
-
@sema = Dispatch::Semaphore.new 0
|
64
|
-
end
|
65
|
-
|
66
|
-
##
|
67
|
-
# Synchrnously start recording. You can optionally specify a file
|
68
|
-
# name for the recording; if you do not then a default name will be
|
69
|
-
# provided in the form `~/Movies/TestRecording-20121017123230.mov`
|
70
|
-
# (the timestamp will be different for you).
|
71
|
-
#
|
72
|
-
# @param file_name [String]
|
73
|
-
def start file_name = default_file_name
|
74
|
-
@file = default_file_name
|
75
|
-
file_url = NSURL.fileURLWithPath @file, isDirectory: false
|
76
|
-
|
77
|
-
@session.startRunning
|
78
|
-
@output.startRecordingToOutputFileURL file_url,
|
79
|
-
recordingDelegate: self
|
80
|
-
|
81
|
-
@sema.wait
|
82
|
-
end
|
83
|
-
|
84
|
-
##
|
85
|
-
# Whether or not the recording has begun. This will be `true`
|
86
|
-
# after calling {#start} until {#stop} is called. It will be
|
87
|
-
# `true` while the recording is paused.
|
88
|
-
def started?
|
89
|
-
@output.recording?
|
90
|
-
end
|
91
|
-
|
92
|
-
# ##
|
93
|
-
# # Whether or not the recording has been paused.
|
94
|
-
# def paused?
|
95
|
-
# @output.paused?
|
96
|
-
# end
|
97
|
-
|
98
|
-
##
|
99
|
-
# Duration of the recording, in seconds.
|
100
|
-
#
|
101
|
-
# @return [Float]
|
102
|
-
def length
|
103
|
-
duration = @output.recordedDuration
|
104
|
-
(duration.value.to_f / duration.timescale.to_f)
|
105
|
-
end
|
106
|
-
|
107
|
-
##
|
108
|
-
# Size of the recording on disk, in bytes.
|
109
|
-
#
|
110
|
-
# @return [Fixnum]
|
111
|
-
def size
|
112
|
-
@output.recordedFileSize
|
113
|
-
end
|
114
|
-
|
115
|
-
# ##
|
116
|
-
# # Synchronously pause the recording. You can optionally pass a block
|
117
|
-
# # to this method.
|
118
|
-
# #
|
119
|
-
# # If you pass a block, the recording is paused so that the block
|
120
|
-
# # can execute and recording resumes after the block finishes. If
|
121
|
-
# # you do not pass a block then the recording is paused until you
|
122
|
-
# # call {#resume} on the receiver.
|
123
|
-
# #
|
124
|
-
# # @yield Optionally pass a block
|
125
|
-
# def pause
|
126
|
-
# @output.pauseRecording
|
127
|
-
# wait_for_callback
|
128
|
-
# @sema.wait
|
129
|
-
|
130
|
-
# if block_given?
|
131
|
-
# yield
|
132
|
-
# resume
|
133
|
-
# end
|
134
|
-
# end
|
135
|
-
|
136
|
-
# ##
|
137
|
-
# # Synchronously resume a {#pause}d recording.
|
138
|
-
# def resume
|
139
|
-
# @output.resumeRecording
|
140
|
-
# wait_for_callback
|
141
|
-
# @sema.wait
|
142
|
-
# end
|
143
|
-
|
144
|
-
##
|
145
|
-
# Synchronously stop recording and finish up commiting any data to disk.
|
146
|
-
# A recording cannot be {#start}ed again after it has been stopped; if
|
147
|
-
# you want to pause a recording then you should use {#pause} instead.
|
148
|
-
def stop
|
149
|
-
@session.stopRunning
|
150
|
-
@output.stopRecording
|
151
|
-
@sema.wait
|
152
|
-
wait_for_callback
|
153
|
-
@sema.wait
|
154
|
-
end
|
155
|
-
|
156
|
-
|
157
|
-
# @!group AVCaptureFileOutputDelegate
|
158
|
-
|
159
|
-
def captureOutput captureOutput, didOutputSampleBuffer:sampleBuffer, fromConnection:connection
|
160
|
-
# gets called for every chunk of the recording getting committed to disk
|
161
|
-
end
|
162
|
-
|
163
|
-
def captureOutput captureOutput, didDropSampleBuffer:sampleBuffer, fromConnection:connection
|
164
|
-
NSLog("Error: dropped same data from recording")
|
165
|
-
end
|
166
|
-
|
167
|
-
|
168
|
-
# @!group AVCaptureFileOutputRecordingDelegate
|
169
|
-
|
170
|
-
def captureOutput captureOutput, didFinishRecordingToOutputFileAtURL:outputFileURL, fromConnections:connections, error:error
|
171
|
-
NSLog('Finishing')
|
172
|
-
CFRunLoopStop(CFRunLoopGetCurrent())
|
173
|
-
@sema.signal
|
174
|
-
end
|
175
|
-
|
176
|
-
def captureOutput captureOutput, didPauseRecordingToOutputFileAtURL:fileURL, fromConnections:connections
|
177
|
-
NSLog('Pausing')
|
178
|
-
CFRunLoopStop(CFRunLoopGetCurrent())
|
179
|
-
@sema.signal
|
180
|
-
end
|
181
|
-
|
182
|
-
def captureOutput captureOutput, didResumeRecordingToOutputFileAtURL:fileURL, fromConnections:connections
|
183
|
-
NSLog('Resuming')
|
184
|
-
CFRunLoopStop(CFRunLoopGetCurrent())
|
185
|
-
@sema.signal
|
186
|
-
end
|
187
|
-
|
188
|
-
def captureOutput captureOutput, didStartRecordingToOutputFileAtURL:fileURL, fromConnections:connections
|
189
|
-
NSLog('Starting')
|
190
|
-
@sema.signal
|
191
|
-
end
|
192
|
-
|
193
|
-
def captureOutput captureOutput, willFinishRecordingToOutputFileAtURL:fileURL, fromConnections:connections, error:error
|
194
|
-
NSLog('Will Finish')
|
195
|
-
@sema.signal
|
196
|
-
end
|
197
|
-
|
198
|
-
|
199
|
-
private
|
200
|
-
|
201
|
-
def default_file_name
|
202
|
-
date = Time.now.strftime '%Y%m%d%H%M%S'
|
203
|
-
File.expand_path("~/Movies/TestRecording-#{date}.mov")
|
204
|
-
end
|
205
|
-
|
206
|
-
def wait_for_callback
|
207
|
-
case CFRunLoopRunInMode(KCFRunLoopDefaultMode, 30, false)
|
208
|
-
when KCFRunLoopRunStopped
|
209
|
-
true
|
210
|
-
when KCFRunLoopRunTimedOut
|
211
|
-
raise 'did not get callback'
|
212
|
-
else
|
213
|
-
raise 'unexpected result from waiting for callback'
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
end
|