rautomation 0.8.0 → 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.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +3 -3
  4. data/History.rdoc +17 -0
  5. data/README.rdoc +2 -1
  6. data/Rakefile +23 -6
  7. data/VERSION +1 -1
  8. data/ext/IAccessibleDLL/Release/IAccessibleDLL.dll +0 -0
  9. data/ext/UiaDll/Release/UiaDll.dll +0 -0
  10. data/ext/UiaDll/UiaDll/{AutomatedComboBox.cpp → AutomatedSelectList.cpp} +22 -11
  11. data/ext/UiaDll/UiaDll/{AutomatedComboBox.h → AutomatedSelectList.h} +17 -4
  12. data/ext/UiaDll/UiaDll/AutomatedTable.cpp +55 -13
  13. data/ext/UiaDll/UiaDll/AutomatedTable.h +16 -3
  14. data/ext/UiaDll/UiaDll/AutomationControl.cpp +28 -0
  15. data/ext/UiaDll/UiaDll/AutomationControl.h +56 -0
  16. data/ext/UiaDll/UiaDll/AutomationFinder.cpp +57 -0
  17. data/ext/UiaDll/UiaDll/AutomationFinder.h +48 -0
  18. data/ext/UiaDll/UiaDll/ControlMethods.cpp +15 -0
  19. data/ext/UiaDll/UiaDll/MenuItemSelector.h +2 -0
  20. data/ext/UiaDll/UiaDll/MenuMethods.cpp +58 -0
  21. data/ext/UiaDll/UiaDll/SelectListMethods.cpp +37 -0
  22. data/ext/UiaDll/UiaDll/SelectionItem.cpp +10 -0
  23. data/ext/UiaDll/UiaDll/SelectionItem.h +21 -0
  24. data/ext/UiaDll/UiaDll/StringHelper.cpp +33 -2
  25. data/ext/UiaDll/UiaDll/StringHelper.h +6 -0
  26. data/ext/UiaDll/UiaDll/StringMethods.cpp +8 -0
  27. data/ext/UiaDll/UiaDll/TableMethods.cpp +76 -0
  28. data/ext/UiaDll/UiaDll/Toggle.cpp +2 -0
  29. data/ext/UiaDll/UiaDll/Toggle.h +22 -0
  30. data/ext/UiaDll/UiaDll/UiaDll.cpp +96 -327
  31. data/ext/UiaDll/UiaDll/UiaDll.vcxproj +15 -4
  32. data/ext/UiaDll/UiaDll/UiaDll.vcxproj.filters +91 -22
  33. data/ext/UiaDll/UiaDll/dllmain.cpp +1 -1
  34. data/ext/UiaDll/UiaDll/stdafx.h +38 -21
  35. data/ext/WindowsForms/Release/WindowsForms.exe +0 -0
  36. data/ext/WindowsForms/WindowsForms.sln +10 -0
  37. data/ext/WindowsForms/WindowsForms/AutomatableMonthCalendar.cs +59 -0
  38. data/ext/WindowsForms/WindowsForms/AutomationHelpers/AutomationProvider.cs +91 -0
  39. data/ext/WindowsForms/WindowsForms/MainFormWindow.Designer.cs +32 -10
  40. data/ext/WindowsForms/WindowsForms/MainFormWindow.cs +10 -0
  41. data/ext/WindowsForms/WindowsForms/WindowsForms.csproj +15 -6
  42. data/lib/rautomation/adapter/ms_uia.rb +1 -0
  43. data/lib/rautomation/adapter/ms_uia/checkbox.rb +2 -10
  44. data/lib/rautomation/adapter/ms_uia/constants.rb +1 -0
  45. data/lib/rautomation/adapter/ms_uia/control.rb +14 -67
  46. data/lib/rautomation/adapter/ms_uia/functions.rb +2 -18
  47. data/lib/rautomation/adapter/ms_uia/list_box.rb +5 -27
  48. data/lib/rautomation/adapter/ms_uia/list_item.rb +2 -29
  49. data/lib/rautomation/adapter/ms_uia/radio.rb +1 -1
  50. data/lib/rautomation/adapter/ms_uia/select_list.rb +5 -6
  51. data/lib/rautomation/adapter/ms_uia/table.rb +15 -50
  52. data/lib/rautomation/adapter/ms_uia/text_field.rb +1 -1
  53. data/lib/rautomation/adapter/ms_uia/uia_dll.rb +226 -58
  54. data/lib/rautomation/adapter/ms_uia/value_control.rb +21 -0
  55. data/lib/rautomation/adapter/ms_uia/window.rb +6 -104
  56. data/lib/rautomation/adapter/win_32/functions.rb +0 -23
  57. data/lib/rautomation/adapter/win_32/keys.rb +64 -61
  58. data/rautomation.gemspec +6 -1
  59. data/spec/adapter/autoit/mouse_spec.rb +1 -1
  60. data/spec/adapter/ms_uia/select_list_spec.rb +0 -21
  61. data/spec/adapter/ms_uia/table_spec.rb +13 -11
  62. data/spec/adapter/ms_uia/text_field_spec.rb +15 -8
  63. data/spec/adapter/ms_uia/value_control_spec.rb +11 -0
  64. data/spec/adapter/ms_uia/window_spec.rb +7 -1
  65. data/spec/adapter/win_32/mouse_spec.rb +1 -1
  66. data/spec/adapter/win_32/text_field_spec.rb +5 -5
  67. data/spec/adapter/win_32/window_spec.rb +1 -1
  68. data/spec/text_field_spec.rb +18 -23
  69. data/spec/window_spec.rb +1 -3
  70. metadata +45 -34
  71. data/ext/UiaDll/UiaDll/ToggleStateHelper.cpp +0 -33
