AXElements 0.7.8 → 0.8.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/.yardopts +1 -10
- data/README.markdown +7 -14
- data/ext/accessibility/key_coder/key_coder.c +7 -0
- data/lib/AXElements.rb +0 -2
- data/lib/accessibility/core.rb +180 -123
- data/lib/accessibility/dsl.rb +310 -191
- data/lib/accessibility/enumerators.rb +9 -8
- data/lib/accessibility/errors.rb +7 -8
- data/lib/accessibility/factory.rb +16 -9
- data/lib/accessibility/graph.rb +68 -22
- data/lib/accessibility/highlighter.rb +86 -0
- data/lib/accessibility/pp_inspector.rb +4 -4
- data/lib/accessibility/qualifier.rb +11 -9
- data/lib/accessibility/string.rb +12 -4
- data/lib/accessibility/translator.rb +19 -10
- data/lib/accessibility/version.rb +3 -1
- data/lib/accessibility.rb +42 -17
- data/lib/ax/application.rb +90 -30
- data/lib/ax/button.rb +5 -2
- data/lib/ax/element.rb +133 -149
- data/lib/ax/pop_up_button.rb +12 -0
- data/lib/ax/radio_button.rb +5 -2
- data/lib/ax/row.rb +2 -2
- data/lib/ax/static_text.rb +5 -2
- data/lib/ax/systemwide.rb +24 -12
- data/lib/ax_elements/awesome_print.rb +13 -0
- data/lib/ax_elements/exception_workaround.rb +5 -0
- data/lib/ax_elements/nsarray_compat.rb +1 -0
- data/lib/ax_elements.rb +2 -1
- data/lib/minitest/ax_elements.rb +60 -4
- data/lib/mouse.rb +47 -20
- data/lib/rspec/expectations/ax_elements.rb +180 -88
- data/rakelib/doc.rake +7 -0
- data/test/helper.rb +2 -1
- data/test/integration/accessibility/test_dsl.rb +126 -18
- data/test/integration/accessibility/test_errors.rb +1 -1
- data/test/integration/ax/test_element.rb +17 -0
- data/test/integration/minitest/test_ax_elements.rb +33 -38
- data/test/integration/rspec/expectations/test_ax_elements.rb +68 -19
- data/test/sanity/accessibility/test_core.rb +45 -37
- data/test/sanity/accessibility/test_highlighter.rb +56 -0
- data/test/sanity/ax/test_application.rb +8 -0
- data/test/sanity/ax/test_element.rb +7 -3
- data/test/sanity/minitest/test_ax_elements.rb +2 -0
- data/test/sanity/rspec/expectations/test_ax_elements.rb +3 -0
- data/test/sanity/test_accessibility.rb +9 -0
- data/test/sanity/test_mouse.rb +2 -2
- metadata +11 -38
- data/docs/AccessibilityTips.markdown +0 -119
- data/docs/Acting.markdown +0 -340
- data/docs/Debugging.markdown +0 -165
- data/docs/Inspecting.markdown +0 -261
- data/docs/KeyboardEvents.markdown +0 -122
- data/docs/NewBehaviour.markdown +0 -151
- data/docs/Notifications.markdown +0 -271
- data/docs/Searching.markdown +0 -250
- data/docs/TestingExtensions.markdown +0 -52
- data/docs/images/all_the_buttons.jpg +0 -0
- data/docs/images/next_version.png +0 -0
- data/docs/images/ui_hierarchy.dot +0 -34
- data/docs/images/ui_hierarchy.png +0 -0
- data/lib/accessibility/debug.rb +0 -164
- data/test/integration/accessibility/test_debug.rb +0 -44
- data/test/sanity/accessibility/test_debug.rb +0 -63
data/lib/accessibility.rb
CHANGED
@@ -1,29 +1,41 @@
|
|
1
|
+
require 'accessibility/version'
|
1
2
|
require 'ax/application'
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
class << Accessibility
|
5
|
+
|
6
|
+
# Initialize the DEBUG value
|
7
|
+
@debug = ENV.fetch 'AXDEBUG', $DEBUG
|
8
|
+
|
9
|
+
##
|
10
|
+
# Whether or not to turn on DEBUG features in AXElements. The
|
11
|
+
# value is initially inherited from `$DEBUG` but can be overridden
|
12
|
+
# by an environment variable named `AXDEBUG` or changed dynamically
|
13
|
+
# at runtime.
|
14
|
+
#
|
15
|
+
# @return [Boolean]
|
16
|
+
attr_accessor :debug
|
17
|
+
alias_method :debug?, :debug
|
18
|
+
|
7
19
|
|
8
20
|
# @group Finding an application object
|
9
21
|
|
10
22
|
##
|
11
23
|
# @todo Move to {AX::Aplication#initialize} eventually.
|
12
|
-
# @todo Find a way for this method to work without sleeping;
|
13
|
-
# consider looping begin/rescue/end until AX starts up
|
14
|
-
# @todo This needs to handle bad bundle identifier's gracefully
|
15
24
|
#
|
16
25
|
# This is the standard way of creating an application object. It will
|
17
26
|
# launch the app if it is not already running and then create the
|
18
27
|
# accessibility object.
|
19
28
|
#
|
20
|
-
# However, this method is a
|
29
|
+
# However, this method is a bit of a hack in cases where the app is not
|
21
30
|
# already running; I've tried to register for notifications, launch
|
22
31
|
# synchronously, etc., but there is always a problem with accessibility
|
23
|
-
# not being ready.
|
32
|
+
# not being ready right away.
|
24
33
|
#
|
25
34
|
# If this method fails to find an app with the appropriate bundle
|
26
|
-
# identifier then it will
|
35
|
+
# identifier then it will raise an exception. If the problem was not a
|
36
|
+
# typo, then it might mean that the bundle identifier has not been
|
37
|
+
# registered with the system yet and you should launch the app once
|
38
|
+
# manually.
|
27
39
|
#
|
28
40
|
# @example
|
29
41
|
#
|
@@ -33,17 +45,20 @@ class << self
|
|
33
45
|
# @param [String] bundle a bundle identifier
|
34
46
|
# @return [AX::Application,nil]
|
35
47
|
def application_with_bundle_identifier bundle
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
48
|
+
if app_running?(bundle) || launch_application(bundle)
|
49
|
+
10.times do
|
50
|
+
return AX::Application.new(bundle) if app_running? bundle
|
51
|
+
sleep 1
|
52
|
+
end
|
53
|
+
else
|
54
|
+
raise ArgumentError "Could not launch app matching bundle id `#{bundle}'"
|
41
55
|
end
|
42
56
|
nil
|
43
57
|
end
|
44
58
|
|
45
59
|
##
|
46
|
-
# @deprecated
|
60
|
+
# @deprecated Directly initialize an {AX::Application} instance instead
|
61
|
+
# (e.g. `AX::Application.new('Terminal')`).
|
47
62
|
#
|
48
63
|
# Get the accessibility object for an application given its localized
|
49
64
|
# name. This will only work if the application is already running.
|
@@ -55,6 +70,7 @@ class << self
|
|
55
70
|
# @param [String] name name of the application to launch
|
56
71
|
# @return [AX::Application,nil]
|
57
72
|
def application_with_name name
|
73
|
+
$stderr.puts 'DEPRECATED: Use AX::Application.new instead'
|
58
74
|
AX::Application.new name
|
59
75
|
end
|
60
76
|
|
@@ -63,6 +79,16 @@ class << self
|
|
63
79
|
|
64
80
|
private
|
65
81
|
|
82
|
+
##
|
83
|
+
# Find out if the app is running and if so, return the running application
|
84
|
+
# for that bundle.
|
85
|
+
#
|
86
|
+
# @param [String]
|
87
|
+
# @return [NSRunningApplication,nil]
|
88
|
+
def app_running? bundle
|
89
|
+
NSRunningApplication.runningApplicationsWithBundleIdentifier(bundle).first
|
90
|
+
end
|
91
|
+
|
66
92
|
##
|
67
93
|
# Asynchronously launch an application given the bundle identifier.
|
68
94
|
#
|
@@ -76,4 +102,3 @@ class << self
|
|
76
102
|
end
|
77
103
|
|
78
104
|
end
|
79
|
-
end
|
data/lib/ax/application.rb
CHANGED
@@ -2,28 +2,24 @@ require 'ax/element'
|
|
2
2
|
require 'accessibility/string'
|
3
3
|
|
4
4
|
##
|
5
|
-
#
|
5
|
+
# The accessibility object representing the running application. This
|
6
|
+
# class contains some additional constructors and conveniences for
|
7
|
+
# Application objects.
|
6
8
|
#
|
7
9
|
# As this class has evolved, it has gathered some functionality from
|
8
|
-
# the `NSRunningApplication`
|
10
|
+
# the `NSRunningApplication` and `NSBundle` classes.
|
9
11
|
class AX::Application < AX::Element
|
10
12
|
include Accessibility::String
|
11
13
|
|
12
14
|
##
|
13
|
-
#
|
14
|
-
# Cached reference to the system wide object.
|
15
|
-
#
|
16
|
-
# @return [AXUIElementRef]
|
17
|
-
SYSTEMWIDE = AXUIElementCreateSystemWide()
|
18
|
-
|
19
|
-
##
|
20
|
-
# Overridden so that we can also cache the `NSRunningApplication`
|
21
|
-
# instance for this object.
|
15
|
+
# Overridden so that we can more flexibly manipulate input.
|
22
16
|
#
|
23
17
|
# You can initialize an application object with either the process
|
24
18
|
# identifier (pid) of the application, the name of the application,
|
25
19
|
# an `NSRunningApplication` instance for the application, or an
|
26
20
|
# accessibility (`AXUIElementRef`) token.
|
21
|
+
#
|
22
|
+
# @param [Number,String,NSRunningApplication]
|
27
23
|
def initialize arg
|
28
24
|
case arg
|
29
25
|
when Fixnum
|
@@ -52,7 +48,7 @@ class AX::Application < AX::Element
|
|
52
48
|
# @group Attributes
|
53
49
|
|
54
50
|
##
|
55
|
-
# Overridden to handle the {Accessibility::DSL#
|
51
|
+
# Overridden to handle the {Accessibility::DSL#set_focus_to} case.
|
56
52
|
#
|
57
53
|
# (see AX::Element#attribute)
|
58
54
|
def attribute attr
|
@@ -74,7 +70,7 @@ class AX::Application < AX::Element
|
|
74
70
|
|
75
71
|
##
|
76
72
|
# Ask the app whether or not it is the active app. This is equivalent
|
77
|
-
# to the dynamic
|
73
|
+
# to the dynamic `#focused?` method, but might make more sense to use
|
78
74
|
# in some cases.
|
79
75
|
def active?
|
80
76
|
@ref.spin_run_loop
|
@@ -100,7 +96,7 @@ class AX::Application < AX::Element
|
|
100
96
|
##
|
101
97
|
# Overridden to handle the {Accessibility::Language#set_focus} case.
|
102
98
|
#
|
103
|
-
# (see AX::Element#set
|
99
|
+
# (see AX::Element#set)
|
104
100
|
def set attr, value
|
105
101
|
case attr
|
106
102
|
when :focused
|
@@ -142,30 +138,50 @@ class AX::Application < AX::Element
|
|
142
138
|
end
|
143
139
|
|
144
140
|
##
|
145
|
-
# Send keyboard input to
|
146
|
-
# has focus will receive the key presses.
|
141
|
+
# Send keyboard input to the receiver, the control in the app that
|
142
|
+
# currently has focus will receive the key presses.
|
147
143
|
#
|
148
144
|
# For details on how to format the string, check out the
|
149
|
-
#
|
145
|
+
# [Keyboarding documentation](http://github.com/Marketcircle/AXElements/wiki/Keyboarding).
|
150
146
|
#
|
151
147
|
# @return [Boolean]
|
152
148
|
def type string
|
153
149
|
@ref.post keyboard_events_for string
|
154
150
|
true
|
155
151
|
end
|
152
|
+
alias_method :type_string, :type
|
156
153
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
#
|
164
|
-
|
165
|
-
|
166
|
-
|
154
|
+
##
|
155
|
+
# Press the given modifier key and hold it down while yielding to
|
156
|
+
# the given block.
|
157
|
+
#
|
158
|
+
# @example
|
159
|
+
#
|
160
|
+
# hold_key "\\CONTROL" do
|
161
|
+
# drag_mouse_to point
|
162
|
+
# end
|
163
|
+
#
|
164
|
+
# @param [String]
|
165
|
+
# @return [Number,nil]
|
166
|
+
def hold_modifier key
|
167
|
+
code = EventGenerator::CUSTOM[key]
|
168
|
+
raise ArgumentError, "Invalid modifier `#{key}' given" unless code
|
169
|
+
@ref.post [[code, true]]
|
170
|
+
yield
|
171
|
+
ensure
|
172
|
+
@ref.post [[code,false]] if code
|
173
|
+
code
|
167
174
|
end
|
168
175
|
|
176
|
+
##
|
177
|
+
# Navigate the menu bar menus for the receiver and select the menu
|
178
|
+
# item at the end of the given path. This method will open each menu
|
179
|
+
# in the path.
|
180
|
+
#
|
181
|
+
# @example
|
182
|
+
#
|
183
|
+
# safari.select_menu_item 'Edit', 'Find', /Google/
|
184
|
+
#
|
169
185
|
# @return [AX::MenuItem]
|
170
186
|
def select_menu_item *path
|
171
187
|
target = navigate_menu *path
|
@@ -173,8 +189,15 @@ class AX::Application < AX::Element
|
|
173
189
|
target
|
174
190
|
end
|
175
191
|
|
192
|
+
##
|
193
|
+
# Navigate the menu bar menus for the receiver. This method will not
|
194
|
+
# select the last item, but it will open each menu along the path.
|
195
|
+
#
|
196
|
+
# You may also be interested in {#select_menu_item}.
|
197
|
+
#
|
176
198
|
# @return [AX::MenuItem]
|
177
199
|
def navigate_menu *path
|
200
|
+
# @todo CLEAN UP
|
178
201
|
perform :unhide # can't navigate menus unless the app is up front
|
179
202
|
current = attribute(:menu_bar).search(:menu_bar_item, title: path.shift)
|
180
203
|
path.each do |part|
|
@@ -220,15 +243,13 @@ class AX::Application < AX::Element
|
|
220
243
|
|
221
244
|
|
222
245
|
##
|
223
|
-
# @todo Include bundle identifier?
|
224
|
-
#
|
225
246
|
# Override the base class to make sure the pid is included.
|
226
247
|
def inspect
|
227
248
|
super.sub! />$/, "#{pp_checkbox(:focused)} pid=#{pid}>"
|
228
249
|
end
|
229
250
|
|
230
251
|
##
|
231
|
-
# Find the element in
|
252
|
+
# Find the element in the receiver that is at point given.
|
232
253
|
#
|
233
254
|
# `nil` will be returned if there was nothing at that point.
|
234
255
|
#
|
@@ -251,4 +272,43 @@ class AX::Application < AX::Element
|
|
251
272
|
@app.bundleIdentifier
|
252
273
|
end
|
253
274
|
|
275
|
+
##
|
276
|
+
# Return the `Info.plist` data for the application. This is a plist
|
277
|
+
# file that all bundles in OS X must contain.
|
278
|
+
#
|
279
|
+
# Many bits of metadata are stored in the plist, check the
|
280
|
+
# [reference](https://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPRuntimeConfig/Articles/ConfigFiles.html)
|
281
|
+
# for more details.
|
282
|
+
#
|
283
|
+
# @return [Hash]
|
284
|
+
def info_plist
|
285
|
+
bundle.infoDictionary
|
286
|
+
end
|
287
|
+
|
288
|
+
##
|
289
|
+
# Get the version string for the application.
|
290
|
+
#
|
291
|
+
# @example
|
292
|
+
#
|
293
|
+
# AX::Application.new("Safari").version # => "5.2"
|
294
|
+
# AX::Application.new("Terminal").version # => "2.2.2"
|
295
|
+
# AX::Application.new("Daylite").version # => "3.15 (build 3664)"
|
296
|
+
#
|
297
|
+
# @return [String]
|
298
|
+
def version
|
299
|
+
bundle.objectForInfoDictionaryKey 'CFBundleShortVersionString'
|
300
|
+
end
|
301
|
+
|
302
|
+
|
303
|
+
private
|
304
|
+
|
305
|
+
# @return [NSBundle]
|
306
|
+
def bundle
|
307
|
+
@bundle ||= NSBundle.bundleWithURL @app.bundleURL
|
308
|
+
end
|
309
|
+
|
310
|
+
# @private
|
311
|
+
# @return [AXUIElementRef]
|
312
|
+
SYSTEMWIDE = AXUIElementCreateSystemWide()
|
313
|
+
|
254
314
|
end
|
data/lib/ax/button.rb
CHANGED
@@ -13,8 +13,11 @@ class AX::Button < AX::Element
|
|
13
13
|
#
|
14
14
|
# @return [Boolean]
|
15
15
|
def == other
|
16
|
-
|
17
|
-
|
16
|
+
if other.kind_of? NSString
|
17
|
+
attribute(:title) == other
|
18
|
+
else
|
19
|
+
super
|
20
|
+
end
|
18
21
|
end
|
19
22
|
|
20
23
|
end
|