rautomation 0.6.3 → 0.7.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.
Files changed (88) hide show
  1. data/.gitignore +34 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +24 -0
  4. data/History.rdoc +21 -0
  5. data/LICENSE +1 -1
  6. data/README.rdoc +8 -7
  7. data/Rakefile +22 -32
  8. data/VERSION +1 -1
  9. data/ext/UiaDll/Release/UiaDll.dll +0 -0
  10. data/ext/UiaDll/UiaDll.suo +0 -0
  11. data/ext/UiaDll/UiaDll/UiaDll.cpp +236 -10
  12. data/lib/rautomation/adapter/autoit/locators.rb +1 -1
  13. data/lib/rautomation/adapter/autoit/text_field.rb +10 -1
  14. data/lib/rautomation/adapter/autoit/window.rb +50 -23
  15. data/lib/rautomation/adapter/helper.rb +6 -6
  16. data/lib/rautomation/adapter/ms_uia.rb +22 -0
  17. data/lib/rautomation/adapter/{win_ffi → ms_uia}/button.rb +3 -2
  18. data/lib/rautomation/adapter/ms_uia/button_helper.rb +25 -0
  19. data/lib/rautomation/adapter/ms_uia/checkbox.rb +27 -0
  20. data/lib/rautomation/adapter/{win_ffi → ms_uia}/constants.rb +20 -5
  21. data/lib/rautomation/adapter/ms_uia/control.rb +180 -0
  22. data/lib/rautomation/adapter/{win_ffi → ms_uia}/functions.rb +24 -26
  23. data/lib/rautomation/adapter/ms_uia/keystroke_converter.rb +122 -0
  24. data/lib/rautomation/adapter/{win_ffi → ms_uia}/label.rb +3 -2
  25. data/lib/rautomation/adapter/ms_uia/list_box.rb +91 -0
  26. data/lib/rautomation/adapter/ms_uia/list_item.rb +49 -0
  27. data/lib/rautomation/adapter/ms_uia/locators.rb +23 -0
  28. data/lib/rautomation/adapter/{win_ffi → ms_uia}/radio.rb +2 -2
  29. data/lib/rautomation/adapter/{win_ffi → ms_uia}/select_list.rb +41 -7
  30. data/lib/rautomation/adapter/ms_uia/table.rb +86 -0
  31. data/lib/rautomation/adapter/{win_ffi → ms_uia}/text_field.rb +5 -4
  32. data/lib/rautomation/adapter/ms_uia/uia_dll.rb +62 -0
  33. data/lib/rautomation/adapter/ms_uia/window.rb +364 -0
  34. data/lib/rautomation/adapter/win_32.rb +21 -0
  35. data/lib/rautomation/adapter/win_32/button.rb +14 -0
  36. data/lib/rautomation/adapter/{win_ffi → win_32}/button_helper.rb +1 -1
  37. data/lib/rautomation/adapter/win_32/checkbox.rb +14 -0
  38. data/lib/rautomation/adapter/win_32/constants.rb +68 -0
  39. data/lib/rautomation/adapter/{win_ffi → win_32}/control.rb +30 -23
  40. data/lib/rautomation/adapter/win_32/functions.rb +313 -0
  41. data/lib/rautomation/adapter/win_32/keys.rb +121 -0
  42. data/lib/rautomation/adapter/win_32/label.rb +10 -0
  43. data/lib/rautomation/adapter/win_32/list_box.rb +40 -0
  44. data/lib/rautomation/adapter/{win_ffi → win_32}/locators.rb +2 -2
  45. data/lib/rautomation/adapter/win_32/radio.rb +11 -0
  46. data/lib/rautomation/adapter/win_32/select_list.rb +97 -0
  47. data/lib/rautomation/adapter/win_32/table.rb +22 -0
  48. data/lib/rautomation/adapter/win_32/text_field.rb +42 -0
  49. data/lib/rautomation/adapter/{win_ffi → win_32}/window.rb +79 -62
  50. data/lib/rautomation/element_collections.rb +9 -1
  51. data/lib/rautomation/window.rb +17 -9
  52. data/rautomation.gemspec +24 -0
  53. data/spec/adapter/autoit/window_spec.rb +71 -0
  54. data/spec/adapter/{win_ffi → ms_uia}/button_spec.rb +1 -1
  55. data/spec/adapter/{win_ffi → ms_uia}/checkbox_spec.rb +9 -3
  56. data/spec/adapter/ms_uia/control_spec.rb +28 -0
  57. data/spec/adapter/ms_uia/keystroke_converter_spec.rb +50 -0
  58. data/spec/adapter/{win_ffi → ms_uia}/label_spec.rb +2 -2
  59. data/spec/adapter/ms_uia/list_item_spec.rb +14 -0
  60. data/spec/adapter/{win_ffi → ms_uia}/listbox_spec.rb +18 -5
  61. data/spec/adapter/{win_ffi → ms_uia}/radio_spec.rb +3 -1
  62. data/spec/adapter/ms_uia/select_list_spec.rb +109 -0
  63. data/spec/adapter/{win_ffi → ms_uia}/table_spec.rb +12 -1
  64. data/spec/adapter/{win_ffi → ms_uia}/text_field_spec.rb +2 -1
  65. data/spec/adapter/ms_uia/window_spec.rb +89 -0
  66. data/spec/adapter/win_32/button_spec.rb +30 -0
  67. data/spec/adapter/win_32/checkbox_spec.rb +48 -0
  68. data/spec/adapter/win_32/label_spec.rb +15 -0
  69. data/spec/adapter/win_32/listbox_spec.rb +42 -0
  70. data/spec/adapter/win_32/radio_spec.rb +32 -0
  71. data/spec/adapter/{win_ffi → win_32}/select_list_spec.rb +16 -16
  72. data/spec/adapter/win_32/table_spec.rb +28 -0
  73. data/spec/adapter/win_32/text_field_spec.rb +24 -0
  74. data/spec/adapter/{win_ffi → win_32}/window_spec.rb +19 -14
  75. data/spec/button_spec.rb +1 -0
  76. data/spec/buttons_spec.rb +4 -4
  77. data/spec/spec_helper.rb +30 -4
  78. data/spec/text_field_spec.rb +6 -7
  79. data/spec/window_spec.rb +12 -0
  80. data/spec/windows_spec.rb +19 -0
  81. metadata +116 -97
  82. data/lib/rautomation/adapter/win_ffi.rb +0 -21
  83. data/lib/rautomation/adapter/win_ffi/checkbox.rb +0 -19
  84. data/lib/rautomation/adapter/win_ffi/keystroke_converter.rb +0 -67
  85. data/lib/rautomation/adapter/win_ffi/list_box.rb +0 -60
  86. data/lib/rautomation/adapter/win_ffi/ms_uia/uia_dll.rb +0 -36
  87. data/lib/rautomation/adapter/win_ffi/table.rb +0 -57
  88. data/spec/adapter/win_ffi/keystroke_converter_spec.rb +0 -47