@@ -12,7 +12,7 @@ module RAutomation
12
12
  end
13
13
 
14
14
  def set?
15
- UiaDll::get_is_selected(uia_element)
15
+ UiaDll::is_selected(search_information)
16
16
  end
17
17
 
18
18
  alias_method :exists?, :exist?
@@ -16,12 +16,12 @@ module RAutomation
16
16
  end
17
17
 
18
18
  def selected?
19
- @index == UiaDll::get_combobox_selected_index(@select_list.control_hwnd)
19
+ @index == UiaDll::select_list_selected_index(@select_list.control_hwnd)
20
20
  end
21
21
 
22
22
  def select
23
23
  @select_list.assert_enabled
24
- UiaDll::select_combo_by_index @select_list.control_hwnd, @index
24
+ UiaDll::select_list_select_index @select_list.search_information, @index
25
25
  end
26
26
 
27
27
  alias_method :set, :select
@@ -33,8 +33,7 @@ module RAutomation
33
33
  end
34
34
 
35
35
  def set(value)
36
- list = UiaDll::element_from_handle(@hwnd)
37
- UiaDll::set_value(list, value)
36
+ UiaDll::select_list_select_value(search_information, value)
38
37
  end
39
38
 
40
39
  def options(options = {})
@@ -72,7 +71,7 @@ module RAutomation
72
71
  end
73
72
 
74
73
  def select(index)
75
- UiaDll::select_combo_by_index @hwnd, index
74
+ UiaDll::select_list_select_index search_information, index
76
75
  end
77
76
 
78
77
  def list_item_height
@@ -104,7 +103,7 @@ module RAutomation
104
103
  private
105
104
 
106
105
  def item_count
107
- UiaDll::get_combobox_count(@hwnd)
106
+ UiaDll::select_list_count(search_information)
108
107
  end
109
108
 
110
109
  end
@@ -13,11 +13,11 @@ module RAutomation
13
13
  end
14
14
 
15
15
  def exists?
16
- UiaDll::data_item_exists hwnd, row, column
16
+ UiaDll::table_coordinate_valid? hwnd, row, column
17
17
  end
18
18
 
19
19
  def value
20
- UiaDll::cell_value_at hwnd, row, column
20
+ UiaDll::table_value_at hwnd, row, column
21
21
  end
22
22
 
23
23
  alias_method :text, :value
@@ -51,11 +51,11 @@ module RAutomation
51
51
  end
52
52
 
53
53
  def value
