AXElements 0.8.1 → 0.9.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 +4 -0
- data/History.markdown +41 -0
- data/README.markdown +59 -62
- data/Rakefile +1 -1
- data/ext/accessibility/key_coder/extconf.rb +1 -1
- data/ext/accessibility/key_coder/key_coder.c +8 -5
- data/lib/accessibility/dsl.rb +261 -87
- data/lib/accessibility/enumerators.rb +14 -11
- data/lib/accessibility/errors.rb +4 -3
- data/lib/accessibility/factory.rb +159 -108
- data/lib/accessibility/graph.rb +13 -9
- data/lib/accessibility/{pp_inspector.rb → pretty_printer.rb} +4 -5
- data/lib/accessibility/qualifier.rb +23 -13
- data/lib/accessibility/string.rb +4 -4
- data/lib/accessibility/system_info.rb +230 -0
- data/lib/accessibility/translator.rb +38 -28
- data/lib/accessibility/version.rb +24 -2
- data/lib/accessibility.rb +25 -8
- data/lib/ax/application.rb +207 -77
- data/lib/ax/element.rb +62 -65
- data/lib/ax/menu.rb +5 -1
- data/lib/ax/row.rb +1 -1
- data/lib/ax/scroll_area.rb +7 -6
- data/lib/ax/systemwide.rb +38 -5
- data/lib/ax_elements/active_support_selections.rb +10 -0
- data/lib/ax_elements/mri.rb +57 -0
- data/lib/ax_elements/nsarray_compat.rb +97 -17
- data/lib/ax_elements.rb +9 -1
- data/rakelib/gem.rake +11 -11
- data/rakelib/test.rake +0 -9
- data/test/helper.rb +10 -18
- data/test/integration/accessibility/test_dsl.rb +52 -42
- data/test/integration/accessibility/test_enumerators.rb +0 -1
- data/test/integration/accessibility/test_graph.rb +1 -0
- data/test/integration/accessibility/test_qualifier.rb +2 -2
- data/test/integration/ax/test_application.rb +9 -2
- data/test/integration/ax/test_element.rb +41 -1
- data/test/sanity/accessibility/test_factory.rb +23 -56
- data/test/sanity/accessibility/{test_pp_inspector.rb → test_pretty_printer.rb} +9 -9
- data/test/sanity/accessibility/test_translator.rb +2 -5
- data/test/sanity/accessibility/test_version.rb +15 -0
- data/test/sanity/ax/test_application.rb +17 -2
- data/test/sanity/ax/test_element.rb +2 -2
- data/test/sanity/ax_elements/test_nsobject_inspect.rb +4 -2
- data/test/sanity/test_ax_elements.rb +1 -0
- metadata +69 -39
- data/lib/accessibility/core.rb +0 -973
- data/lib/accessibility/highlighter.rb +0 -86
- data/lib/ax_elements/vendor/inflection_data.rb +0 -66
- data/lib/ax_elements/vendor/inflections.rb +0 -172
- data/lib/ax_elements/vendor/inflector.rb +0 -306
- data/lib/minitest/ax_elements.rb +0 -175
- data/lib/mouse.rb +0 -223
- data/lib/rspec/expectations/ax_elements.rb +0 -234
- data/test/integration/accessibility/test_core.rb +0 -18
- data/test/integration/minitest/test_ax_elements.rb +0 -89
- data/test/integration/rspec/expectations/test_ax_elements.rb +0 -102
- data/test/sanity/accessibility/test_core.rb +0 -561
- data/test/sanity/accessibility/test_highlighter.rb +0 -56
- data/test/sanity/minitest/test_ax_elements.rb +0 -17
- data/test/sanity/rspec/expectations/test_ax_elements.rb +0 -15
- data/test/sanity/test_mouse.rb +0 -19
data/lib/accessibility/dsl.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
|
3
|
+
require 'active_support/core_ext/object/blank'
|
4
|
+
|
3
5
|
require 'mouse'
|
4
6
|
require 'ax/element'
|
5
7
|
require 'ax/application'
|
@@ -8,6 +10,8 @@ require 'ax/scroll_area'
|
|
8
10
|
require 'ax/menu'
|
9
11
|
require 'accessibility'
|
10
12
|
require 'accessibility/enumerators'
|
13
|
+
require 'accessibility/highlighter'
|
14
|
+
|
11
15
|
|
12
16
|
##
|
13
17
|
# DSL methods for AXElements.
|
@@ -22,14 +26,14 @@ require 'accessibility/enumerators'
|
|
22
26
|
module Accessibility::DSL
|
23
27
|
|
24
28
|
|
25
|
-
#
|
29
|
+
# @!group Actions
|
26
30
|
|
27
31
|
##
|
28
32
|
# We assume that any method that has the first argument with a type
|
29
33
|
# of {AX::Element} is intended to be an action and so `#method_missing`
|
30
34
|
# will forward the message to the element.
|
31
35
|
#
|
32
|
-
# @param [String]
|
36
|
+
# @param meth [String] an action constant
|
33
37
|
def method_missing meth, *args
|
34
38
|
arg = args.first
|
35
39
|
if arg.kind_of? AX::Element
|
@@ -46,7 +50,7 @@ module Accessibility::DSL
|
|
46
50
|
##
|
47
51
|
# Try to perform the `press` action on the given element.
|
48
52
|
#
|
49
|
-
# @param [AX::Element]
|
53
|
+
# @param element [AX::Element]
|
50
54
|
# @return [Boolean]
|
51
55
|
def press element
|
52
56
|
element.perform :press
|
@@ -55,7 +59,7 @@ module Accessibility::DSL
|
|
55
59
|
##
|
56
60
|
# Try to perform the `show_menu` action on the given element.
|
57
61
|
#
|
58
|
-
# @param [AX::Element]
|
62
|
+
# @param element [AX::Element]
|
59
63
|
# @return [Boolean]
|
60
64
|
def show_menu element
|
61
65
|
element.perform :show_menu
|
@@ -64,7 +68,7 @@ module Accessibility::DSL
|
|
64
68
|
##
|
65
69
|
# Try to perform the `pick` action on the given element.
|
66
70
|
#
|
67
|
-
# @param [AX::Element]
|
71
|
+
# @param element [AX::Element]
|
68
72
|
# @return [Boolean]
|
69
73
|
def pick element
|
70
74
|
element.perform :pick
|
@@ -73,7 +77,7 @@ module Accessibility::DSL
|
|
73
77
|
##
|
74
78
|
# Try to perform the `decrement` action on the given element.
|
75
79
|
#
|
76
|
-
# @param [AX::Element]
|
80
|
+
# @param element [AX::Element]
|
77
81
|
# @return [Boolean]
|
78
82
|
def decrement element
|
79
83
|
element.perform :decrement
|
@@ -82,7 +86,7 @@ module Accessibility::DSL
|
|
82
86
|
##
|
83
87
|
# Try to perform the `confirm` action on the given element.
|
84
88
|
#
|
85
|
-
# @param [AX::Element]
|
89
|
+
# @param element [AX::Element]
|
86
90
|
# @return [Boolean]
|
87
91
|
def confirm element
|
88
92
|
element.perform :confirm
|
@@ -91,7 +95,7 @@ module Accessibility::DSL
|
|
91
95
|
##
|
92
96
|
# Try to perform the `increment` action on the given element.
|
93
97
|
#
|
94
|
-
# @param [AX::Element]
|
98
|
+
# @param element [AX::Element]
|
95
99
|
# @return [Boolean]
|
96
100
|
def increment element
|
97
101
|
element.perform :increment
|
@@ -100,7 +104,7 @@ module Accessibility::DSL
|
|
100
104
|
##
|
101
105
|
# Try to perform the `delete` action on the given element.
|
102
106
|
#
|
103
|
-
# @param [AX::Element]
|
107
|
+
# @param element [AX::Element]
|
104
108
|
# @return [Boolean]
|
105
109
|
def delete element
|
106
110
|
element.perform :delete
|
@@ -109,7 +113,7 @@ module Accessibility::DSL
|
|
109
113
|
##
|
110
114
|
# Try to perform the `cancel` action on the given element.
|
111
115
|
#
|
112
|
-
# @param [AX::Element]
|
116
|
+
# @param element [AX::Element]
|
113
117
|
# @return [Boolean]
|
114
118
|
def cancel element
|
115
119
|
element.perform :cancel
|
@@ -122,20 +126,20 @@ module Accessibility::DSL
|
|
122
126
|
# Try to perform the `raise` action on the given element.
|
123
127
|
#
|
124
128
|
# @overload raise element
|
125
|
-
# @param [AX::Element]
|
129
|
+
# @param element [AX::Element]
|
126
130
|
# @return [Boolean]
|
127
131
|
#
|
128
132
|
# @overload raise exception[, message[, backtrace]]
|
129
133
|
# The normal way to raise an exception.
|
130
134
|
def raise *args
|
131
135
|
arg = args.first
|
132
|
-
arg.kind_of?(AX::Element) ? arg.perform(:raise) :
|
136
|
+
arg.kind_of?(AX::Element) ? arg.perform(:raise) : Kernel.raise(*args)
|
133
137
|
end
|
134
138
|
|
135
139
|
##
|
136
140
|
# Tell an app to hide itself.
|
137
141
|
#
|
138
|
-
# @param [AX::Application]
|
142
|
+
# @param app [AX::Application]
|
139
143
|
# @return [Boolean]
|
140
144
|
def hide app
|
141
145
|
app.perform :hide
|
@@ -144,7 +148,7 @@ module Accessibility::DSL
|
|
144
148
|
##
|
145
149
|
# Tell an app to unhide itself.
|
146
150
|
#
|
147
|
-
# @param [AX::Application]
|
151
|
+
# @param app [AX::Application]
|
148
152
|
# @return [Boolean]
|
149
153
|
def unhide app
|
150
154
|
app.perform :unhide
|
@@ -154,7 +158,7 @@ module Accessibility::DSL
|
|
154
158
|
##
|
155
159
|
# Tell an app to quit.
|
156
160
|
#
|
157
|
-
# @param [AX::Application]
|
161
|
+
# @param app [AX::Application]
|
158
162
|
# @return [Boolean]
|
159
163
|
def terminate app
|
160
164
|
app.perform :terminate
|
@@ -165,7 +169,7 @@ module Accessibility::DSL
|
|
165
169
|
# focused. It is safe to pass any element into this method as nothing
|
166
170
|
# will happen if it does not have a writable focused state attribute.
|
167
171
|
#
|
168
|
-
# @param [AX::Element]
|
172
|
+
# @param element [AX::Element]
|
169
173
|
def set_focus_to element
|
170
174
|
element.set(:focused, true) if element.writable? :focused
|
171
175
|
end
|
@@ -180,8 +184,8 @@ module Accessibility::DSL
|
|
180
184
|
#
|
181
185
|
# @overload set element, attribute_name: new_value
|
182
186
|
# Set a specified attribute to a new value
|
183
|
-
# @param [AX::Element]
|
184
|
-
# @param [Hash{attribute_name=>new_value}]
|
187
|
+
# @param element [AX::Element]
|
188
|
+
# @param change [Hash{attribute_name=>new_value}]
|
185
189
|
#
|
186
190
|
# @example
|
187
191
|
#
|
@@ -189,8 +193,8 @@ module Accessibility::DSL
|
|
189
193
|
#
|
190
194
|
# @overload set element, new_value
|
191
195
|
# Set the `value` attribute to a new value
|
192
|
-
# @param [AX::Element]
|
193
|
-
# @param [Object]
|
196
|
+
# @param element [AX::Element]
|
197
|
+
# @param change [Object]
|
194
198
|
#
|
195
199
|
# @example
|
196
200
|
#
|
@@ -216,7 +220,7 @@ module Accessibility::DSL
|
|
216
220
|
#
|
217
221
|
# @overload type string
|
218
222
|
# Send input to the currently focused application
|
219
|
-
# @param [
|
223
|
+
# @param string [String]
|
220
224
|
#
|
221
225
|
# @example
|
222
226
|
#
|
@@ -224,7 +228,7 @@ module Accessibility::DSL
|
|
224
228
|
#
|
225
229
|
# @overload type string, app
|
226
230
|
# Send input to a specific application
|
227
|
-
# @param [
|
231
|
+
# @param String [String]
|
228
232
|
# @param [AX::Application]
|
229
233
|
#
|
230
234
|
def type string, app = system_wide
|
@@ -243,18 +247,18 @@ module Accessibility::DSL
|
|
243
247
|
# select_menu_item mail, 'View', 'Sort By', 'Subject'
|
244
248
|
# select_menu_item mail, 'Edit', /Spelling/, /show spelling/i
|
245
249
|
#
|
246
|
-
# @param [AX::Application]
|
247
|
-
# @param [String,Regexp]
|
250
|
+
# @param app [AX::Application]
|
251
|
+
# @param path [String,Regexp]
|
248
252
|
# @return [Boolean]
|
249
253
|
def select_menu_item app, *path
|
250
|
-
app.select_menu_item *path
|
254
|
+
app.application.select_menu_item *path
|
251
255
|
end
|
252
256
|
|
253
257
|
##
|
254
258
|
# Show the "About" window for an app. Returns the window that is
|
255
259
|
# opened.
|
256
260
|
#
|
257
|
-
# @param [AX::Application]
|
261
|
+
# @param app [AX::Application]
|
258
262
|
# @return [AX::Window]
|
259
263
|
def show_about_window_for app
|
260
264
|
app.show_about_window
|
@@ -267,10 +271,10 @@ module Accessibility::DSL
|
|
267
271
|
# Try to open the preferences for an app. Returns the window that
|
268
272
|
# is opened.
|
269
273
|
#
|
270
|
-
# @param [AX::Application]
|
274
|
+
# @param app [AX::Application]
|
271
275
|
# @return [AX::Window]
|
272
276
|
def show_preferences_window_for app
|
273
|
-
app.show_preferences_window
|
277
|
+
app.application.show_preferences_window
|
274
278
|
end
|
275
279
|
|
276
280
|
##
|
@@ -285,7 +289,7 @@ module Accessibility::DSL
|
|
285
289
|
#
|
286
290
|
# scroll_to table.rows.last
|
287
291
|
#
|
288
|
-
# @param [AX::Element]
|
292
|
+
# @param element [AX::Element]
|
289
293
|
# @return [void]
|
290
294
|
def scroll_to element
|
291
295
|
element.ancestor(:scroll_area).scroll_to element
|
@@ -302,14 +306,39 @@ module Accessibility::DSL
|
|
302
306
|
# scroll_menu_to pop_up.menu.item(title: "Expensive Cake")
|
303
307
|
# end
|
304
308
|
#
|
305
|
-
# @param [AX
|
309
|
+
# @param element [AX::Element]
|
306
310
|
# @return [void]
|
307
311
|
def scroll_menu_to element
|
308
|
-
|
312
|
+
element.ancestor(:menu).scroll_to element
|
313
|
+
end
|
314
|
+
|
315
|
+
##
|
316
|
+
# @note This is a hack to workaround an AXAPI deficiency
|
317
|
+
# @note This method may move or be renamed in the next release, though
|
318
|
+
# it will not be removed
|
319
|
+
#
|
320
|
+
# Find a contextual menu that is open near the mouses current position
|
321
|
+
#
|
322
|
+
# This method assumes that it is being called in the block of a call to
|
323
|
+
# {#right_click}, and that the contextual menu is going to be very close
|
324
|
+
# to the mouse pointer.
|
325
|
+
#
|
326
|
+
# @return [AX::Menu,nil]
|
327
|
+
def contextual_menu
|
328
|
+
# CAST, just like high school trigonometry! :P
|
329
|
+
c, a, s, t = quads = Array.new(4) { Mouse.current_position }
|
330
|
+
c.x -= 10; c.y += 10
|
331
|
+
a.x += 10; a.y += 10
|
332
|
+
s.x += 10; s.y -= 10
|
333
|
+
t.x -= 10; t.y -= 10
|
334
|
+
elements = quads.map { |quad| element_at_point quad }
|
335
|
+
elements.uniq!
|
336
|
+
elements.map! { |el| el.kind_of?(AX::Menu) ? el : el.ancestor(:menu) }
|
337
|
+
elements.find { |element| element.present? }
|
309
338
|
end
|
310
339
|
|
311
340
|
|
312
|
-
#
|
341
|
+
# @!group Polling
|
313
342
|
|
314
343
|
##
|
315
344
|
# Simply wait around for something to show up. This method is similar
|
@@ -335,11 +364,12 @@ module Accessibility::DSL
|
|
335
364
|
# # Waiting for something that will never show up
|
336
365
|
# wait_for :a_million_dollars, ancestor: fruit_basket, timeout: 1000000
|
337
366
|
#
|
338
|
-
# @param [#to_s]
|
339
|
-
# @param [Hash]
|
367
|
+
# @param element [#to_s]
|
368
|
+
# @param filters [Hash]
|
340
369
|
# @option filters [Number] :timeout (5) timeout in seconds
|
341
370
|
# @option filters [AX::Element] :parent
|
342
371
|
# @option filters [AX::Element] :ancestor
|
372
|
+
# @yield Optional block used as a search filter
|
343
373
|
# @return [AX::Element,nil]
|
344
374
|
def wait_for element, filters = {}, &block
|
345
375
|
if filters.has_key? :ancestor
|
@@ -358,9 +388,9 @@ module Accessibility::DSL
|
|
358
388
|
#
|
359
389
|
# See {#wait_for} for more details.
|
360
390
|
#
|
361
|
-
# @param [#to_s]
|
362
|
-
# @param [AX::Element]
|
363
|
-
# @param [Hash]
|
391
|
+
# @param descendant [#to_s]
|
392
|
+
# @param ancestor [AX::Element]
|
393
|
+
# @param filters [Hash]
|
364
394
|
# @return [AX::Element,nil]
|
365
395
|
def wait_for_descendant descendant, ancestor, filters, &block
|
366
396
|
timeout = filters.delete(:timeout) || 5
|
@@ -388,9 +418,9 @@ module Accessibility::DSL
|
|
388
418
|
#
|
389
419
|
# See {#wait_for} for more details.
|
390
420
|
#
|
391
|
-
# @param [#to_s]
|
392
|
-
# @param [AX::Element]
|
393
|
-
# @param [Hash]
|
421
|
+
# @param child [#to_s]
|
422
|
+
# @param parent [AX::Element]
|
423
|
+
# @param filters [Hash]
|
394
424
|
# @return [AX::Element,nil]
|
395
425
|
def wait_for_child child, parent, filters, &block
|
396
426
|
timeout = filters.delete(:timeout) || 5
|
@@ -418,8 +448,8 @@ module Accessibility::DSL
|
|
418
448
|
# all search results have been returned.
|
419
449
|
#
|
420
450
|
# @overload wait_for_invalidation_of element
|
421
|
-
# @param [AX::Element]
|
422
|
-
# @param [Hash]
|
451
|
+
# @param element [AX::Element]
|
452
|
+
# @param filters [Hash]
|
423
453
|
# @option filters [Number] :timeout (5) in seconds
|
424
454
|
# @return [Boolean]
|
425
455
|
#
|
@@ -428,8 +458,8 @@ module Accessibility::DSL
|
|
428
458
|
# wait_for_invalidation_of table.row(static_text: { value: 'Cake' })
|
429
459
|
#
|
430
460
|
# @overload wait_for_invalidation_of kind, filters = {}, &block
|
431
|
-
# @param [#to_s]
|
432
|
-
# @param [Hash]
|
461
|
+
# @param element [#to_s]
|
462
|
+
# @param filters [Hash]
|
433
463
|
# @option filters [Number] :timeout (5) in seconds
|
434
464
|
# @return [Boolean]
|
435
465
|
#
|
@@ -458,7 +488,7 @@ module Accessibility::DSL
|
|
458
488
|
alias_method :wait_for_invalid, :wait_for_invalidation_of
|
459
489
|
|
460
490
|
|
461
|
-
#
|
491
|
+
# @!group Mouse Manipulation
|
462
492
|
|
463
493
|
##
|
464
494
|
# Move the mouse cursor to the given point or object on the screen.
|
@@ -469,13 +499,13 @@ module Accessibility::DSL
|
|
469
499
|
# move_mouse_to [344, 516]
|
470
500
|
# move_mouse_to CGPoint.new(100, 100)
|
471
501
|
#
|
472
|
-
# @param [#to_point]
|
473
|
-
# @param [Hash]
|
502
|
+
# @param arg [#to_point]
|
503
|
+
# @param opts [Hash]
|
474
504
|
# @option opts [Number] :duration (0.2) in seconds
|
475
505
|
# @option opts [Number] :wait (0.2) in seconds
|
476
506
|
def move_mouse_to arg, opts = {}
|
477
507
|
duration = opts[:duration] || 0.2
|
478
|
-
if Accessibility.debug? && arg.
|
508
|
+
if Accessibility.debug? && arg.kind_of?(AX::Element)
|
479
509
|
highlight arg, timeout: duration, color: NSColor.orangeColor
|
480
510
|
end
|
481
511
|
Mouse.move_to arg.to_point, duration
|
@@ -495,8 +525,8 @@ module Accessibility::DSL
|
|
495
525
|
# drag_mouse_to [100,100]
|
496
526
|
# drag_mouse_to drop_zone, from: desktop_icon
|
497
527
|
#
|
498
|
-
# @param [#to_point]
|
499
|
-
# @param [Hash]
|
528
|
+
# @param arg [#to_point]
|
529
|
+
# @param opts [Hash]
|
500
530
|
# @option opts [#to_point] :from a point to move to before dragging
|
501
531
|
# @option opts [Number] :duration (0.2) in seconds
|
502
532
|
# @option opts [Number] :wait (0.2) in seconds
|
@@ -516,14 +546,36 @@ module Accessibility::DSL
|
|
516
546
|
# If the second argument is provided then the mouse will move to that
|
517
547
|
# point first; the argument must respond to `#to_point`.
|
518
548
|
#
|
519
|
-
# @param [Number]
|
520
|
-
# @param [#to_point]
|
549
|
+
# @param lines [Number]
|
550
|
+
# @param obj [#to_point]
|
551
|
+
# @param wait [Number]
|
521
552
|
def scroll lines, obj = nil, wait = 0.1
|
522
553
|
move_mouse_to obj, wait: 0 if obj
|
523
554
|
Mouse.scroll lines
|
524
555
|
sleep wait
|
525
556
|
end
|
526
557
|
|
558
|
+
##
|
559
|
+
# @todo Need to expose the units option? Would allow scrolling by pixel.
|
560
|
+
#
|
561
|
+
# Horizontally scrolls an arbitrary number of lines at the mouses current
|
562
|
+
# point on the screen
|
563
|
+
#
|
564
|
+
# Use a positive number to scroll left, and a negative number to scroll
|
565
|
+
# right.
|
566
|
+
#
|
567
|
+
# If the second argument is provided then the mouse will move to that
|
568
|
+
# point first; the argument must respond to `#to_point`.
|
569
|
+
#
|
570
|
+
# @param lines [Number]
|
571
|
+
# @param obj [#to_point]
|
572
|
+
# @param wait [Number]
|
573
|
+
def horizontal_scroll lines, obj = nil, wait = 0.1
|
574
|
+
move_mouse_to obj, wait: 0 if obj
|
575
|
+
Mouse.horizontal_scroll lines
|
576
|
+
sleep wait
|
577
|
+
end
|
578
|
+
|
527
579
|
##
|
528
580
|
# Perform a regular click.
|
529
581
|
#
|
@@ -543,25 +595,35 @@ module Accessibility::DSL
|
|
543
595
|
#
|
544
596
|
# @yield Optionally take a block that is executed between click down
|
545
597
|
# and click up events.
|
546
|
-
# @param [#to_point]
|
598
|
+
# @param obj [#to_point]
|
547
599
|
def click obj = nil, wait = 0.2
|
548
600
|
move_mouse_to obj, wait: 0 if obj
|
549
601
|
Mouse.click_down
|
550
602
|
yield if block_given?
|
603
|
+
ensure
|
551
604
|
Mouse.click_up
|
552
605
|
sleep wait
|
553
606
|
end
|
554
607
|
|
555
608
|
##
|
556
|
-
# Perform a right (
|
609
|
+
# Perform a right (a.k.a. secondary) click action.
|
557
610
|
#
|
558
611
|
# If an argument is provided then the mouse will move to that point
|
559
612
|
# first; the argument must respond to `#to_point`.
|
560
613
|
#
|
561
|
-
#
|
614
|
+
# If a block is given, it will be yielded to between the click down
|
615
|
+
# and click up event. This behaviour is the same as passing a block
|
616
|
+
# to {DSL#click}.
|
617
|
+
#
|
618
|
+
# @yield Optionally take a block that is executed between click down
|
619
|
+
# and click up events.
|
620
|
+
# @param obj [#to_point]
|
562
621
|
def right_click obj = nil, wait = 0.2
|
563
622
|
move_mouse_to obj, wait: 0 if obj
|
564
|
-
Mouse.
|
623
|
+
Mouse.right_click_down
|
624
|
+
yield if block_given?
|
625
|
+
ensure
|
626
|
+
Mouse.right_click_up
|
565
627
|
sleep wait
|
566
628
|
end
|
567
629
|
alias_method :secondary_click, :right_click
|
@@ -572,15 +634,119 @@ module Accessibility::DSL
|
|
572
634
|
# If an argument is provided then the mouse will move to that point
|
573
635
|
# first; the argument must respond to `#to_point`.
|
574
636
|
#
|
575
|
-
# @param [#to_point]
|
637
|
+
# @param obj [#to_point]
|
576
638
|
def double_click obj = nil, wait = 0.2
|
577
639
|
move_mouse_to obj, wait: 0 if obj
|
578
640
|
Mouse.double_click
|
579
641
|
sleep wait
|
580
642
|
end
|
581
643
|
|
644
|
+
##
|
645
|
+
# Perform a triple click action
|
646
|
+
#
|
647
|
+
# If an argument is provided then the mouse will move to that point
|
648
|
+
# first; the argument must respond to `#to_point`.
|
649
|
+
#
|
650
|
+
# @param obj [#to_point]
|
651
|
+
def triple_click obj = nil, wait = 0.2
|
652
|
+
move_mouse_to obj, wait: 0 if obj
|
653
|
+
Mouse.triple_click
|
654
|
+
sleep wait
|
655
|
+
end
|
582
656
|
|
583
|
-
|
657
|
+
##
|
658
|
+
# Perform a swipe gesture in the given `direction`
|
659
|
+
#
|
660
|
+
# Valid directions are:
|
661
|
+
#
|
662
|
+
# - `:up`
|
663
|
+
# - `:down`
|
664
|
+
# - `:left`
|
665
|
+
# - `:right`
|
666
|
+
#
|
667
|
+
# An optional second argument can be provided. If the argument
|
668
|
+
# is provided then the mouse pointer will move to that point first.
|
669
|
+
#
|
670
|
+
# @example
|
671
|
+
#
|
672
|
+
# swipe :left, safari.web_area
|
673
|
+
#
|
674
|
+
# @param direction [Symbol]
|
675
|
+
# @param obj [#to_point]
|
676
|
+
def swipe direction, obj = nil, wait = 0.2
|
677
|
+
move_mouse_to obj, wait: 0 if obj
|
678
|
+
Mouse.swipe direction
|
679
|
+
sleep wait
|
680
|
+
end
|
681
|
+
|
682
|
+
##
|
683
|
+
# Perform a pinch gesture in the given `direction`
|
684
|
+
#
|
685
|
+
# You can optionally specify the `magnification` factor and
|
686
|
+
# `position` for the pinch event.
|
687
|
+
#*
|
688
|
+
# Available pinch directions are:
|
689
|
+
#
|
690
|
+
# - `:zoom` or `:expand`
|
691
|
+
# - `:unzoom` or `:contract`
|
692
|
+
#
|
693
|
+
# Magnification is a relative magnification setting. A zoom value of
|
694
|
+
# `1.0` means `1.0` more than the current zoom level. `2.0` would be
|
695
|
+
# `2.0` levels higher than the current zoom.
|
696
|
+
#
|
697
|
+
# You can also optionally specify an object/point on screen for the mouse
|
698
|
+
# pointer to be moved to before the gesture begins.
|
699
|
+
#
|
700
|
+
# @param direction [Symbol]
|
701
|
+
# @param magnification [Float]
|
702
|
+
# @param obj [#to_point]
|
703
|
+
def pinch direction, magnification = 1, obj = nil, wait = 0.2
|
704
|
+
move_mouse_to obj, wait: 0 if obj
|
705
|
+
Mouse.pinch direction, magnification
|
706
|
+
sleep wait
|
707
|
+
end
|
708
|
+
|
709
|
+
##
|
710
|
+
# Perform a rotation gesture in the given `direction` the given `angle` degrees
|
711
|
+
#
|
712
|
+
# Possible directions are:
|
713
|
+
#
|
714
|
+
# - `:cw`, ':clockwise`, ':clock_wise` to rotate in the clockwise
|
715
|
+
# direction
|
716
|
+
# - `:ccw`, ':counter_clockwise`, `:counter_clock_wise` to rotate in
|
717
|
+
# the the counter clockwise direction
|
718
|
+
#
|
719
|
+
# The `angle` parameter is a number of degrees to rotate. There are 360
|
720
|
+
# degrees in a full rotation, as you would expect in Euclidian geometry.
|
721
|
+
#
|
722
|
+
# You can also optionally specify an object/point on screen for the mouse
|
723
|
+
# pointer to be moved to before the gesture begins. The movement will
|
724
|
+
# be instantaneous.
|
725
|
+
#
|
726
|
+
# @param direction [Symbol]
|
727
|
+
# @param angle [Float]
|
728
|
+
# @param obj [#to_point]
|
729
|
+
def rotate direction, angle, obj = nil, wait = 0.2
|
730
|
+
move_mouse_to obj, wait: 0 if obj
|
731
|
+
Mouse.rotate direction, angle
|
732
|
+
sleep wait
|
733
|
+
end
|
734
|
+
|
735
|
+
##
|
736
|
+
# Perform a smart magnify (double tap on trackpad)
|
737
|
+
#
|
738
|
+
# You can optionally specify an object/point on the screen where to perform
|
739
|
+
# the smart magnification. The mouse will move to this point first
|
740
|
+
#
|
741
|
+
# @param obj [#to_point]
|
742
|
+
def smart_magnify obj = nil, wait = 0.2
|
743
|
+
move_mouse_to obj, wait: 0 if obj
|
744
|
+
Mouse.smart_magnify
|
745
|
+
sleep wait
|
746
|
+
end
|
747
|
+
|
748
|
+
|
749
|
+
# @!group Debug Helpers
|
584
750
|
|
585
751
|
##
|
586
752
|
# Highlight an element on screen. You can optionally specify the
|
@@ -603,32 +769,17 @@ module Accessibility::DSL
|
|
603
769
|
# # highlighter automatically turns off after 5 seconds
|
604
770
|
# highlight window.outline.row, colour: NSColor.greenColor, timeout: 5
|
605
771
|
#
|
606
|
-
# @param [#bounds]
|
607
|
-
# @param [Hash]
|
772
|
+
# @param obj [#bounds]
|
773
|
+
# @param opts [Hash]
|
608
774
|
# @option opts [Number] :timeout
|
609
775
|
# @option opts [NSColor] :colour (NSColor.magentaColor)
|
610
776
|
# @return [Accessibility::Highlighter]
|
611
777
|
def highlight obj, opts = {}
|
612
|
-
require 'accessibility/highlighter'
|
613
778
|
Accessibility::Highlighter.new obj.bounds, opts
|
614
779
|
end
|
615
780
|
|
616
781
|
##
|
617
|
-
#
|
618
|
-
# element. Each generation down the tree will be indented another level,
|
619
|
-
# and each element will be inspected.
|
620
|
-
#
|
621
|
-
# @example
|
622
|
-
#
|
623
|
-
# puts subtree app
|
624
|
-
#
|
625
|
-
# @return [String]
|
626
|
-
def subtree element
|
627
|
-
element.inspect_subtree
|
628
|
-
end
|
629
|
-
alias_method :subtree_for, :subtree
|
630
|
-
|
631
|
-
##
|
782
|
+
# @note This method is currently experimental
|
632
783
|
# @note You will need to have GraphViz command line tools installed
|
633
784
|
# in order for this to work.
|
634
785
|
#
|
@@ -639,7 +790,7 @@ module Accessibility::DSL
|
|
639
790
|
#
|
640
791
|
# graph app.main_window
|
641
792
|
#
|
642
|
-
# @param [AX::Element]
|
793
|
+
# @param element [AX::Element]
|
643
794
|
# @return [String] path to the saved image
|
644
795
|
def graph element
|
645
796
|
require 'accessibility/graph'
|
@@ -667,8 +818,8 @@ module Accessibility::DSL
|
|
667
818
|
# screenshot app.title, "/Volumes/SecretStash"
|
668
819
|
# # => "/Volumes/SecretStash/Safari-20120422184650.png"
|
669
820
|
#
|
670
|
-
# @param [#to_s]
|
671
|
-
# @param [#to_s]
|
821
|
+
# @param name [#to_s]
|
822
|
+
# @param dir [#to_s]
|
672
823
|
# @return [String] path to the screenshot
|
673
824
|
def screenshot name = "AXElements-ScreenShot", dir = '~/Desktop'
|
674
825
|
# @todo this could move to its own class, much like
|
@@ -691,8 +842,31 @@ module Accessibility::DSL
|
|
691
842
|
end
|
692
843
|
alias_method :capture_screen, :screenshot
|
693
844
|
|
845
|
+
##
|
846
|
+
# See (ScreenRecorder)[http://rdoc.info/gems/screen_recorder/frames]
|
847
|
+
# for details on the screen recording options
|
848
|
+
#
|
849
|
+
# @example
|
850
|
+
#
|
851
|
+
# file = record do
|
852
|
+
# run_tests
|
853
|
+
# end
|
854
|
+
# `open '#{file}'`
|
855
|
+
#
|
856
|
+
# @param file [String]
|
857
|
+
# @yield
|
858
|
+
# @yieldparam recorder [ScreenRecorder]
|
859
|
+
# @return [String]
|
860
|
+
def record file = nil, &block
|
861
|
+
require 'screen_recorder'
|
862
|
+
if file
|
863
|
+
ScreenRecorder.record file, &block
|
864
|
+
else
|
865
|
+
ScreenRecorder.record &block
|
866
|
+
end
|
867
|
+
end
|
694
868
|
|
695
|
-
#
|
869
|
+
# @!endgroup
|
696
870
|
|
697
871
|
|
698
872
|
##
|
@@ -704,10 +878,10 @@ module Accessibility::DSL
|
|
704
878
|
# app_with_bundle_identifier 'com.apple.finder'
|
705
879
|
# launch 'com.apple.mail'
|
706
880
|
#
|
707
|
-
# @param [String]
|
881
|
+
# @param id [String]
|
708
882
|
# @return [AX::Application,nil]
|
709
883
|
def app_with_bundle_identifier id
|
710
|
-
|
884
|
+
AX::Application.new id
|
711
885
|
end
|
712
886
|
alias_method :app_with_bundle_id, :app_with_bundle_identifier
|
713
887
|
alias_method :launch, :app_with_bundle_identifier
|
@@ -721,7 +895,7 @@ module Accessibility::DSL
|
|
721
895
|
#
|
722
896
|
# app_with_name 'Finder'
|
723
897
|
#
|
724
|
-
# @param [String]
|
898
|
+
# @param name [String]
|
725
899
|
# @return [AX::Application,nil]
|
726
900
|
def app_with_name name
|
727
901
|
AX::Application.new name
|
@@ -735,14 +909,14 @@ module Accessibility::DSL
|
|
735
909
|
#
|
736
910
|
# app_with_pid 35843
|
737
911
|
#
|
738
|
-
# @param [Fixnum]
|
912
|
+
# @param pid [Fixnum]
|
739
913
|
# @return [AX::Application]
|
740
914
|
def app_with_pid pid
|
741
915
|
AX::Application.new pid
|
742
916
|
end
|
743
917
|
|
744
918
|
##
|
745
|
-
#
|
919
|
+
# Synonym for `AX::SystemWide.new`.
|
746
920
|
#
|
747
921
|
# @return [AX::SystemWide]
|
748
922
|
def system_wide
|
@@ -775,8 +949,8 @@ module Accessibility::DSL
|
|
775
949
|
#
|
776
950
|
# element_at window # find out what is in the middle of the window
|
777
951
|
#
|
778
|
-
# @param [#to_point]
|
779
|
-
# @param [Hash]
|
952
|
+
# @param point [#to_point]
|
953
|
+
# @param opts [Hash]
|
780
954
|
# @option opts [AX::Application] :for
|
781
955
|
# @return [AX::Element]
|
782
956
|
def element_at_point point, opts = {}
|