@@ -0,0 +1,86 @@
1
+ module RAutomation
2
+ module Adapter
3
+ module MsUia
4
+ class Table < Control
5
+ include WaitHelper
6
+ include Locators
7
+
8
+ def strings
9
+ rows = []
10
+ header_columns = []
11
+
12
+ raise "Not a list control" unless UiaDll::current_control_type(uia_element) == Constants::UIA_LIST_CONTROL_TYPE
13
+
14
+
15
+ children_count = count_children(uia_element)
16
+
17
+ children = FFI::MemoryPointer.new :pointer, children_count
18
+ UiaDll::find_children(uia_element, children)
19
+
20
+
21
+ children.read_array_of_pointer(children_count).each do |child|
22
+ grandchildren_count = count_children(child)
23
+
24
+ if grandchildren_count > 0
25
+
26
+ grandchildren = FFI::MemoryPointer.new :pointer, grandchildren_count
27
+ UiaDll::find_children(child, grandchildren)
28
+
29
+ grandchildren.read_array_of_pointer(grandchildren_count).each do |grandchild|
30
+ grandchild_name = FFI::MemoryPointer.new :char, UiaDll::get_name(grandchild, nil) + 1
31
+ UiaDll::get_name(grandchild, grandchild_name)
32
+ header_columns.push grandchild_name.read_string
33
+ end
34
+ else
35
+ grandchild_name = FFI::MemoryPointer.new :char, UiaDll::get_name(child, nil) + 1
36
+ UiaDll::get_name(child, grandchild_name)
37
+ header_columns = grandchild_name.read_string
38
+ end
39
+
40
+ rows.push header_columns
41
+ header_columns = []
42
+ end
43
+
44
+ rows
45
+ end
46
+
47
+ # def select(row)
48
+ # Functions.select_table_row(Window.oleacc_module_handle, Functions.control_hwnd(@window.hwnd, @locators), row)
49
+ # end
50
+
51
+ def select(index)
52
+ children = FFI::MemoryPointer.new :pointer, row_count
53
+
54
+ length = UiaDll::find_children(uia_element, children)
55
+
56
+ target_element = children.read_array_of_pointer(length)[index]
57
+
58
+ UiaDll::select(target_element)
59
+ end
60
+
61
+ #todo - replace with UIA version
62
+ def selected?(row)
63
+ state = Functions.get_table_row_state(Window.oleacc_module_handle, Functions.control_hwnd(@window.hwnd, @locators), row)
64
+ state & Constants::STATE_SYSTEM_SELECTED != 0
65
+ end
66
+
67
+ def row_count
68
+ UiaDll::find_children(uia_element, nil)
69
+ end
70
+
71
+ def exist?
72
+ super && matches_type?(Constants::UIA_LIST_CONTROL_TYPE)
73
+ end
74
+
75
+ alias_method :exists?, :exist?
76
+
77
+ private
78
+
79
+ def count_children(element)
80
+ UiaDll::find_children(element, nil)
81
+ end
82
+
83
+ end
84
+ end
85
+ end
86
+ end
@@ -1,6 +1,6 @@
1
1
  module RAutomation