54
- UiaDll::cell_value_at @hwnd, @locators[:index]
54
+ UiaDll::table_value_at @hwnd, @locators[:index]
55
55
  end
56
56
 
57
57
  def exists?
58
- UiaDll::data_item_exists(@hwnd, @locators[:index])
58
+ UiaDll::table_coordinate_valid?(@hwnd, @locators[:index])
59
59
  end
60
60
 
61
61
  def self.locators_match?(locators, item)
@@ -87,60 +87,25 @@ module RAutomation
87
87
  end
88
88
 
89
89
  def strings
90
- rows = []
91
- header_columns = []
90
+ headers = UiaDll.table_headers(hwnd)
91
+ values = UiaDll.table_values(hwnd)
92
+ return values if headers.empty?
92
93
 
93
- raise "Not a list control" unless of_type_table?
94
-
95
-
96
- children_count = count_children(uia_element)
97
-
98
- children = FFI::MemoryPointer.new :pointer, children_count
99
- UiaDll::find_children(uia_element, children)
100
-
101
-
102
- children.read_array_of_pointer(children_count).each do |child|
103
- grandchildren_count = count_children(child)
104
-
105
- if grandchildren_count > 0
106
-
107
- grandchildren = FFI::MemoryPointer.new :pointer, grandchildren_count
108
- UiaDll::find_children(child, grandchildren)
109
-
110
- grandchildren.read_array_of_pointer(grandchildren_count).each do |grandchild|
111
- grandchild_name = FFI::MemoryPointer.new :char, UiaDll::get_name(grandchild, nil) + 1
112
- UiaDll::get_name(grandchild, grandchild_name)
113
- header_columns.push grandchild_name.read_string
114
- end
115
- else
116
- grandchild_name = FFI::MemoryPointer.new :char, UiaDll::get_name(child, nil) + 1
117
- UiaDll::get_name(child, grandchild_name)
118
- header_columns = grandchild_name.read_string
119
- end
120
-
121
- rows.push header_columns
122
- header_columns = []
123
- end
124
-
125
- rows
94
+ all_strings = [] << headers
95
+ values.each_slice(headers.count) {|r| all_strings << r }
96
+ all_strings
126
97
  end
127
98
 
128
- # def select(row)
129
- # Functions.select_table_row(Window.oleacc_module_handle, Functions.control_hwnd(@window.hwnd, @locators), row)
130
- # end
131
-
132
- def select(index)
133
- UiaDll::select_data_item hwnd, index - 1
99
+ def select(which_item)
100
+ UiaDll::table_select hwnd, which_item
134
101
  end
135
102
 
136
- #todo - replace with UIA version
137
- def selected?(row)
138
- state = Functions.get_table_row_state(Window.oleacc_module_handle, hwnd, row)
139
- state & Constants::STATE_SYSTEM_SELECTED != 0
103
+ def selected?(which_item)
104
+ UiaDll::table_row_is_selected hwnd, which_item
140
105
  end
141
106
 
142
107
  def row_count
143
- UiaDll::get_data_item_count hwnd
108
+ UiaDll::table_row_count hwnd
144
109
  end
145
110
 
146
111
  def exist?
@@ -42,7 +42,7 @@ module RAutomation
42
42
  end
43
43
 
44
44
  def exist?
45
- super && matches_type?(Constants::UIA_EDIT_CONTROL_TYPE)
45
+ super && matches_type?(Constants::UIA_EDIT_CONTROL_TYPE, Constants::UIA_DOCUMENT_CONTROL_TYPE)
46
46
  end
47
47
 
48
48
  alias_method :exists?, :exist?
@@ -7,73 +7,243 @@ module RAutomation
7
7
  module UiaDll
8
8
  extend FFI::Library
9
9
 
