AXElements 0.7.8 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -30,11 +30,12 @@ module Accessibility::Enumerators
|
|
30
30
|
end
|
31
31
|
|
32
32
|
##
|
33
|
-
# @note Explicitly defined so that escaping at the first found
|
34
|
-
# actually works. Since only a single `break` is
|
35
|
-
# item is found it does not fully escape the
|
36
|
-
# we need to do this
|
37
|
-
# they aren't
|
33
|
+
# @note Explicitly defined so that escaping at the first found
|
34
|
+
# element actually works. Since only a single `break` is
|
35
|
+
# called when an item is found it does not fully escape the
|
36
|
+
# built in implementation. Technically, we need to do this
|
37
|
+
# with other 'escape-early' iteraters, but they aren't
|
38
|
+
# being used...yet.
|
38
39
|
#
|
39
40
|
# Override `Enumerable#find` for performance reasons.
|
40
41
|
def find
|
@@ -60,14 +61,14 @@ module Accessibility::Enumerators
|
|
60
61
|
until stack.empty?
|
61
62
|
current = stack.shift
|
62
63
|
yield current
|
63
|
-
# needed to reverse
|
64
|
+
# needed to reverse, child ordering matters in practice
|
64
65
|
stack.unshift *current.children
|
65
66
|
end
|
66
67
|
end
|
67
68
|
|
68
69
|
##
|
69
|
-
# Walk the UI element tree and yield both the element and the
|
70
|
-
# that the element is at relative to the root.
|
70
|
+
# Walk the UI element tree and yield both the element and the
|
71
|
+
# level that the element is at relative to the root.
|
71
72
|
#
|
72
73
|
# @yieldparam [AX::Element,AXUIElementRef]
|
73
74
|
# @yieldparam [Number]
|
data/lib/accessibility/errors.rb
CHANGED
@@ -1,32 +1,31 @@
|
|
1
|
-
require 'accessibility/debug'
|
2
|
-
|
3
1
|
##
|
4
2
|
# Error raised when an implicit search fails to return a result.
|
5
3
|
class Accessibility::SearchFailure < NoMethodError
|
6
4
|
|
5
|
+
# @param [AX::Element]
|
6
|
+
# @param [#to_s]
|
7
|
+
# @param [Hash{Symbol=>Object}]
|
7
8
|
def initialize searcher, searchee, filters
|
8
9
|
filters = {} unless filters.kind_of? Hash
|
9
10
|
msg = "Could not find `#{pp_searchee searchee, filters}` "
|
10
11
|
msg << "as a child of #{searcher.class}\n"
|
11
12
|
msg << "Element Path:\n\t" << path_to(searcher)
|
12
13
|
# @todo Consider turning this on by default
|
13
|
-
msg << "\nSubtree:\n\
|
14
|
+
msg << "\nSubtree:\n\n" << subtree_for(searcher) if Accessibility.debug?
|
14
15
|
super msg
|
15
16
|
end
|
16
17
|
|
17
18
|
|
18
19
|
private
|
19
20
|
|
21
|
+
# Nice string representation of what was being searched for
|
20
22
|
def pp_searchee searchee, filters
|
21
23
|
Accessibility::Qualifier.new(searchee, filters).describe
|
22
24
|
end
|
23
25
|
|
26
|
+
# Nice string representation of element's path from the application root
|
24
27
|
def path_to element
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
def debug searcher
|
29
|
-
Accessibility::Debug.text_subtree(searcher)
|
28
|
+
element.ancestry.map! { |x| x.inspect }.join("\n\t")
|
30
29
|
end
|
31
30
|
|
32
31
|
end
|
@@ -9,13 +9,20 @@ module AX; end
|
|
9
9
|
# Mixin made for processing low level data from AXAPI methods.
|
10
10
|
module Accessibility::Factory
|
11
11
|
|
12
|
+
# @todo This should provide alternate #to_ruby functionality for
|
13
|
+
# the __NSCFType class in order to avoid the overhead of
|
14
|
+
# checking type information (or at least reducing it).
|
15
|
+
# However, it will force the lower level to always wrap
|
16
|
+
# element references; this should be ok most of the time
|
17
|
+
# but makes testing a bit of a pain...hmmm
|
18
|
+
|
12
19
|
##
|
13
|
-
# Processes any given data from an AXAPI
|
14
|
-
# needed. Meant for taking a return value from
|
15
|
-
# and friends.
|
20
|
+
# Processes any given data from an AXAPI function and wraps it if
|
21
|
+
# needed. Meant for taking a return value from
|
22
|
+
# {Accessibility::Core#attribute} and friends.
|
16
23
|
#
|
17
|
-
# Generally, used to process an `
|
18
|
-
#
|
24
|
+
# Generally, used to process an `AXUIElementRef` into a some kind
|
25
|
+
# of {AX::Element} subclass.
|
19
26
|
def process value
|
20
27
|
return nil if value.nil? # CFGetTypeID(nil) crashes runtime
|
21
28
|
case CFGetTypeID(value)
|
@@ -73,7 +80,7 @@ module Accessibility::Factory
|
|
73
80
|
subrole = ref.subrole
|
74
81
|
# Some objects claim to have a subrole but return nil
|
75
82
|
if subrole
|
76
|
-
|
83
|
+
class_for2(TRANSLATOR.unprefix(subrole), role).new ref
|
77
84
|
else
|
78
85
|
class_for(role).new ref
|
79
86
|
end
|
@@ -118,12 +125,12 @@ module Accessibility::Factory
|
|
118
125
|
# @param [#to_s]
|
119
126
|
# @param [#to_s]
|
120
127
|
# @return [Class]
|
121
|
-
def
|
128
|
+
def class_for2 subrole, role
|
122
129
|
# @todo it would be nice if we didn't have to lookup twice
|
123
130
|
if AX.const_defined? subrole, false
|
124
131
|
AX.const_get subrole
|
125
132
|
else
|
126
|
-
|
133
|
+
create_class2 subrole, role
|
127
134
|
end
|
128
135
|
end
|
129
136
|
|
@@ -145,7 +152,7 @@ module Accessibility::Factory
|
|
145
152
|
# @param [#to_s] name
|
146
153
|
# @param [#to_s] superklass
|
147
154
|
# @return [Class]
|
148
|
-
def
|
155
|
+
def create_class2 name, superklass
|
149
156
|
unless AX.const_defined? superklass, false
|
150
157
|
create_class superklass
|
151
158
|
end
|
data/lib/accessibility/graph.rb
CHANGED
@@ -4,11 +4,13 @@
|
|
4
4
|
# an image for the graph.
|
5
5
|
#
|
6
6
|
# You can learn more about generating graphs in the
|
7
|
-
#
|
7
|
+
# [Debugging tutorial](http://github.com/Marketcircle/AXElements/wiki/Debugging).
|
8
|
+
#
|
9
|
+
# [Learn more about GraphViz](http://www.graphviz.org/).
|
8
10
|
class Accessibility::Graph
|
9
11
|
|
10
12
|
##
|
11
|
-
# @todo Graphs could be
|
13
|
+
# @todo Graphs could be nicer looking. That is, nodes could be much
|
12
14
|
# more easily identifiable, by allowing different classes to tell
|
13
15
|
# the node more about itself. A mixin module/protocol should
|
14
16
|
# probably be created, just as with the inspector mixin, and added
|
@@ -35,38 +37,82 @@ class Accessibility::Graph
|
|
35
37
|
|
36
38
|
# @return [String]
|
37
39
|
def to_dot
|
38
|
-
"#{@id} #{identifier}
|
40
|
+
"#{@id} #{identifier} [shape=#{shape}] [style=#{style}] [color=#{colour}]"
|
39
41
|
end
|
40
42
|
|
41
43
|
|
42
44
|
private
|
43
45
|
|
44
|
-
EMPTY_STRING = ''
|
45
|
-
NAMESPACE = '::'
|
46
|
-
|
47
46
|
def identifier
|
48
47
|
klass = @element.class.to_s.split(NAMESPACE).last
|
49
|
-
ident = @element.pp_identifier
|
48
|
+
ident = @element.pp_identifier.dup
|
49
|
+
if ident.length > 12
|
50
|
+
ident = "#{ident[0...12]}..."
|
51
|
+
end
|
52
|
+
ident << '"' if ident[1] == QUOTE && ident[-1] != QUOTE
|
50
53
|
ident.gsub! /"/, '\"'
|
54
|
+
ident.gsub! /\\/, '\\'
|
51
55
|
"[label = \"#{klass}#{ident}\"]"
|
52
56
|
end
|
53
57
|
|
54
58
|
def shape
|
55
|
-
@element.
|
59
|
+
(@element.attribute(:focused) && OCTAGON) ||
|
60
|
+
(@element.actions.empty? && OVAL) ||
|
61
|
+
BOX
|
56
62
|
end
|
57
63
|
|
58
|
-
def
|
59
|
-
|
64
|
+
def style
|
65
|
+
# fill in the node if it is disabled (greyed out effect)
|
66
|
+
if @element.attributes.include?(:enabled)
|
67
|
+
return FILLED unless @element.attribute(:enabled)
|
68
|
+
end
|
69
|
+
# bold if focused and no children
|
70
|
+
if @element.attribute(:focused)
|
71
|
+
return BOLD if @element.size_of(:children).zero?
|
72
|
+
end
|
73
|
+
SOLID
|
60
74
|
end
|
61
75
|
|
62
|
-
def
|
63
|
-
|
76
|
+
def colour
|
77
|
+
if @element.attributes.include?(:enabled)
|
78
|
+
return GREY unless @element.attribute(:enabled)
|
79
|
+
end
|
80
|
+
BLACK
|
64
81
|
end
|
65
82
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
83
|
+
# @private
|
84
|
+
# @return [String]
|
85
|
+
EMPTY_STRING = ''
|
86
|
+
# @private
|
87
|
+
# @return [String]
|
88
|
+
NAMESPACE = '::'
|
89
|
+
# @private
|
90
|
+
# @return [String]
|
91
|
+
QUOTE = '"'
|
92
|
+
# @private
|
93
|
+
# @return [String]
|
94
|
+
OVAL = 'oval'
|
95
|
+
# @private
|
96
|
+
# @return [String]
|
97
|
+
BOX = 'box'
|
98
|
+
# @private
|
99
|
+
# @return [String]
|
100
|
+
OCTAGON = 'doubleoctagon'
|
101
|
+
# @private
|
102
|
+
# @return [String]
|
103
|
+
BOLD = 'bold'
|
104
|
+
# @private
|
105
|
+
# @return [String]
|
106
|
+
FILLED = 'filled'
|
107
|
+
# @private
|
108
|
+
# @return [String]
|
109
|
+
SOLID = 'solid'
|
110
|
+
# @private
|
111
|
+
# @return [String]
|
112
|
+
GREY = 'grey'
|
113
|
+
# @private
|
114
|
+
# @return [String]
|
115
|
+
BLACK = 'black'
|
70
116
|
end
|
71
117
|
|
72
118
|
##
|
@@ -83,8 +129,7 @@ class Accessibility::Graph
|
|
83
129
|
# @param [Accessibility::Graph::Node]
|
84
130
|
# @param [Accessibility::Graph::Node]
|
85
131
|
def initialize head, tail
|
86
|
-
@head = head
|
87
|
-
@tail = tail
|
132
|
+
@head, @tail = head, tail
|
88
133
|
end
|
89
134
|
|
90
135
|
# @return [String]
|
@@ -117,7 +162,7 @@ class Accessibility::Graph
|
|
117
162
|
# exploit the ordering of a breadth-first enumeration to simplify
|
118
163
|
# the creation of edges for the graph. This only works because
|
119
164
|
# the UI hiearchy is a simple tree.
|
120
|
-
@edge_queue = Array.new(root.
|
165
|
+
@edge_queue = Array.new(root.children.size, root_node)
|
121
166
|
end
|
122
167
|
|
123
168
|
##
|
@@ -130,7 +175,8 @@ class Accessibility::Graph
|
|
130
175
|
Accessibility::Enumerators::BreadthFirst.new(nodes.last.element).each do |element|
|
131
176
|
nodes << node = Node.new(element)
|
132
177
|
edges << Edge.new(node, @edge_queue.shift)
|
133
|
-
|
178
|
+
# should use #size_of(:children), but that doesn't in all cases
|
179
|
+
@edge_queue.concat Array.new(element.children.size, node)
|
134
180
|
end
|
135
181
|
end
|
136
182
|
|
@@ -141,9 +187,9 @@ class Accessibility::Graph
|
|
141
187
|
# @return [String]
|
142
188
|
def to_dot
|
143
189
|
graph = "digraph {\n"
|
144
|
-
graph << nodes.map(&:to_dot).join("
|
190
|
+
graph << nodes.map(&:to_dot).join(";\n")
|
145
191
|
graph << "\n\n"
|
146
|
-
graph << edges.map(&:to_dot).join("
|
192
|
+
graph << edges.map(&:to_dot).join(";\n")
|
147
193
|
graph << "\n}\n"
|
148
194
|
end
|
149
195
|
|
@@ -0,0 +1,86 @@
|
|
1
|
+
framework 'AppKit'
|
2
|
+
require 'accessibility/version'
|
3
|
+
|
4
|
+
##
|
5
|
+
# A screen highlighter for debugging. When you initialize a highligter
|
6
|
+
# object it will highlight the given bounds on the screen.
|
7
|
+
#
|
8
|
+
# Highligter objects can have their colour configured at initialization,
|
9
|
+
# and can also have a timeout to automatically stop displaying.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
#
|
13
|
+
# h = Accessibility::Highlighter.new(CGRectMake(100,100,100,100))
|
14
|
+
# # when you are done...
|
15
|
+
# h.stop
|
16
|
+
#
|
17
|
+
class Accessibility::Highlighter < NSWindow
|
18
|
+
|
19
|
+
# @param [CGRect]
|
20
|
+
# @param [Hash] opts
|
21
|
+
# @option opts [Number] :timeout
|
22
|
+
# @option opts [NSColor] :colour (NSColor.magentaColor)
|
23
|
+
def initialize bounds, opts = {}
|
24
|
+
colour = opts[:colour] || opts[:color] || NSColor.magentaColor
|
25
|
+
|
26
|
+
bounds.flip! # we assume the rect is in the other co-ordinate system
|
27
|
+
|
28
|
+
initWithContentRect bounds,
|
29
|
+
styleMask: NSBorderlessWindowMask,
|
30
|
+
backing: NSBackingStoreBuffered,
|
31
|
+
defer: true
|
32
|
+
setOpaque false
|
33
|
+
setAlphaValue 0.20
|
34
|
+
setLevel NSStatusWindowLevel
|
35
|
+
setBackgroundColor colour
|
36
|
+
setIgnoresMouseEvents true
|
37
|
+
setFrame bounds, display: false
|
38
|
+
makeKeyAndOrderFront NSApp
|
39
|
+
|
40
|
+
if opts.has_key? :timeout
|
41
|
+
Dispatch::Queue.new(queue_id).after opts[:timeout] do
|
42
|
+
self.stop
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Tell the highlighter to stop displaying.
|
49
|
+
#
|
50
|
+
# @return [self]
|
51
|
+
def stop
|
52
|
+
close
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def queue_id
|
59
|
+
"com.marketcircle.axelements.window_killer_#{hash}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
##
|
65
|
+
# AXElements extensions to `CGRect`.
|
66
|
+
class CGRect
|
67
|
+
##
|
68
|
+
# Treats the rect as belonging to one co-ordinate system and then
|
69
|
+
# converts it to the other system.
|
70
|
+
#
|
71
|
+
# This is useful because accessibility API's expect to work with
|
72
|
+
# the flipped co-ordinate system (origin in top left), but AppKit
|
73
|
+
# prefers to use the cartesian co-ordinate system (origin in bottom
|
74
|
+
# left).
|
75
|
+
#
|
76
|
+
# @return [CGRect]
|
77
|
+
def flip!
|
78
|
+
screen_height = NSMaxY(NSScreen.mainScreen.frame)
|
79
|
+
origin.y = screen_height - NSMaxY(self)
|
80
|
+
self
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
# Initialize the shared application so that windows can be created
|
86
|
+
NSApplication.sharedApplication
|
@@ -13,8 +13,8 @@
|
|
13
13
|
module Accessibility::PPInspector
|
14
14
|
|
15
15
|
##
|
16
|
-
# Create an identifier for
|
17
|
-
# make it very easy to identify the element.
|
16
|
+
# Create an identifier for the receiver by using various attributes
|
17
|
+
# that should make it very easy to identify the element.
|
18
18
|
#
|
19
19
|
# @return [String]
|
20
20
|
def pp_identifier
|
@@ -55,7 +55,7 @@ module Accessibility::PPInspector
|
|
55
55
|
|
56
56
|
##
|
57
57
|
# Create a string that succinctly encodes the screen coordinates
|
58
|
-
# of
|
58
|
+
# of the receiver.
|
59
59
|
#
|
60
60
|
# @return [String]
|
61
61
|
def pp_position
|
@@ -69,7 +69,7 @@ module Accessibility::PPInspector
|
|
69
69
|
|
70
70
|
##
|
71
71
|
# Create a string that nicely presents the number of children
|
72
|
-
# that
|
72
|
+
# that the receiver has.
|
73
73
|
#
|
74
74
|
# @return [String]
|
75
75
|
def pp_children
|
@@ -10,7 +10,7 @@ class Accessibility::Qualifier
|
|
10
10
|
# Initialize a qualifier with the kind of object that you want to
|
11
11
|
# qualify and a dictionary of filter criteria. You can optionally
|
12
12
|
# pass a block if your qualification criteria is too complicated
|
13
|
-
# for key/value pairs
|
13
|
+
# for key/value pairs; the blocks return value will be used to
|
14
14
|
# determine if an element qualifies.
|
15
15
|
#
|
16
16
|
# @example
|
@@ -22,7 +22,7 @@ class Accessibility::Qualifier
|
|
22
22
|
# element.children.size > 5 && NSContainsRect(element.bounds, rect)
|
23
23
|
# end
|
24
24
|
#
|
25
|
-
# @param [#to_s]
|
25
|
+
# @param [#to_s]
|
26
26
|
# @param [Hash]
|
27
27
|
# @yield Optional block that can qualify an element
|
28
28
|
def initialize klass, criteria
|
@@ -41,6 +41,10 @@ class Accessibility::Qualifier
|
|
41
41
|
the_right_type?(element) && meets_criteria?(element)
|
42
42
|
end
|
43
43
|
|
44
|
+
##
|
45
|
+
# Return a compact description of the qualifier. If the qualifier
|
46
|
+
# includes a block then a checkmarked box will be included.
|
47
|
+
#
|
44
48
|
# @return [String]
|
45
49
|
def describe
|
46
50
|
"#{@klass}#{@criteria.ax_pp}#{@block ? '[✔]' : ''}"
|
@@ -49,16 +53,14 @@ class Accessibility::Qualifier
|
|
49
53
|
|
50
54
|
private
|
51
55
|
|
52
|
-
##
|
53
56
|
# @private
|
54
|
-
#
|
55
|
-
# Local reference to the {Accessibility::Translator}.
|
56
|
-
#
|
57
57
|
# @return [Accessibility::Translator]
|
58
58
|
TRANSLATOR = Accessibility::Translator.instance
|
59
59
|
|
60
60
|
##
|
61
61
|
# Take a hash of search filters and generate an optimized search
|
62
|
+
# array. This is done to avoid checking types for each call to
|
63
|
+
# {#qualifies?}.
|
62
64
|
#
|
63
65
|
# @param [Hash]
|
64
66
|
def compile criteria
|
@@ -118,11 +120,11 @@ class Accessibility::Qualifier
|
|
118
120
|
end
|
119
121
|
|
120
122
|
def parameterized_match attr, param, regexp, element
|
121
|
-
element.
|
123
|
+
element.parameterized_attribute(attr, param).to_s.match regexp
|
122
124
|
end
|
123
125
|
|
124
126
|
def parameterized_equality attr, param, value, element
|
125
|
-
element.
|
127
|
+
element.parameterized_attribute(attr, param) == value
|
126
128
|
end
|
127
129
|
|
128
130
|
def block_check element
|
@@ -133,7 +135,7 @@ end
|
|
133
135
|
|
134
136
|
|
135
137
|
##
|
136
|
-
#
|
138
|
+
# AXElements extensions to `NSDictionary`.
|
137
139
|
class NSDictionary
|
138
140
|
##
|
139
141
|
# Format the hash for AXElements pretty printing.
|
data/lib/accessibility/string.rb
CHANGED
@@ -26,7 +26,7 @@ module Accessibility::String
|
|
26
26
|
# {Accessibility::String::EventGenerator::CUSTOM}.
|
27
27
|
#
|
28
28
|
# For more details on event generation, read the
|
29
|
-
#
|
29
|
+
# [Keyboarding documentation](http://github.com/Marketcircle/AXElements/wiki/Keyboarding).
|
30
30
|
#
|
31
31
|
# @param [String]
|
32
32
|
# @return [Array<Array(Fixnum,Boolean)>]
|
@@ -43,7 +43,7 @@ module Accessibility::String
|
|
43
43
|
# @example
|
44
44
|
#
|
45
45
|
# Lexer.new("Hai").lex # => ['H','a','i']
|
46
|
-
# Lexer.new("\\
|
46
|
+
# Lexer.new("\\CONTROL").lex # => [["\\CONTROL"]]
|
47
47
|
# Lexer.new("\\COMMAND+a").lex # => [["\\COMMAND", ['a']]]
|
48
48
|
# Lexer.new("One\nTwo").lex # => ['O','n','e',"\n",'T','w','o']
|
49
49
|
#
|
@@ -132,10 +132,13 @@ module Accessibility::String
|
|
132
132
|
end
|
133
133
|
|
134
134
|
# @private
|
135
|
+
# @return [String]
|
135
136
|
SPACE = " "
|
136
137
|
# @private
|
138
|
+
# @return [String]
|
137
139
|
PLUS = "+"
|
138
140
|
# @private
|
141
|
+
# @return [String]
|
139
142
|
CUSTOM_ESCAPE = "\\"
|
140
143
|
end
|
141
144
|
|
@@ -150,8 +153,8 @@ module Accessibility::String
|
|
150
153
|
# # Upper case 'A'
|
151
154
|
# EventGenerator.new(["A"]).generate # => [[56,true],[70,true],[70,false],[56,false]]
|
152
155
|
#
|
153
|
-
# # Press the
|
154
|
-
# EventGenerator.new([["\\
|
156
|
+
# # Press the volume up key
|
157
|
+
# EventGenerator.new([["\\F12"]]).generate # => [[0x6F,true],[0x6F,false]]
|
155
158
|
#
|
156
159
|
# # Hotkey, press and hold command key and then 'a', then release both
|
157
160
|
# EventGenerator.new([["\\CMD",["a"]]]).generate # => [[55,true],[70,true],[70,false],[55,false]]
|
@@ -470,14 +473,19 @@ module Accessibility::String
|
|
470
473
|
end
|
471
474
|
|
472
475
|
# @private
|
476
|
+
# @return [String]
|
473
477
|
EMPTY_STRING = ""
|
474
478
|
# @private
|
479
|
+
# @return [Array(Number,Boolean)]
|
475
480
|
OPTION_DOWN = [58, true]
|
476
481
|
# @private
|
482
|
+
# @return [Array(Number,Boolean)]
|
477
483
|
OPTION_UP = [58, false]
|
478
484
|
# @private
|
485
|
+
# @return [Array(Number,Boolean)]
|
479
486
|
SHIFT_DOWN = [56, true]
|
480
487
|
# @private
|
488
|
+
# @return [Array(Number,Boolean)]
|
481
489
|
SHIFT_UP = [56, false]
|
482
490
|
end
|
483
491
|
|
@@ -16,9 +16,16 @@ end
|
|
16
16
|
|
17
17
|
##
|
18
18
|
# Maintain all the rules for transforming Cocoa constants into something
|
19
|
-
# a little more Rubyish
|
19
|
+
# a little more Rubyish and taking the Rubyish symbols and translating
|
20
|
+
# them back to Cocoa constants.
|
20
21
|
class Accessibility::Translator
|
21
22
|
|
23
|
+
##
|
24
|
+
# Get the singleton instance of the {Accessibility::Translator} class.
|
25
|
+
# This is meant to mimic the important functionality of the
|
26
|
+
# `Singleton` mix-in.
|
27
|
+
#
|
28
|
+
# @return [Accessibility::Translator]
|
22
29
|
def self.instance
|
23
30
|
@instance ||= new
|
24
31
|
end
|
@@ -54,6 +61,14 @@ class Accessibility::Translator
|
|
54
61
|
@unprefixes[key]
|
55
62
|
end
|
56
63
|
|
64
|
+
##
|
65
|
+
# Take an array of Cocoa accessibility constants and return an
|
66
|
+
# array of shortened Ruby symbols.
|
67
|
+
#
|
68
|
+
# @example
|
69
|
+
#
|
70
|
+
# rubyize ["AXRole", "AXTitleUIElement"] # => [:role, :title_ui_element]
|
71
|
+
#
|
57
72
|
# @return [Array<Symbol>]
|
58
73
|
def rubyize keys
|
59
74
|
keys.map { |x| @rubyisms[x] }
|
@@ -102,7 +117,9 @@ class Accessibility::Translator
|
|
102
117
|
|
103
118
|
##
|
104
119
|
# Try to turn an arbitrary symbol into a notification constant, and
|
105
|
-
# then get the value of the constant.
|
120
|
+
# then get the value of the constant. If it cannot be turned into
|
121
|
+
# a notification constant then the original string parameter will
|
122
|
+
# be returned.
|
106
123
|
#
|
107
124
|
# @param [#to_s]
|
108
125
|
# @return [String]
|
@@ -156,19 +173,11 @@ class Accessibility::Translator
|
|
156
173
|
end
|
157
174
|
end
|
158
175
|
|
159
|
-
##
|
160
176
|
# @private
|
161
|
-
#
|
162
|
-
# Cached for performance.
|
163
|
-
#
|
164
177
|
# @return [String]
|
165
178
|
EMPTY_STRING = ''
|
166
179
|
|
167
|
-
##
|
168
180
|
# @private
|
169
|
-
#
|
170
|
-
# Performance hack.
|
171
|
-
#
|
172
181
|
# @return [String]
|
173
182
|
QUESTION_MARK = '?'
|
174
183
|
end
|