2
2
  module Adapter
3
- module WinFfi
3
+ module MsUia
4
4
  class TextField < Control
5
5
  include WaitHelper
6
6
  include Locators
@@ -8,6 +8,7 @@ module RAutomation
8
8
  # Default locators used for searching text fields.
9
9
  DEFAULT_LOCATORS = {:class => /edit/i}
10
10
 
11
+ #todo - replace with UIA version
11
12
  # @see RAutomation::TextField#set
12
13
  def set(text)
13
14
  raise "Cannot set value on a disabled text field" if disabled?
@@ -28,24 +29,24 @@ module RAutomation
28
29
  set ""
29
30
  end
30
31
 
32
+ #todo - replace with UIA version
31
33
  # @see RAutomation::TextField#value
32
34
  def value
33
35
  Functions.control_value(hwnd)
34
36
  end
35
37
 
38
+ #todo - replace with UIA version
36
39
  # @see RAutomation::TextField#hwnd
37
40
  def hwnd
38
41
  Functions.control_hwnd(@window.hwnd, @locators)
39
42
  end
40
43
 
41
44
  def exist?
42
- @locators[:id].nil? ? super : super && matches_type(Constants::UIA_EDIT_CONTROL_TYPE)
45
+ super && matches_type?(Constants::UIA_EDIT_CONTROL_TYPE)
43
46
  end
44
47
 
45
48
  alias_method :exists?, :exist?
46
49
 
47
-
48
-
49
50
  end