10
+ HowToFind = enum(:hwnd, 1,
11
+ :id,
12
+ :value,
13
+ :focus,
14
+ :point)
15
+
16
+
17
+ class FindData < FFI::Union
18
+ layout :string_data, [:uint8, 256],
19
+ :int_data, :int,
20
+ :point_data, [:int, 2]
21
+ end
22
+
23
+ class SearchCriteria < FFI::Struct
24
+ def self.from_locator(parent, locator)
25
+ info = SearchCriteria.new
26
+ info.parent_window = parent
27
+ info.index = locator[:index] || 0
28
+
29
+ case
30
+ when locator[:hwnd]
31
+ info.how = :hwnd
32
+ info.data = locator[:hwnd]
33
+ when locator[:id]
34
+ info.how = :id
35
+ info.data = locator[:id]
36
+ when locator[:value]
37
+ info.how = :value
38
+ info.data = locator[:value]
39
+ when locator[:point]
40
+ info.how = :point
41
+ info.data = locator[:point]
42
+ when locator[:focus]
43
+ info.how = :focus
44
+ end
45
+ info
46
+ end
47
+
48
+ def how
49
+ self[:how]
50
+ end
51
+
52
+ def how=(value)
53
+ self[:how] = value
54
+ end
55
+
56
+ def index
57
+ self[:index]
58
+ end
59
+
60
+ def index=(value)
61
+ self[:index] = value
62
+ end
63
+
64
+ def parent_window
65
+ self[:hwnd]
66
+ end
67
+
68
+ def parent_window=(parent)
69
+ self[:hwnd] = parent
70
+ end
71
+
72
+ def data
73
+ case how
74
+ when :hwnd
75
+ return self[:data][:int_data]
76
+ when :id, :value
77
+ return self[:data][:string_data].to_ptr.read_string
78
+ when :point
79
+ return self[:data][:point_data].to_ptr.read_array_of_int(2)
80
+ else
81
+ return nil
82
+ end
83
+ end
84
+
85
+ def data=(value)
86
+ case how
87
+ when :hwnd
88
+ self[:data][:int_data] = value
89
+ when :id, :value
90
+ self[:data][:string_data] = value
91
+ when :point
92
+ self[:data][:point_data].to_ptr.write_array_of_int(value)
93
+ end
94
+ end
95
+
96
+ layout :hwnd, :int,
97
+ :index, :int,
98
+ :how, HowToFind, :data, FindData
99
+ end
100
+
10
101
  ffi_lib File.dirname(__FILE__) + '/../../../../ext/UiaDll/Release/UiaDll.dll'
11
102
  ffi_convention :stdcall
12
103
 
