AXElements 0.6.0beta2 → 0.7.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +1 -2
- data/README.markdown +152 -88
- data/Rakefile +8 -103
- data/docs/Debugging.markdown +9 -2
- data/docs/KeyboardEvents.markdown +114 -49
- data/docs/Setting.markdown +1 -0
- data/docs/images/next_version.png +0 -0
- data/ext/accessibility/key_coder/extconf.rb +22 -0
- data/ext/accessibility/key_coder/key_coder.c +113 -0
- data/lib/AXElements.rb +2 -0
- data/lib/accessibility/core.rb +897 -0
- data/lib/accessibility/debug.rb +168 -0
- data/lib/accessibility/dsl.rb +697 -0
- data/lib/accessibility/enumerators.rb +104 -0
- data/lib/accessibility/errors.rb +32 -0
- data/lib/accessibility/factory.rb +153 -0
- data/lib/accessibility/graph.rb +150 -0
- data/lib/{ax_elements/inspector.rb → accessibility/pp_inspector.rb} +39 -28
- data/lib/accessibility/qualifier.rb +158 -0
- data/lib/accessibility/string.rb +494 -0
- data/lib/accessibility/translator.rb +178 -0
- data/lib/accessibility/version.rb +7 -0
- data/lib/accessibility.rb +79 -0
- data/lib/ax/application.rb +234 -0
- data/lib/{ax_elements/elements → ax}/button.rb +2 -0
- data/lib/ax/element.rb +518 -0
- data/lib/{ax_elements/elements → ax}/radio_button.rb +2 -0
- data/lib/ax/row.rb +37 -0
- data/lib/{ax_elements/elements → ax}/static_text.rb +2 -0
- data/lib/ax/systemwide.rb +86 -0
- data/lib/ax_elements/awesome_print.rb +25 -0
- data/lib/ax_elements/exception_workaround.rb +8 -0
- data/lib/ax_elements/nsarray_compat.rb +64 -0
- data/lib/ax_elements/vendor/inflection_data.rb +65 -0
- data/lib/ax_elements/vendor/inflections.rb +172 -0
- data/lib/ax_elements/vendor/inflector.rb +306 -0
- data/lib/ax_elements.rb +14 -25
- data/lib/minitest/ax_elements.rb +112 -12
- data/lib/mouse.rb +72 -46
- data/lib/rspec/expectations/ax_elements.rb +133 -6
- data/rakelib/doc.rake +13 -0
- data/rakelib/ext.rake +61 -0
- data/rakelib/gem.rake +28 -0
- data/rakelib/test.rake +53 -0
- data/test/helper.rb +11 -97
- data/test/integration/accessibility/test_core.rb +18 -0
- data/test/integration/accessibility/test_debug.rb +44 -0
- data/test/integration/accessibility/test_dsl.rb +225 -0
- data/test/integration/accessibility/test_enumerators.rb +122 -0
- data/test/integration/accessibility/test_errors.rb +38 -0
- data/test/integration/accessibility/test_notifications.rb +22 -0
- data/test/integration/accessibility/test_qualifier.rb +148 -0
- data/test/integration/ax/test_application.rb +56 -0
- data/test/integration/ax/test_element.rb +46 -0
- data/test/integration/ax/test_row.rb +23 -0
- data/test/integration/ax_elements/test_nsarray_compat.rb +43 -0
- data/test/integration/minitest/test_ax_elements.rb +98 -0
- data/test/integration/rspec/expectations/test_ax_elements.rb +58 -0
- data/test/integration/test_mouse.rb +35 -0
- data/test/sanity/accessibility/test_core.rb +553 -0
- data/test/sanity/accessibility/test_debug.rb +63 -0
- data/test/sanity/accessibility/test_dsl.rb +75 -0
- data/test/sanity/accessibility/test_errors.rb +10 -0
- data/test/sanity/accessibility/test_factory.rb +88 -0
- data/test/sanity/accessibility/test_pp_inspector.rb +110 -0
- data/test/sanity/accessibility/test_qualifier.rb +13 -0
- data/test/sanity/accessibility/test_string.rb +238 -0
- data/test/sanity/accessibility/test_translator.rb +145 -0
- data/test/sanity/ax/test_application.rb +90 -0
- data/test/sanity/ax/test_element.rb +80 -0
- data/test/sanity/ax/test_systemwide.rb +66 -0
- data/test/sanity/ax_elements/test_nsarray_compat.rb +16 -0
- data/test/sanity/ax_elements/test_nsobject_inspect.rb +11 -0
- data/test/sanity/minitest/test_ax_elements.rb +15 -0
- data/test/sanity/rspec/expectations/test_ax_elements.rb +12 -0
- data/test/sanity/test_ax_elements.rb +10 -0
- data/test/sanity/test_mouse.rb +19 -0
- metadata +111 -93
- data/LICENSE.txt +0 -25
- data/ext/key_coder/extconf.rb +0 -6
- data/ext/key_coder/key_coder.m +0 -77
- data/lib/ax_elements/accessibility/enumerators.rb +0 -104
- data/lib/ax_elements/accessibility/graph.rb +0 -118
- data/lib/ax_elements/accessibility/language.rb +0 -347
- data/lib/ax_elements/accessibility/qualifier.rb +0 -73
- data/lib/ax_elements/accessibility.rb +0 -166
- data/lib/ax_elements/core.rb +0 -541
- data/lib/ax_elements/element.rb +0 -593
- data/lib/ax_elements/elements/application.rb +0 -88
- data/lib/ax_elements/elements/row.rb +0 -30
- data/lib/ax_elements/elements/systemwide.rb +0 -46
- data/lib/ax_elements/macruby_extensions.rb +0 -255
- data/lib/ax_elements/notification.rb +0 -37
- data/lib/ax_elements/version.rb +0 -9
- data/test/elements/test_application.rb +0 -72
- data/test/elements/test_row.rb +0 -27
- data/test/elements/test_systemwide.rb +0 -38
- data/test/test_accessibility.rb +0 -127
- data/test/test_blankness.rb +0 -26
- data/test/test_core.rb +0 -448
- data/test/test_element.rb +0 -939
- data/test/test_enumerators.rb +0 -81
- data/test/test_inspector.rb +0 -130
- data/test/test_language.rb +0 -157
- data/test/test_macruby_extensions.rb +0 -303
- data/test/test_mouse.rb +0 -5
- data/test/test_search_semantics.rb +0 -143
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'accessibility/version'
|
2
|
+
require 'ax_elements/vendor/inflector'
|
3
|
+
|
4
|
+
framework 'ApplicationServices'
|
5
|
+
|
6
|
+
unless Object.const_defined? :KAXIdentifierAttribute
|
7
|
+
##
|
8
|
+
# Added for backwards compatability with Snow Leopard.
|
9
|
+
# This attribute is standard with Lion and newer. AXElements depends
|
10
|
+
# on it being defined.
|
11
|
+
#
|
12
|
+
# @return [String]
|
13
|
+
KAXIdentifierAttribute = 'AXIdentifier'
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
##
|
18
|
+
# Maintain all the rules for transforming Cocoa constants into something
|
19
|
+
# a little more Rubyish.
|
20
|
+
class Accessibility::Translator
|
21
|
+
|
22
|
+
def self.instance
|
23
|
+
@instance ||= new
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Initialize the caches.
|
28
|
+
def initialize
|
29
|
+
init_unprefixes
|
30
|
+
init_normalizations
|
31
|
+
init_rubyisms
|
32
|
+
init_classifications
|
33
|
+
init_singularizations
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# @note In the case of a predicate name, this will strip the 'Is'
|
38
|
+
# part of the name if it is present
|
39
|
+
#
|
40
|
+
# Takes an accessibility constant and returns a new string with the
|
41
|
+
# namespace prefix removed.
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
#
|
45
|
+
# unprefix 'AXTitle' # => 'Title'
|
46
|
+
# unprefix 'AXIsApplicationEnabled' # => 'ApplicationEnabled'
|
47
|
+
# unprefix 'MCAXEnabled' # => 'Enabled'
|
48
|
+
# unprefix KAXWindowCreatedNotification # => 'WindowCreated'
|
49
|
+
# unprefix NSAccessibilityButtonRole # => 'Button'
|
50
|
+
#
|
51
|
+
# @param [String]
|
52
|
+
# @return [String]
|
53
|
+
def unprefix key
|
54
|
+
@unprefixes[key]
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# Given a symbol, return the equivalent accessibility constant.
|
59
|
+
#
|
60
|
+
# @param [#to_sym]
|
61
|
+
# @param [Array<String>]
|
62
|
+
# @return [String]
|
63
|
+
def lookup key, values
|
64
|
+
@values = values
|
65
|
+
@rubyisms[key.to_sym]
|
66
|
+
end
|
67
|
+
|
68
|
+
# @return [Array<Symbol>]
|
69
|
+
def rubyize keys
|
70
|
+
keys.map { |x| @normalizations[x] }
|
71
|
+
end
|
72
|
+
|
73
|
+
##
|
74
|
+
# Try to turn an arbitrary symbol into a notification constant, and
|
75
|
+
# then get the value of the constant.
|
76
|
+
#
|
77
|
+
# @param [#to_s]
|
78
|
+
# @return [String]
|
79
|
+
def guess_notification_for name
|
80
|
+
name = name.to_s.gsub /(?:^|_)(.)/ do $1.upcase! || $1 end
|
81
|
+
const = "KAX#{name}Notification"
|
82
|
+
Object.const_defined?(const) ? Object.const_get(const) : name
|
83
|
+
end
|
84
|
+
|
85
|
+
##
|
86
|
+
# Get the class name equivalent for a given symbol or string. This
|
87
|
+
# is just a caching front end to the `#classify` method from the
|
88
|
+
# ActiveSupport inflector.
|
89
|
+
#
|
90
|
+
# @example
|
91
|
+
#
|
92
|
+
# classify 'text_field' # => "TextField"
|
93
|
+
# classify 'buttons' # => "Button"
|
94
|
+
#
|
95
|
+
# @param [String]
|
96
|
+
# @return [String]
|
97
|
+
def classify klass
|
98
|
+
@classifications[klass]
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# Get the singularized version of the word passed in. This is just
|
103
|
+
# a caching front end to the `#singularize` method from the
|
104
|
+
# ActiveSupport inflector.
|
105
|
+
#
|
106
|
+
# @example
|
107
|
+
#
|
108
|
+
# singularize 'buttons' # => 'button'
|
109
|
+
# singularize 'check_boxes' # => 'check_box'
|
110
|
+
#
|
111
|
+
# @param [String]
|
112
|
+
# @return [String]
|
113
|
+
def singularize klass
|
114
|
+
@singularizations[klass]
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
# @return [Hash{String=>String}]
|
121
|
+
def init_unprefixes
|
122
|
+
@unprefixes = Hash.new do |hash, key|
|
123
|
+
hash[key] = key.sub /^[A-Z]*?AX(?:Is)?|\s+/, EMPTY_STRING
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# @return [Hash{String=>Symbol}]
|
128
|
+
def init_normalizations
|
129
|
+
@normalizations = Hash.new do |hash, key|
|
130
|
+
hash[key] = Accessibility::Inflector.underscore(@unprefixes[key]).to_sym
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# @return [Hash{Symbol=>String}]
|
135
|
+
def init_rubyisms
|
136
|
+
@rubyisms = Hash.new do |hash, key|
|
137
|
+
@values.each do |v| hash[@normalizations[v]] = v end
|
138
|
+
hash.fetch(key) do |k|
|
139
|
+
chomped_key = k.chomp(QUESTION_MARK).to_sym
|
140
|
+
chomped_val = hash.fetch(chomped_key, nil)
|
141
|
+
hash[key] = chomped_val if chomped_val
|
142
|
+
end
|
143
|
+
end
|
144
|
+
# preload the table
|
145
|
+
@rubyisms[:id] = KAXIdentifierAttribute
|
146
|
+
@rubyisms[:placeholder] = KAXPlaceholderValueAttribute
|
147
|
+
end
|
148
|
+
|
149
|
+
# @return [Hash{String=>String}]
|
150
|
+
def init_classifications
|
151
|
+
@classifications = Hash.new do |hash, key|
|
152
|
+
hash[key] = Accessibility::Inflector.classify(key)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# @return [Hash{String=>String}]
|
157
|
+
def init_singularizations
|
158
|
+
@singularizations = Hash.new do |hash, key|
|
159
|
+
hash[key] = Accessibility::Inflector.singularize(key)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
##
|
164
|
+
# @private
|
165
|
+
#
|
166
|
+
# Cached for performance.
|
167
|
+
#
|
168
|
+
# @return [String]
|
169
|
+
EMPTY_STRING = ''
|
170
|
+
|
171
|
+
##
|
172
|
+
# @private
|
173
|
+
#
|
174
|
+
# Performance hack.
|
175
|
+
#
|
176
|
+
# @return [String]
|
177
|
+
QUESTION_MARK = '?'
|
178
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'ax/application'
|
2
|
+
|
3
|
+
##
|
4
|
+
# The main AXElements namespace.
|
5
|
+
module Accessibility
|
6
|
+
class << self
|
7
|
+
|
8
|
+
# @group Finding an application object
|
9
|
+
|
10
|
+
##
|
11
|
+
# @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
|
+
#
|
16
|
+
# This is the standard way of creating an application object. It will
|
17
|
+
# launch the app if it is not already running and then create the
|
18
|
+
# accessibility object.
|
19
|
+
#
|
20
|
+
# However, this method is a _HUGE_ hack in cases where the app is not
|
21
|
+
# already running; I've tried to register for notifications, launch
|
22
|
+
# synchronously, etc., but there is always a problem with accessibility
|
23
|
+
# not being ready.
|
24
|
+
#
|
25
|
+
# If this method fails to find an app with the appropriate bundle
|
26
|
+
# identifier then it will return nil, eventually.
|
27
|
+
#
|
28
|
+
# @example
|
29
|
+
#
|
30
|
+
# application_with_bundle_identifier 'com.apple.mail' # wait a few seconds
|
31
|
+
# application_with_bundle_identifier 'com.marketcircle.Daylite'
|
32
|
+
#
|
33
|
+
# @param [String] bundle a bundle identifier
|
34
|
+
# @return [AX::Application,nil]
|
35
|
+
def application_with_bundle_identifier bundle
|
36
|
+
10.times do
|
37
|
+
apps = NSRunningApplication.runningApplicationsWithBundleIdentifier bundle
|
38
|
+
return AX::Application.new(apps.first.processIdentifier) unless apps.empty?
|
39
|
+
launch_application bundle
|
40
|
+
sleep 2
|
41
|
+
end
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# @deprecated Use {AX::Application.new} instead.
|
47
|
+
#
|
48
|
+
# Get the accessibility object for an application given its localized
|
49
|
+
# name. This will only work if the application is already running.
|
50
|
+
#
|
51
|
+
# @example
|
52
|
+
#
|
53
|
+
# application_with_name 'Mail'
|
54
|
+
#
|
55
|
+
# @param [String] name name of the application to launch
|
56
|
+
# @return [AX::Application,nil]
|
57
|
+
def application_with_name name
|
58
|
+
AX::Application.new name
|
59
|
+
end
|
60
|
+
|
61
|
+
# @endgroup
|
62
|
+
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
##
|
67
|
+
# Asynchronously launch an application given the bundle identifier.
|
68
|
+
#
|
69
|
+
# @param [String] bundle the bundle identifier for the app
|
70
|
+
# @return [Boolean]
|
71
|
+
def launch_application bundle
|
72
|
+
NSWorkspace.sharedWorkspace.launchAppWithBundleIdentifier bundle,
|
73
|
+
options: NSWorkspaceLaunchAsync,
|
74
|
+
additionalEventParamDescriptor: nil,
|
75
|
+
launchIdentifier: nil
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,234 @@
|
|
1
|
+
require 'ax/element'
|
2
|
+
require 'accessibility/string'
|
3
|
+
|
4
|
+
##
|
5
|
+
# Some additional constructors and conveniences for Application objects.
|
6
|
+
#
|
7
|
+
# As this class has evolved, it has gathered some functionality from
|
8
|
+
# the `NSRunningApplication` class.
|
9
|
+
class AX::Application < AX::Element
|
10
|
+
include Accessibility::String
|
11
|
+
|
12
|
+
##
|
13
|
+
# Overridden so that we can also cache the `NSRunningApplication`
|
14
|
+
# instance for this object.
|
15
|
+
#
|
16
|
+
# You can initialize an application object with either the process
|
17
|
+
# identifier (pid) of the application, the name of the application,
|
18
|
+
# an `NSRunningApplication` instance for the application, or an
|
19
|
+
# accessibility (`AXUIElementRef`) token.
|
20
|
+
def initialize arg
|
21
|
+
case arg
|
22
|
+
when Fixnum
|
23
|
+
super SYSTEMWIDE.application_for arg
|
24
|
+
@app = NSRunningApplication.runningApplicationWithProcessIdentifier arg
|
25
|
+
when String
|
26
|
+
SYSTEMWIDE.spin_run_loop
|
27
|
+
@app = NSWorkspace.sharedWorkspace.runningApplications
|
28
|
+
.find { |app| app.localizedName == arg }
|
29
|
+
super SYSTEMWIDE.application_for @app.processIdentifier
|
30
|
+
when NSRunningApplication
|
31
|
+
super SYSTEMWIDE.application_for arg.processIdentifier
|
32
|
+
@app = arg
|
33
|
+
else
|
34
|
+
super arg # assume it is an AXUIElementRef
|
35
|
+
@app = NSRunningApplication.runningApplicationWithProcessIdentifier pid
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
# @group Attributes
|
41
|
+
|
42
|
+
##
|
43
|
+
# Overridden to handle the {Accessibility::Language#set_focus} case.
|
44
|
+
#
|
45
|
+
# (see AX::Element#attribute)
|
46
|
+
def attribute attr
|
47
|
+
case attr
|
48
|
+
when :focused?, :focused then active?
|
49
|
+
when :hidden?, :hidden then hidden?
|
50
|
+
else
|
51
|
+
super
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# Ask the app whether or not it is the active app. This is equivalent
|
57
|
+
# to the dynamic #focused? method, but might make more sense to use
|
58
|
+
# in some cases.
|
59
|
+
def active?
|
60
|
+
@ref.spin_run_loop
|
61
|
+
@app.active?
|
62
|
+
end
|
63
|
+
alias_method :focused, :active?
|
64
|
+
alias_method :focused?, :active?
|
65
|
+
|
66
|
+
##
|
67
|
+
# Ask the app whether or not it is hidden.
|
68
|
+
def hidden?
|
69
|
+
@ref.spin_run_loop
|
70
|
+
@app.hidden?
|
71
|
+
end
|
72
|
+
|
73
|
+
##
|
74
|
+
# Ask the app whether or not it is still running.
|
75
|
+
def terminated?
|
76
|
+
@ref.spin_run_loop
|
77
|
+
@app.terminated?
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Overridden to handle the {Accessibility::Language#set_focus} case.
|
82
|
+
#
|
83
|
+
# (see AX::Element#set:to:)
|
84
|
+
def set attr, to: value
|
85
|
+
case attr
|
86
|
+
when :focused
|
87
|
+
perform(value ? :unhide : :hide)
|
88
|
+
when :active, :hidden
|
89
|
+
perform(value ? :hide : :unhide)
|
90
|
+
else
|
91
|
+
super
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
# @group Actions
|
97
|
+
|
98
|
+
##
|
99
|
+
# Overridden to provide extra actions (e.g. `hide`, `terminate`).
|
100
|
+
#
|
101
|
+
# (see AX::Element#perform)
|
102
|
+
#
|
103
|
+
# @return [Boolean]
|
104
|
+
def perform name
|
105
|
+
case name
|
106
|
+
when :terminate
|
107
|
+
return true if terminated?
|
108
|
+
@app.terminate; sleep 0.2; terminated?
|
109
|
+
when :force_terminate
|
110
|
+
return true if terminated?
|
111
|
+
@app.forceTerminate; sleep 0.2; terminated?
|
112
|
+
when :hide
|
113
|
+
return true if hidden?
|
114
|
+
@app.hide; sleep 0.2; hidden?
|
115
|
+
when :unhide
|
116
|
+
return true if active?
|
117
|
+
@app.activateWithOptions(NSApplicationActivateIgnoringOtherApps)
|
118
|
+
sleep 0.2; active?
|
119
|
+
else
|
120
|
+
super
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
##
|
125
|
+
# Send keyboard input to `self`, the control in the app that currently
|
126
|
+
# has focus will receive the key presses.
|
127
|
+
#
|
128
|
+
# For details on how to format the string, check out the
|
129
|
+
# {file:docs/KeyboardEvents.markdown Keyboard} documentation.
|
130
|
+
#
|
131
|
+
# @return [Boolean]
|
132
|
+
def type_string string
|
133
|
+
@ref.post keyboard_events_for string
|
134
|
+
true
|
135
|
+
end
|
136
|
+
|
137
|
+
# @todo doc and cleanup
|
138
|
+
def keydown key
|
139
|
+
@ref.post [[EventGenerator::CUSTOM[key], true]]
|
140
|
+
true
|
141
|
+
end
|
142
|
+
|
143
|
+
# @todo doc and cleanup
|
144
|
+
def keyup key
|
145
|
+
@ref.post [[EventGenerator::CUSTOM[key], false]]
|
146
|
+
true
|
147
|
+
end
|
148
|
+
|
149
|
+
# @return [AX::MenuItem]
|
150
|
+
def select_menu_item *path
|
151
|
+
target = navigate_menu *path
|
152
|
+
target.perform :press
|
153
|
+
target
|
154
|
+
end
|
155
|
+
|
156
|
+
# @return [AX::MenuItem]
|
157
|
+
def navigate_menu *path
|
158
|
+
perform :unhide # can't navigate menus unless the app is up front
|
159
|
+
current = attribute(:menu_bar).search(:menu_bar_item, title: path.shift)
|
160
|
+
path.each do |part|
|
161
|
+
current.perform :press
|
162
|
+
next_item = current.search(:menu_item, title: part)
|
163
|
+
if next_item.blank?
|
164
|
+
failure = Accessibility::SearchFailure.new(current, :menu_item, title: part)
|
165
|
+
current.perform :cancel # close menu
|
166
|
+
raise failure
|
167
|
+
else
|
168
|
+
current = next_item
|
169
|
+
end
|
170
|
+
end
|
171
|
+
current
|
172
|
+
end
|
173
|
+
|
174
|
+
##
|
175
|
+
# Show the "About" window for the app. Returns the window that is
|
176
|
+
# opened.
|
177
|
+
#
|
178
|
+
# @return [AX::Window]
|
179
|
+
def show_about_window
|
180
|
+
windows = self.children.select { |x| x.kind_of? AX::Window }
|
181
|
+
select_menu_item self.title, /^About /
|
182
|
+
wait_for(:window, parent: self) { |window| !windows.include?(window) }
|
183
|
+
end
|
184
|
+
|
185
|
+
##
|
186
|
+
# @note This method assumes that the app has setup the standard
|
187
|
+
# CMD+, hotkey to open the pref window
|
188
|
+
#
|
189
|
+
# Try to open the preferences for the app. Returns the window that
|
190
|
+
# is opened.
|
191
|
+
#
|
192
|
+
# @return [AX::Window]
|
193
|
+
def show_preferences_window
|
194
|
+
windows = self.children.select { |x| x.kind_of? AX::Window }
|
195
|
+
type_string "\\COMMAND+,"
|
196
|
+
wait_for(:window, parent: self) { |window| !windows.include?(window) }
|
197
|
+
end
|
198
|
+
|
199
|
+
# @endgroup
|
200
|
+
|
201
|
+
|
202
|
+
##
|
203
|
+
# @todo Include bundle identifier?
|
204
|
+
#
|
205
|
+
# Override the base class to make sure the pid is included.
|
206
|
+
def inspect
|
207
|
+
super.sub! />$/, "#{pp_checkbox(:focused)} pid=#{pid}>"
|
208
|
+
end
|
209
|
+
|
210
|
+
##
|
211
|
+
# Find the element in `self` that is present at point given.
|
212
|
+
#
|
213
|
+
# `nil` will be returned if there was nothing at that point.
|
214
|
+
#
|
215
|
+
# @param [#to_point]
|
216
|
+
# @return [AX::Element,nil]
|
217
|
+
def element_at point
|
218
|
+
process @ref.element_at point
|
219
|
+
end
|
220
|
+
|
221
|
+
##
|
222
|
+
# Get the bundle identifier for the application.
|
223
|
+
#
|
224
|
+
# @example
|
225
|
+
#
|
226
|
+
# safari.bundle_identifier 'com.apple.safari'
|
227
|
+
# daylite.bundle_identifier 'com.marketcircle.Daylite'
|
228
|
+
#
|
229
|
+
# @return [String]
|
230
|
+
def bundle_identifier
|
231
|
+
@app.bundleIdentifier
|
232
|
+
end
|
233
|
+
|
234
|
+
end
|