50
51
  end
51
52
  end
@@ -0,0 +1,62 @@
1
+ #todo - move this file up to the same level as the others
2
+ #todo - organize the methods better
3
+
4
+ module RAutomation
5
+ module Adapter
6
+ module MsUia
7
+ module UiaDll
8
+ extend FFI::Library
9
+
10
+ ffi_lib File.dirname(__FILE__) + '/../../../../ext/UiaDll/Release/UiaDll.dll'
11
+ ffi_convention :stdcall
12
+
13
+ attach_function :find_window, :RA_FindWindow,
14
+ [:string], :pointer
15
+ attach_function :is_offscreen, :RA_IsOffscreen,
16
+ [:pointer], :bool
17
+ attach_function :element_from_handle, :RA_ElementFromHandle,
18
+ [:long], :pointer
19
+ attach_function :element_from_point, :RA_ElementFromPoint,
20
+ [:int, :int], :pointer
21
+ attach_function :get_focused_element, :RA_GetFocusedElement,
22
+ [], :pointer
23
+ attach_function :find_child_by_id, :RA_FindChildById,
24
+ [:pointer, :string], :pointer
25
+ attach_function :find_child_by_name, :RA_FindChildByName,
26
+ [:pointer, :string], :pointer
27
+ attach_function :current_native_window_handle, :RA_CurrentNativeWindowHandle,
28
+ [:pointer], :long
29
+ attach_function :set_focus, :RA_SetFocus,
30
+ [:pointer], :bool
31
+ attach_function :current_control_type, :RA_GetCurrentControlType,
32
+ [:pointer], :int
33
+ attach_function :desktop_handle, :RA_GetDesktopHandle,
34
+ [], :long
35
+ attach_function :move_mouse, :RA_MoveMouse,
36
+ [:int,:int], :long
37
+ attach_function :click_mouse, :RA_ClickMouse,
38
+ [], :long
39
+ attach_function :bounding_rectangle, :RA_CurrentBoundingRectangle,
40
+ [:pointer, :pointer], :int
41
+ attach_function :is_offscreen, :RA_CurrentIsOffscreen,
42
+ [:pointer, :pointer], :int
43
+ attach_function :find_children, :RA_FindChildren,
44
+ [:pointer, :pointer], :int
45
+ attach_function :get_name, :RA_GetName,
46
+ [:pointer, :pointer], :int
47
+ attach_function :get_class_name, :RA_GetClassName,
48
+ [:pointer, :pointer], :int
49
+ attach_function :get_is_selected, :RA_GetIsSelected,
50
+ [:pointer], :bool
51
+ attach_function :select, :RA_Select,
52
+ [:pointer], :int
53
+ attach_function :set_value, :RA_Set_Value,
54
+ [:pointer, :pointer], :int
55
+ attach_function :find_window_by_pid, :RA_FindWindowByPID,
56
+ [:int], :pointer
57
+ attach_function :current_process_id, :RA_GetCurrentProcessId,
58
+ [:pointer], :int
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,364 @@
1
+ module RAutomation
2
+ module Adapter
3
+ module MsUia
4
+ autoload :UiaDll, File.dirname(__FILE__) + "/uia_dll"
5
+
6
+ class Window
7
+ include WaitHelper
8
+ include Locators
9
+ extend ElementCollections
10
+
11
+ has_many :controls
12
+
13
+ #todo - figure out what this is for and see if MsUia still needs it
14
+ class << self
15
+ def oleacc_module_handle
16
+ @oleacc_module_handle ||= begin
17
+ oleacc = Functions.load_library "oleacc.dll"
18
+ Functions.co_initialize nil
19
+ oleacc
20
+ end
21
+ end
22
+ end
23
+
24
+ # Locators of the window.
25
+ attr_reader :locators
26
+
27
+ # Possible locators are :title, :text, :hwnd, :pid, :class and :index.
28
+ #todo - update list of valid locators for UIA
29
+ # Creates the window object.
30
+ # @note this method is not meant to be accessed directly, but only through {RAutomation::Window#initialize}!
31
+ # @param [Hash] locators for searching the window.
32
+ # @option locators [String, Regexp] :title Title of the window
33
+ # @option locators [String, Regexp] :text Visible text of the window
34
+ # @option locators [String, Regexp] :class Internal class name of the window
35
+ # @option locators [String, Fixnum] :hwnd Window handle in decimal format
36
+ # @option locators [String, Fixnum] :pid Window process ID (PID)
37
+ # @option locators [String, Fixnum] :index 0-based index to specify n-th window if all other criteria match
38
+ # all other criteria match
39
+ # @see RAutomation::Window#initialize
40
+ def initialize(container, locators)
41
+ @container = container
42
+ extract(locators)
43
+ end
44
+
45
+ #todo - replace with UIA version
46
+ # Retrieves handle of the window.
47
+ # @note Searches only for visible windows.
48
+ # @see RAutomation::Window#hwnd
49
+ def hwnd
50
+ @hwnd ||= Functions.window_hwnd(@locators)
51
+ end
52
+
53
+ #todo - replace with UIA version
54
+ # @see RAutomation::Window#pid
55
+ def pid
56
+ Functions.window_pid(hwnd)
57
+ end
58
+
59
+ #todo - replace with UIA version
60
+ # @see RAutomation::Window#title
61
+ def title
62
+ Functions.window_title(hwnd)
63
+ end
64
+
65
+ # @see RAutomation::Window#class_names
66
+ def class_names
67
+ root_element = UiaDll::element_from_handle(hwnd)
68
+
69
+ root_class = FFI::MemoryPointer.new :char, UiaDll::get_class_name(root_element, nil) + 1
70
+ UiaDll::get_class_name(root_element, root_class)
71
+
72
+ classes = gather_children_classes(root_element)
73
+ classes = classes.flatten
74
+ classes.delete("")
75
+ classes.sort
76
+ end
77
+
78
+ # @see RAutomation::Window#activate
79
+ def activate
80
+ return if !exists? || active?
81
+ restore if minimized?
82
+ Functions.activate_window(hwnd)
83
+ restore if minimized?
84
+ sleep 1
85
+ end
86
+
87
+ #todo - replace with UIA version
88
+ # @see RAutomation::Window#active?
89
+ def active?
90
+ exists? && Functions.foreground_window == hwnd
91
+ end
92
+
93
+ #todo - replace with UIA version
94
+ # @see RAutomation::Window#text
95
+ def text
96
+ Functions.window_text(hwnd)
97
+ end
98
+
99
+ #todo - replace with UIA version
100
+ # @see RAutomation::Window#exists?
101
+ def exists?
102
+ hwnd && Functions.window_exists(hwnd)
103
+ end
104
+
105
+ #todo - replace with UIA version
106
+ # @see RAutomation::Window#visible?
107
+ def visible?
108
+ Functions.window_visible(hwnd)
109
+ end
110
+
111
+ #todo - replace with UIA version
112
+ # @see RAutomation::Window#maximize
113
+ def maximize
114
+ Functions.show_window(hwnd, Constants::SW_MAXIMIZE)
115
+ sleep 1
116
+ end
117
+
118
+ #todo - replace with UIA version
119
+ # @see RAutomation::Window#minimize
120
+ def minimize
121
+ Functions.show_window(hwnd, Constants::SW_MINIMIZE)
122
+ sleep 1
123
+ end
124
+
125
+ #todo - replace with UIA version
126
+ # @see RAutomation::Window#minimized?
127
+ def minimized?
128
+ Functions.minimized(hwnd)
129
+ end
130
+
131
+ #todo - replace with UIA version
132
+ # @see RAutomation::Window#restore
133
+ def restore
134
+ Functions.show_window(hwnd, Constants::SW_RESTORE)
135
+ sleep 1
136
+ end
137
+
138
+ #todo - replace with UIA version if possible
139
+ # Activates the window and sends keys to it.
140
+ #
141
+ # Refer to KeystrokeConverter#convert_special_characters for the special keycodes.
142
+ # @see RAutomation::Window#send_keys
143
+ def send_keys(keys)
144
+ shift_pressed = false
145
+ KeystrokeConverter.convert(keys[0]).each do |key|
146
+ wait_until do
147
+ activate
148
+ active?
149
+ end
150
+ press_key key
151
+
152
+ if key == Constants::VK_LSHIFT
153
+ shift_pressed = true
154
+ next
155
+ end
156
+
157
+ release_key key
158
+
159
+ if shift_pressed
160
+ shift_pressed = false
161
+ release_key Constants::VK_LSHIFT
162
+ end
163
+ end
164
+ end
165
+
166
+ #todo - replace with UIA version
167
+ # @see RAutomation::Window#close
168
+ def close
169
+ Functions.close_window(hwnd)
170
+ end
171
+
172
+ # @see Button#initialize
173
+ # @see RAutomation::Window#button
174
+ def button(locator)
175
+ Button.new(self, locator)
176
+ end
177
+
178
+ # @see TextField#initialize
179
+ # @see RAutomation::Window#text_field
180
+ def text_field(locator)
181
+ TextField.new(self, locator)
182
+ end
183
+
184
+ # Redirects all method calls not part of the public API to the {Functions} directly.
185
+ # @see RAutomation::Window#method_missing
186
+ def method_missing(name, *args)
187
+ Functions.respond_to?(name) ? Functions.send(name, *args) : super
188
+ end
189
+
190
+ # MsUia adapter specific API methods
191
+ def element
192
+ case
193
+ when @locators[:focus]
194
+ uia_control = UiaDll::get_focused_element
195
+ when @locators[:id]
196
+ uia_control = UiaDll::find_window(@locators[:id].to_s)
197
+ raise UnknownElementException, "#{@locators[:id]} does not exist" if uia_control.nil?
198
+ when @locators[:point]
199
+ uia_control = UiaDll::element_from_point(@locators[:point][0], @locators[:point][1])
200
+ raise UnknownElementException, "#{@locators[:point]} does not exist" if uia_control.nil?
201
+ else
202
+ hwnd = find_hwnd(locators, window_hwnd) do |hwnd|
203
+ locators_match?(locators, control_properties(hwnd, locators))
204
+ end
205
+ raise UnknownElementException, "Element with #{locators.inspect} does not exist" if (hwnd == 0) or (hwnd == nil)
206
+ uia_control = UiaDll::element_from_handle(hwnd)
207
+ end
208
+ uia_control
209
+ end
210
+
211
+ def new_pid
212
+ UiaDll::current_process_id(uia_control())
213
+ end
214
+
215
+ def display_tree
216
+ root_element = UiaDll::element_from_handle(hwnd)
217
+
218
+ root_name = FFI::MemoryPointer.new :char, UiaDll::get_name(root_element, nil) + 1
219
+ UiaDll::get_name(root_element, root_name)
220
+
221
+ [root_name.read_string.inspect, gather_children(root_element)]
222
+ end
223
+
224
+ def gather_children(root_element)
225
+ element_tree = []
226
+
227
+ child_count = count_children(root_element)
228
+ children = FFI::MemoryPointer.new :pointer, child_count
229
+ UiaDll::find_children(root_element, children)
230
+
231
+ children.read_array_of_pointer(child_count).each do |child|
232
+ child_name = FFI::MemoryPointer.new :char, UiaDll::get_name(child, nil) + 1
233
+ UiaDll::get_name(child, child_name)
234
+
235
+ grandchild_count = count_children(child)
236
+
237
+ if grandchild_count > 0
238
+ element_tree << [child_name.read_string, gather_children(child)]
239
+ else
240
+ element_tree << child_name.read_string
241
+ end
242
+ end
243
+
244
+ element_tree
245
+ end
246
+
247
+ def count_children(element)
248
+ UiaDll::find_children(element, nil)
249
+ end
250
+
251
+ def gather_children_classes(root_element)
252
+ element_tree = []
253
+
254
+ child_count = count_children(root_element)
255
+ children = FFI::MemoryPointer.new :pointer, child_count
256
+ UiaDll::find_children(root_element, children)
257
+
258
+ children.read_array_of_pointer(child_count).each do |child|
259
+ child_name = FFI::MemoryPointer.new :char, UiaDll::get_class_name(child, nil) + 1
260
+ UiaDll::get_class_name(child, child_name)
261
+
262
+ grandchild_count = count_children(child)
263
+
264
+ if grandchild_count > 0
265
+ element_tree << [child_name.read_string, gather_children_classes(child)]
266
+ else
267
+ element_tree << child_name.read_string
268
+ end
269
+ end
270
+
271
+ element_tree
272
+ end
273
+
274
+ def get_focused_element
275
+ UiaDll::get_focused_element()
276
+ end
277
+
278
+ def bounding_rectangle
279
+ window = UiaDll::element_from_handle(hwnd)
280
+
281
+ boundary = FFI::MemoryPointer.new :long, 4
282
+ UiaDll::bounding_rectangle(window, boundary)
283
+
284
+ boundary.read_array_of_long(4)
285
+ end
286
+
287
+ def move_mouse(x, y)
288
+ UiaDll::move_mouse(x, y)
289
+ end
290
+
291
+ def click_mouse()
292
+ UiaDll::click_mouse
293
+ end
294
+
295
+ def label(locator)
296
+ @container.wait_until_present
297
+ Label.new(self, locator)
298
+ end
299
+
300
+ def control(locator)
301
+ @container.wait_until_present
302
+ Control.new(self, locator)
303
+ end
304
+
305
+ def controls(locator)
306
+ @container.wait_until_present
307
+ Controls.new(self, locator)
308
+ end
309
+
310
+ def list_box(locator)
311
+ @container.wait_until_present
312
+ ListBox.new(self, locator)
313
+ end
314
+
315
+ def list_item(locator)
316
+ @container.wait_until_present
317
+ ListItem.new(self, locator)
318
+ end
319
+
320
+ def select_list(locator)
321
+ @container.wait_until_present
322
+ SelectList.new(self, locator)
323
+ end
324
+
325
+ def checkbox(locator)
326
+ @container.wait_until_present
327
+ Checkbox.new(self, locator)
328
+ end
329
+
330
+ def radio(locator)
331
+ @container.wait_until_present
332
+ Radio.new(self, locator)
333
+ end
334
+
335
+ def table(locator)
336
+ @container.wait_until_present
337
+ Table.new(self, locator)
338
+ end
339
+
340
+ #todo - replace with UIA version
341
+ # Creates the child window object.
342
+ # @note This is an Win32 adapter specific method, not part of the public API
343
+ # @example
344
+ # RAutomation::Window.new(:title => /Windows Internet Explorer/i).
345
+ # child(:title => /some popup/)
346
+ # @param (see Window#initialize)
347
+ # @return [RAutomation::Window] child window, popup or regular window.
348
+ def child(locators)
349
+ RAutomation::Window.new Functions.child_window_locators(hwnd, locators)
350
+ end
351
+
352
+ private
353
+
354
+ def press_key key
355
+ Functions.send_key(key, 0, 0, nil)
356
+ end
357
+
358
+ def release_key key
359
+ Functions.send_key(key, 0, Constants::KEYEVENTF_KEYUP, nil)
360
+ end
361
+ end
362
+ end
363
+ end
364
+ end