13
- attach_function :find_window, :RA_FindWindow,
14
- [:string], :pointer
15
- attach_function :is_offscreen, :RA_IsOffscreen,
16
- [:pointer], :bool
104
+ # Generic Control methods
105
+ attach_function :ElementExists, [SearchCriteria.by_ref], :bool
106
+ attach_function :process_id, :ProcessId, [SearchCriteria.by_ref], :int
107
+ attach_function :Control_GetValue, [:long, :pointer, :int], :void
108
+ attach_function :set_control_value, :Control_SetValue, [:long, :string], :void
109
+ attach_function :BoundingRectangle, [SearchCriteria.by_ref, :pointer], :int
110
+ attach_function :current_control_type, :ControlType, [SearchCriteria.by_ref], :int
111
+ attach_function :Name, [SearchCriteria.by_ref, :pointer, :int], :void
112
+ attach_function :ClassName, [SearchCriteria.by_ref, :pointer, :int], :void
113
+ attach_function :GetClassNames,
114
+ [SearchCriteria.by_ref, :pointer], :int
115
+
116
+ def self.exists?(search_information)
117
+ ElementExists search_information
118
+ end
119
+
120
+ def self.bounding_rectangle(search_information)
121
+ boundary = FFI::MemoryPointer.new :long, 4
122
+ BoundingRectangle search_information, boundary
123
+ boundary.read_array_of_long(4)
124
+ end
125
+
126
+ def self.get_control_value(hwnd)
127
+ string_from(:Control_GetValue, hwnd)
128
+ end
129
+
130
+ def self.name(search_information)
131
+ string_from(:Name, search_information)
132
+ end
133
+
134
+ def self.class_name(search_information)
135
+ string_from(:ClassName, search_information)
136
+ end
137
+
138
+ def self.children_class_names(search_information)
139
+ strings_from :GetClassNames, search_information
140
+ end
141
+
142
+ # Toggle methods
143
+ attach_function :is_set, :IsSet, [SearchCriteria.by_ref], :bool
144
+
145
+ # Selection Item methods
146
+ attach_function :is_selected, :IsSelected, [SearchCriteria.by_ref], :bool
147
+
148
+ # Select List methods
149
+ attach_function :SelectList_Selection,
150
+ [SearchCriteria.by_ref, :pointer, :int], :void
151
+ attach_function :select_list_count, :SelectList_Count,
152
+ [SearchCriteria.by_ref], :int
153
+ attach_function :select_list_selected_index, :SelectList_SelectedIndex,
154
+ [:long], :int
155
+ attach_function :select_list_value_at, :SelectList_ValueAt,
156
+ [:long, :int, :pointer, :int], :bool
157
+ attach_function :select_list_select_index, :SelectList_SelectIndex,
158
+ [SearchCriteria.by_ref, :int], :bool
159
+ attach_function :select_list_select_value, :SelectList_SelectValue,
160
+ [SearchCriteria.by_ref, :pointer], :int
161
+
162
+ def self.selection(search_information)
163
+ string_from(:SelectList_Selection, search_information)
164
+ end
165
+
166
+ # Menu methods
167
+ attach_function :select_menu_item, :Menu_SelectPath,
168
+ [:long, :pointer, :int, :varargs], :void
169
+ attach_function :menu_item_exists, :Menu_ItemExists,
170
+ [:long, :varargs], :bool
171
+
172
+ # Table methods
173
+ attach_function :Table_GetHeaders,
174
+ [:long, :pointer], :int
175
+ attach_function :Table_GetValues,
176
+ [:long, :pointer], :int
177
+ attach_function :Table_FindValues,
178
+ [SearchCriteria.by_ref, :pointer], :int
179
+ attach_function :table_row_count, :Table_RowCount,
180
+ [:long], :int
181
+ attach_function :Table_CoordinateIsValid,
182
+ [:long, :int, :int], :bool
183
+ attach_function :Table_ValueAt,
184
+ [:long, :int, :int, :pointer, :int], :void
185
+ attach_function :Table_SelectByIndex,
186
+ [:long, :int], :void
187
+ attach_function :Table_SelectByValue,
188
+ [:long, :string], :void
189
+ attach_function :table_row_is_selected, :Table_IsSelectedByIndex,
190
+ [:long, :int], :bool
191
+
192
+ def self.table_select(hwnd, which_item)
193
+ case which_item
194
+ when Integer
195
+ Table_SelectByIndex hwnd, which_item
196
+ when String
197
+ Table_SelectByValue hwnd, which_item
198
+ end
199
+ end
200
+
201
+ def self.table_value_at(hwnd, row, column=0)
202
+ string_from(:Table_ValueAt, hwnd, row, column)
203
+ end
204
+
205
+ def self.table_coordinate_valid?(hwnd, row, column=0)
206
+ Table_CoordinateIsValid hwnd, row, column
207
+ end
208
+
209
+ def self.table_headers(hwnd)
210
+ strings_from :Table_GetHeaders, hwnd
211
+ end
212
+
213
+ def self.table_values(hwnd)
214
+ strings_from :Table_GetValues, hwnd
215
+ end
216
+
217
+ def self.find_table_values(search_information)
218
+ strings_from :Table_FindValues, search_information
219
+ end
220
+
221
+ # String methods
222
+ attach_function :clean_up_strings, :String_CleanUp,
223
+ [:pointer, :int], :void
224
+
17
225
  attach_function :element_from_handle, :RA_ElementFromHandle,
18
226
  [:long], :pointer
19
227
  attach_function :element_from_point, :RA_ElementFromPoint,
20
228
  [:int, :int], :pointer
21
- attach_function :get_focused_element, :RA_GetFocusedElement,
22
- [], :pointer
23
229
  attach_function :find_child_by_id, :RA_FindChildById,
24
230
  [:pointer, :string], :pointer
25
- attach_function :find_child_by_name, :RA_FindChildByName,
26
- [:pointer, :string], :pointer
27
231
  attach_function :current_native_window_handle, :RA_CurrentNativeWindowHandle,
28
232
  [:pointer], :long
