AXElements 1.0.0.alpha7 → 1.0.0.alpha8

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 CHANGED
@@ -1,5 +1,9 @@
1
1
  # 1.0.0
2
2
 
3
+ * Added History.markdown to track notable changes
4
+
5
+ * Ported `mouse.rb` to C and moved code to [MRMouse](https://github.com/ferrous26/MRMouse)
6
+
3
7
  * Remove `Accessibility.application_with_bundle_identifier`; use `AX::Application.new` instead
4
8
  * Remove `Accessibility.application_with_name; use `AX::Application.new` instead
5
9
  * Remove `DSL#subtree_for`; use `Element#inspect_subtree` instead
@@ -47,7 +47,7 @@ class Accessibility::Graph
47
47
 
48
48
  def identifier
49
49
  klass = @element.class.to_s.split(NAMESPACE).last
50
- ident = @element.pp_identifier.dup
50
+ ident = @element.pp_identifier.to_s.dup
51
51
  if ident.length > 12
52
52
  ident = "#{ident[0...12]}..."
53
53
  end
@@ -58,9 +58,13 @@ class Accessibility::Graph
58
58
  end
59
59
 
60
60
  def shape
61
- (@element.attribute(:focused) && OCTAGON) ||
62
- (@element.actions.empty? && OVAL) ||
63
- BOX
61
+ if @element.attributes.include?(:focused) && @element.attribute(:focused)
62
+ OCTAGON
63
+ elsif @element.actions.empty?
64
+ OVAL
65
+ else
66
+ BOX
67
+ end
64
68
  end
65
69
 
66
70
  def style
@@ -69,7 +73,7 @@ class Accessibility::Graph
69
73
  return FILLED unless @element.attribute(:enabled)
70
74
  end
71
75
  # bold if focused and no children
72
- if @element.attribute(:focused)
76
+ if @element.attributes.include?(:focused) && @element.attribute(:focused)
73
77
  return BOLD if @element.size_of(:children).zero?
74
78
  end
75
79
  SOLID
@@ -16,7 +16,7 @@ module Accessibility::PrettyPrinter
16
16
  # Create an identifier for the receiver by using various attributes
17
17
  # that should make it very easy to identify the element.
18
18
  #
19
- # @return [String]
19
+ # @return [String,#to_s]
20
20
  def pp_identifier
21
21
  # @note use, or lack of use, of #inspect is intentional for visual effect
22
22
 
@@ -49,8 +49,7 @@ module Accessibility::PrettyPrinter
49
49
  return " id=#{attribute(:identifier)}"
50
50
  end
51
51
 
52
- # @todo should we have other fallbacks?
53
- return EMPTY_STRING
52
+ rescue NoMethodError
54
53
  end
55
54
 
56
55
  ##
@@ -4,7 +4,7 @@
4
4
  # The main AXElements namespace.
5
5
  module Accessibility
6
6
  # @return [String]
7
- VERSION = '1.0.0.alpha7'
7
+ VERSION = '1.0.0.alpha8'
8
8
 
9
9
  # @return [String]
10
10
  CODE_NAME = 'ルナトーン'
data/lib/ax/element.rb CHANGED
@@ -360,7 +360,7 @@ class AX::Element
360
360
  #
361
361
  # @return [String]
362
362
  def inspect
363
- msg = "#<#{self.class}" << pp_identifier
363
+ msg = "#<#{self.class}" << pp_identifier.to_s
364
364
  msg << pp_position if attributes.include? :position
365
365
  msg << pp_children if attributes.include? :children
366
366
  msg << pp_checkbox(:enabled) if attributes.include? :enabled
@@ -226,32 +226,6 @@ class TestAccessibilityDSL < MiniTest::Unit::TestCase
226
226
  assert @got_called
227
227
  end
228
228
 
229
- def test_dump_works_for_nested_tab_groups
230
- output = dsl.subtree_for app.window.tab_group
231
-
232
- expected = [
233
- ['AX::TabGroup', 0],
234
- ['AX::RadioButton', 1], ['AX::RadioButton', 1], ['AX::TabGroup', 1],
235
- ['AX::RadioButton', 2], ['AX::RadioButton', 2], ['AX::TabGroup', 2],
236
- ['AX::RadioButton', 3], ['AX::RadioButton', 3], ['AX::TabGroup', 3],
237
- ['AX::RadioButton', 4], ['AX::RadioButton', 4],
238
- ['AX::Group', 4],
239
- ['AX::TextField', 5], ['AX::StaticText', 6],
240
- ['AX::TextField' , 5], ['AX::StaticText', 6]
241
- ]
242
-
243
- refute_empty output
244
- output = output.split("\n")
245
-
246
- until output.empty?
247
- line = output.shift
248
- klass, indents = expected.shift
249
- assert_equal indents, line.match(/^\t*/).to_a.first.length, line
250
- line.strip!
251
- assert_match /^\#<#{klass}/, line
252
- end
253
- end
254
-
255
229
  def test_screenshot
256
230
  path = dsl.screenshot
257
231
  assert File.exists? path
@@ -52,4 +52,30 @@ class TestAXElement < MiniTest::Unit::TestCase
52
52
  assert bye.invalid?
53
53
  end
54
54
 
55
+ def test_dump_works_for_nested_tab_groups
56
+ output = app.window.tab_group.inspect_subtree
57
+
58
+ expected = [
59
+ ['AX::TabGroup', 0],
60
+ ['AX::RadioButton', 1], ['AX::RadioButton', 1], ['AX::TabGroup', 1],
61
+ ['AX::RadioButton', 2], ['AX::RadioButton', 2], ['AX::TabGroup', 2],
62
+ ['AX::RadioButton', 3], ['AX::RadioButton', 3], ['AX::TabGroup', 3],
63
+ ['AX::RadioButton', 4], ['AX::RadioButton', 4],
64
+ ['AX::Group', 4],
65
+ ['AX::TextField', 5], ['AX::StaticText', 6],
66
+ ['AX::TextField' , 5], ['AX::StaticText', 6]
67
+ ]
68
+
69
+ refute_empty output
70
+ output = output.split("\n")
71
+
72
+ until output.empty?
73
+ line = output.shift
74
+ klass, indents = expected.shift
75
+ assert_equal indents, line.match(/^\t*/).to_a.first.length, line
76
+ line.strip!
77
+ assert_match /^\#<#{klass}/, line
78
+ end
79
+ end
80
+
55
81
  end
@@ -18,10 +18,10 @@ class TestAccessibilityPrettyPrinter < MiniTest::Unit::TestCase
18
18
  assert_match /value=3.14/, pp_identifier
19
19
 
20
20
  @attribute = ''
21
- assert_match EMPTY_STRING, pp_identifier
21
+ assert_match EMPTY_STRING, pp_identifier.to_s
22
22
 
23
23
  @attribute = nil
24
- assert_match EMPTY_STRING, pp_identifier
24
+ assert_match EMPTY_STRING, pp_identifier.to_s
25
25
  end
26
26
 
27
27
  def test_identifier_using_title
@@ -44,7 +44,7 @@ class TestAccessibilityPrettyPrinter < MiniTest::Unit::TestCase
44
44
  assert_match /roflcopter/, pp_identifier
45
45
 
46
46
  @attribute = NSString.string
47
- assert_equal EMPTY_STRING, pp_identifier
47
+ assert_equal EMPTY_STRING, pp_identifier.to_s
48
48
 
49
49
  @attribute = 26
50
50
  assert_match /26/, pp_identifier
@@ -62,7 +62,7 @@ class TestAccessibilityPrettyPrinter < MiniTest::Unit::TestCase
62
62
 
63
63
  def test_identifier_empty_string_as_final_fallback
64
64
  @attributes = NSArray.array
65
- assert_equal EMPTY_STRING, pp_identifier
65
+ assert_equal EMPTY_STRING, pp_identifier.to_s
66
66
  end
67
67
 
68
68
  def test_position
metadata CHANGED
@@ -2,31 +2,31 @@
2
2
  name: AXElements
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease: 6
5
- version: 1.0.0.alpha7
5
+ version: 1.0.0.alpha8
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-05 00:00:00 Z
12
+ date: 2012-12-08 00:00:00 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: minitest
15
+ name: mouse
16
16
  prerelease: false
17
17
  requirement: !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ~>
21
21
  - !ruby/object:Gem::Version
22
- version: 4.3.1
23
- type: :development
22
+ version: 1.0.1
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: 4.3.1
29
+ version: 1.0.1
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: yard
32
32
  prerelease: false
@@ -107,7 +107,6 @@ files:
107
107
  - lib/ax_elements.rb
108
108
  - lib/AXElements.rb
109
109
  - lib/minitest/ax_elements.rb
110
- - lib/mouse.rb
111
110
  - lib/rspec/expectations/ax_elements.rb
112
111
  - ext/accessibility/key_coder/extconf.rb
113
112
  - ext/accessibility/core/core.c
@@ -151,7 +150,6 @@ files:
151
150
  - test/sanity/rspec/expectations/test_ax_elements.rb
152
151
  - test/sanity/test_accessibility.rb
153
152
  - test/sanity/test_ax_elements.rb
154
- - test/sanity/test_mouse.rb
155
153
  - test/test_core.rb
156
154
  - test/helper.rb
157
155
  homepage: http://github.com/Marketcircle/AXElements
@@ -211,6 +209,5 @@ test_files:
211
209
  - test/sanity/rspec/expectations/test_ax_elements.rb
212
210
  - test/sanity/test_accessibility.rb
213
211
  - test/sanity/test_ax_elements.rb
214
- - test/sanity/test_mouse.rb
215
212
  - test/test_core.rb
216
213
  - test/helper.rb
data/lib/mouse.rb DELETED
@@ -1,273 +0,0 @@
1
- framework 'ApplicationServices'
2
- require 'ax_elements/core_graphics_workaround'
3
-
4
-
5
- ##
6
- # This is a first attempt at writing a wrapper around the CoreGraphics event
7
- # taps API provided by OS X. The module provides a simple Ruby interface to
8
- # performing mouse interactions such as moving and clicking.
9
- #
10
- # [Reference](http://developer.apple.com/library/mac/#documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html).
11
- #
12
- # A rewrite is in the works, but in the mean time this code base still works
13
- # despite its warts.
14
- module Mouse
15
- extend self
16
-
17
- ##
18
- # Number of animation steps per second
19
- #
20
- # @return [Number]
21
- FPS = 120
22
-
23
- ##
24
- # @note We keep the number as a rational to try and avoid rounding
25
- # error introduced by the floats, especially MacRuby floats.
26
- #
27
- # Smallest unit of time allowed for an animation step
28
- #
29
- # @return [Number]
30
- QUANTUM = Rational(1, FPS)
31
-
32
- ##
33
- # Available constants for the type of units to use when scrolling
34
- #
35
- # @return [Hash{Symbol=>Fixnum}]
36
- UNIT = {
37
- line: KCGScrollEventUnitLine,
38
- pixel: KCGScrollEventUnitPixel
39
- }
40
-
41
- ##
42
- # The coordinates of the mouse using the flipped coordinate system
43
- #
44
- # Flipped coordinates have the origin in top left corner of the
45
- # primary screen.
46
- #
47
- # @return [CGPoint]
48
- def current_position
49
- CGEventGetLocation(CGEventCreate(nil))
50
- end
51
-
52
- ##
53
- # Move the mouse from the current position to the given point
54
- #
55
- # @param point [CGPoint]
56
- # @param duration [Float] animation duration, in seconds
57
- def move_to point, duration = 0.2
58
- animate KCGEventMouseMoved, KCGMouseButtonLeft, current_position, point, duration
59
- end
60
-
61
- ##
62
- # Click and drag from the current position to the given point
63
- #
64
- # @param point [CGPoint]
65
- # @param duration [Float] animation duration, in seconds
66
- def drag_to point, duration = 0.2
67
- post new_event(KCGEventLeftMouseDown, current_position, KCGMouseButtonLeft)
68
-
69
- animate KCGEventLeftMouseDragged, KCGMouseButtonLeft, current_position, point, duration
70
-
71
- post new_event(KCGEventLeftMouseUp, current_position, KCGMouseButtonLeft)
72
- end
73
-
74
- ##
75
- # @todo Need to double check to see if I introduce any inaccuracies.
76
- #
77
- # Scroll at the current position the given amount of units
78
- #
79
- # Scrolling too much or too little in a period of time will cause the
80
- # animation to look weird, possibly causing the app to mess things up.
81
- #
82
- # A positive `amonut` to scroll will scroll up and a negative `amount`
83
- # will scroll down.
84
- #
85
- # @param amount [Fixnum] number of units to scroll
86
- # @param duration [Float] in seconds
87
- # @param units [Symbol] must be either `:line` or `:pixel`
88
- def scroll amount, duration = 0.2, units = :line
89
- units = UNIT[units] || raise(ArgumentError, "#{units} is not a valid unit")
90
- steps = (FPS * duration).round
91
- current = 0.0
92
- steps.times do |step|
93
- done = (step+1).to_f / steps
94
- scroll = ((done - current)*amount).round
95
- post new_scroll_event(units, 1, scroll)
96
- sleep QUANTUM
97
- current += scroll.to_f / amount
98
- end
99
- end
100
-
101
- ##
102
- # @api semipublic
103
- #
104
- # Perform a down click
105
- #
106
- # You should follow this up with a call to {#click_up} to finish the click.
107
- #
108
- # @param point [CGPoint]
109
- # @param duration [Number]
110
- def click_down point = current_position, duration = 12
111
- event = new_event KCGEventLeftMouseDown, point, KCGMouseButtonLeft
112
- post event
113
- sleep QUANTUM*duration
114
- end
115
-
116
- ##
117
- # @api semipublic
118
- #
119
- # Perform an up click
120
- #
121
- # This should only be called after a call to {#click_down} to finish
122
- # the click event.
123
- #
124
- # @param point [CGPoint]
125
- def click_up point = current_position
126
- event = new_event KCGEventLeftMouseUp, point, KCGMouseButtonLeft
127
- post event
128
- end
129
-
130
- ##
131
- # Standard secondary click, sometimes called a "right click"
132
- #
133
- # Default position is the current position.
134
- #
135
- # @param point [CGPoint]
136
- # @param duration [Number] in seconds
137
- def secondary_click point = current_position, duration = 12
138
- event = new_event KCGEventRightMouseDown, point, KCGMouseButtonRight
139
- post event
140
- sleep QUANTUM*duration
141
- set_type event, KCGEventRightMouseUp
142
- post event
143
- end
144
- alias_method :right_click, :secondary_click
145
-
146
- ##
147
- # @api semipublic
148
- #
149
- # Generate a multi click event at the given position
150
- #
151
- # `num_clicks` is the number of clicks for the event, where a value of `2'
152
- # corresponds to a double click, `3` corresponds to a triple click, etc.
153
- #
154
- # However, I've only tested with a double and triple click, for which you
155
- # can just call {#double_click} and {#triple_click} instead.
156
- #
157
- # @param num_clicks [Fixnum]
158
- # @param point [CGPoint]
159
- def multi_click num_clicks, point = current_position
160
- event = new_event KCGEventLeftMouseDown, point, KCGMouseButtonLeft
161
- CGEventSetIntegerValueField(event, KCGMouseEventClickState, num_clicks)
162
- set_type event, KCGEventLeftMouseDown
163
- post event
164
- set_type event, KCGEventLeftMouseUp
165
- post event
166
- end
167
-
168
- ##
169
- # A standard double click
170
- #
171
- # Defaults to clicking at the current position.
172
- #
173
- # @param point [CGPoint]
174
- def double_click point = current_position
175
- # some apps still expect to receive the single click event first
176
- # and then the double click event
177
- multi_click 1, point
178
- multi_click 2, point
179
- end
180
-
181
- ##
182
- # A standard triple click
183
- #
184
- # Defaults to clicking at the current position.
185
- #
186
- # @param point [CGPoint]
187
- def triple_click point = current_position
188
- # some apps still expect to receive the single click event first
189
- # and then the double and triple click events
190
- double_click
191
- multi_click 3, point
192
- end
193
-
194
- ##
195
- # Click with an arbitrary mouse button
196
- #
197
- # Numbers are used to map the mouse buttons. At the time of writing,
198
- # the documented values are:
199
- #
200
- # - KCGMouseButtonLeft = 0
201
- # - KCGMouseButtonRight = 1
202
- # - KCGMouseButtonCenter = 2
203
- #
204
- # And the rest are not documented! Though they should be easy enough
205
- # to figure out. See the `CGMouseButton` enum in the reference
206
- # documentation for the most up to date list.
207
- #
208
- # @param point [CGPoint]
209
- # @param button [Number]
210
- # @param duration [Number]
211
- def arbitrary_click point = current_position, button = KCGMouseButtonCenter, duration = 12
212
- event = new_event KCGEventOtherMouseDown, point, button
213
- post event
214
- sleep QUANTUM*duration
215
- set_type event, KCGEventOtherMouseUp
216
- post event
217
- end
218
- alias_method :other_click, :arbitrary_click
219
-
220
-
221
- private
222
-
223
- ##
224
- # Executes a mouse movement animation. It can be a simple cursor
225
- # move or a drag depending on what is passed to `type`.
226
- def animate type, button, from, to, duration
227
- current = from
228
- xstep = (to.x - current.x) / (FPS * duration)
229
- ystep = (to.y - current.y) / (FPS * duration)
230
- start = NSDate.date
231
-
232
- until close_enough?(current, to)
233
- remaining = to.x - current.x
234
- current.x += xstep.abs > remaining.abs ? remaining : xstep
235
-
236
- remaining = to.y - current.y
237
- current.y += ystep.abs > remaining.abs ? remaining : ystep
238
-
239
- post new_event(type, current, button)
240
-
241
- sleep QUANTUM
242
- break if NSDate.date.timeIntervalSinceDate(start) > 5.0
243
- current = current_position
244
- end
245
- end
246
-
247
- def close_enough? current, target
248
- x = current.x - target.x
249
- y = current.y - target.y
250
- ((x**2)+(y**2)) <= 1
251
- end
252
-
253
- def new_event event, position, button
254
- CGEventCreateMouseEvent(nil, event, position, button)
255
- end
256
-
257
- # @param [Fixnum] wheel which scroll wheel to use (value between 1-3)
258
- def new_scroll_event units, wheel, amount
259
- CGEventCreateScrollWheelEvent(nil, units, wheel, amount)
260
- end
261
-
262
- def post event
263
- CGEventPost(KCGHIDEventTap, event)
264
- end
265
-
266
- ##
267
- # Change the event type for an instance of an event. This is how you would
268
- # reuse a specific event. In most cases, reusing events is a necessity.
269
- def set_type event, state
270
- CGEventSetType(event, state)
271
- end
272
-
273
- end
@@ -1,22 +0,0 @@
1
- require 'test/runner'
2
- require 'mouse'
3
-
4
- class TestMouseModule < MiniTest::Unit::TestCase
5
-
6
- def distance point1, point2
7
- x = point1.x - point2.x
8
- y = point1.y - point2.y
9
- Math.sqrt((x**2) + (y**2))
10
- end
11
-
12
- def test_move_to
13
- point = CGPoint.new(100, 100)
14
- Mouse.move_to point
15
- assert_in_delta 0, distance(point,Mouse.current_position), 1.0
16
-
17
- point = CGPoint.new(rand(700)+150, rand(500)+100)
18
- Mouse.move_to point
19
- assert_in_delta 0, distance(point,Mouse.current_position), 1.0
20
- end
21
-
22
- end