29
233
  attach_function :set_focus, :RA_SetFocus,
30
234
  [:pointer], :bool
31
- attach_function :current_control_type, :RA_GetCurrentControlType,
32
- [:pointer], :int
33
- attach_function :desktop_handle, :RA_GetDesktopHandle,
34
- [], :long
35
235
  attach_function :move_mouse, :RA_MoveMouse,
36
236
  [:int,:int], :long
37
237
  attach_function :click_mouse, :RA_ClickMouse,
38
238
  [], :long
39
- attach_function :bounding_rectangle, :RA_CurrentBoundingRectangle,
40
- [:pointer, :pointer], :int
41
239
  attach_function :is_offscreen, :RA_CurrentIsOffscreen,
42
240
  [:pointer, :pointer], :int
43
241
  attach_function :find_children, :RA_FindChildren,
44
242
  [: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 :get_is_set, :RA_GetIsSet,
52
- [:pointer], :bool
243
+ attach_function :get_control_name, :RA_GetControlName,
244
+ [:long, :pointer, :int], :bool
53
245
  attach_function :select, :RA_Select,
54
246
  [: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
- attach_function :select_combo_by_index, :RA_SelectComboByIndex,
60
- [:long, :int], :bool
61
- attach_function :set_value, :RA_SelectComboByValue,
62
- [:pointer, :pointer], :int
63
- attach_function :select_menu_item, :RA_SelectMenuItem,
64
- [:long, :pointer, :int, :varargs], :void
65
- attach_function :menu_item_exists, :RA_MenuItemExists,
66
- [:long, :varargs], :bool
67
- attach_function :get_combobox_count, :RA_GetComboOptionsCount,
68
- [:long], :int
69
- attach_function :get_combobox_value, :RA_GetComboValueByIndex,
70
- [:long, :int, :pointer, :int], :bool
71
- attach_function :get_combobox_selected_index, :RA_GetSelectedComboIndex,
72
- [:long], :int
73
- attach_function :get_data_item_count, :RA_GetDataItemCount,
74
- [:long], :int
75
- attach_function :select_data_item, :RA_SelectDataItem,
76
- [:long, :int], :void
77
247
  attach_function :expand_by_value, :RA_ExpandItemByValue,
78
248
  [:long, :string], :void
79
249
  attach_function :expand_by_index, :RA_ExpandItemByIndex,
@@ -82,27 +252,25 @@ module RAutomation
82
252
  [:long, :string], :void
83
253
  attach_function :collapse_by_index, :RA_CollapseItemByIndex,
84
254
  [:long, :int], :void
85
- attach_function :data_item_exists_by_value, :RA_DataItemExistsByValue,
86
- [:long, :string], :bool
87
- attach_function :RA_DataItemExists,
88
- [:long, :int, :int], :bool
89
-
90
- attach_function :RA_CellValueAt,
91
- [:long, :int, :int, :pointer, :int], :void
92
-
93
255
  attach_function :control_click, :RA_Click,
94
256
  [:long, :pointer, :int], :void
95
257
  attach_function :control_mouse_click, :RA_PointAndClick,
96
258
  [:long, :pointer, :int], :void
97
259
 
98
- def self.cell_value_at(hwnd, row, column=0)
99
- string = FFI::MemoryPointer.new :char, 1024
100
- RA_CellValueAt hwnd, row, column, string, 1024
101
- string.read_string
260
+ private
261
+ def self.strings_from(method, hwnd)
262
+ string_count = send method, hwnd, nil
263
+ pointer = FFI::MemoryPointer.new :pointer, string_count
264
+ send method, hwnd, pointer
265
+ strings = pointer.get_array_of_string 0, string_count
266
+ clean_up_strings pointer, string_count
267
+ strings
102
268
  end
103
269
 
104
- def self.data_item_exists(hwnd, row, column=0)
105
- RA_DataItemExists hwnd, row, column
270
+ def self.string_from(method, *args)
271
+ pointer = FFI::MemoryPointer.new :pointer, 1024
272
+ send method, *(args << pointer << 1024)
273
+ pointer.read_string
106
274
  end
107
275
  end
108
276
  end