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
@@ -0,0 +1,21 @@
1
+ module RAutomation
2
+ module Adapter
3
+ module MsUia
4
+ class ValueControl < Control
5
+ include WaitHelper
6
+ include Locators
7
+
8
+ def value
9
+ UiaDll::get_control_value(hwnd)
10
+ end
11
+
12
+ def set(value)
13
+ UiaDll::set_control_value(hwnd, value)
14
+ end
15
+
16
+ alias_method :exists?, :exist?
17
+ end
18
+ end
19
+ end
20
+ end
21
+
@@ -10,17 +10,6 @@ module RAutomation
10
10
 
11
11
  has_many :controls
12
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
13
  # Locators of the window.
25
14
  attr_reader :locators
26
15
 
@@ -64,15 +53,8 @@ module RAutomation
64
53
 
65
54
  # @see RAutomation::Window#class_names
66
55
  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
56
+ classes = UiaDll::children_class_names(UiaDll::SearchCriteria.from_locator(hwnd, :hwnd => hwnd))
57
+ classes.delete_if(&:empty?).sort
76
58
  end
77
59
 
78
60
  # @see RAutomation::Window#activate
@@ -178,6 +160,10 @@ module RAutomation
178
160
  Button.new(self, locator)
179
161
  end
180
162
 
163
+ def value_control(locator)
164
+ ValueControl.new(self, locator)
165
+ end
166
+
181
167
  # @see TextField#initialize
182
168
  # @see RAutomation::Window#text_field
183
169
  def text_field(locator)
@@ -196,94 +182,10 @@ module RAutomation
196
182
  Functions.respond_to?(name) ? Functions.send(name, *args) : super
197
183
  end
198
184
 
199
- # MsUia adapter specific API methods
200
- def element
201
- case
202
- when @locators[:focus]
203
- uia_control = UiaDll::get_focused_element
204
- when @locators[:id]
205
- uia_control = UiaDll::find_window(@locators[:id].to_s)
206
- raise UnknownElementException, "#{@locators[:id]} does not exist" if uia_control.nil?
207
- when @locators[:point]
208
- uia_control = UiaDll::element_from_point(@locators[:point][0], @locators[:point][1])
209
- raise UnknownElementException, "#{@locators[:point]} does not exist" if uia_control.nil?
210
- else
211
- hwnd = find_hwnd(locators, window_hwnd) do |hwnd|
212
- locators_match?(locators, control_properties(hwnd, locators))
213
- end
214
- raise UnknownElementException, "Element with #{locators.inspect} does not exist" if (hwnd == 0) or (hwnd == nil)
215
- uia_control = UiaDll::element_from_handle(hwnd)
216
- end
217
- uia_control
218
- end
219
-
220
- def new_pid
221
- UiaDll::current_process_id(uia_control())
222
- end
223
-
224
- def display_tree
225
- root_element = UiaDll::element_from_handle(hwnd)
226
-
227
- root_name = FFI::MemoryPointer.new :char, UiaDll::get_name(root_element, nil) + 1
228
- UiaDll::get_name(root_element, root_name)
229
-
230
- [root_name.read_string.inspect, gather_children(root_element)]
231
- end
232
-
233
- def gather_children(root_element)
234
- element_tree = []
235
-
236
- child_count = count_children(root_element)
237
- children = FFI::MemoryPointer.new :pointer, child_count
238
- UiaDll::find_children(root_element, children)
239
-
240
- children.read_array_of_pointer(child_count).each do |child|
241
- child_name = FFI::MemoryPointer.new :char, UiaDll::get_name(child, nil) + 1
242
- UiaDll::get_name(child, child_name)
243
-
244
- grandchild_count = count_children(child)
245
-
246
- if grandchild_count > 0
247
- element_tree << [child_name.read_string, gather_children(child)]
248
- else
249
- element_tree << child_name.read_string
250
- end
251
- end
252
-
253
- element_tree
254
- end
255
-
256
185
  def count_children(element)
257
186
  UiaDll::find_children(element, nil)
258
187
  end
259
188
 
260
- def gather_children_classes(root_element)
261
- element_tree = []
262
-
263
- child_count = count_children(root_element)
264
- children = FFI::MemoryPointer.new :pointer, child_count
265
- UiaDll::find_children(root_element, children)
266
-
267
- children.read_array_of_pointer(child_count).each do |child|
268
- child_name = FFI::MemoryPointer.new :char, UiaDll::get_class_name(child, nil) + 1
269
- UiaDll::get_class_name(child, child_name)
270
-
271
- grandchild_count = count_children(child)
272
-
273
- if grandchild_count > 0
274
- element_tree << [child_name.read_string, gather_children_classes(child)]
275
- else
276
- element_tree << child_name.read_string
277
- end
278
- end
279
-
280
- element_tree
281
- end
282
-
283
- def get_focused_element
284
- UiaDll::get_focused_element()
285
- end
286
-
287
189
  def bounding_rectangle
288
190
  window = UiaDll::element_from_handle(hwnd)
289
191
 
@@ -5,7 +5,6 @@ module RAutomation
5
5
  module Functions
6
6
  extend FFI::Library
7
7
 
8
- # TODO once done adapt the path to the DLL (somewhere in the packaged gem)
9
8
  ffi_lib 'user32', 'kernel32', 'ole32', File.dirname(__FILE__) + '/../../../../ext/IAccessibleDLL/Release/iaccessibleDll.dll'
10
9
  ffi_convention :stdcall
11
10
 
@@ -242,28 +241,6 @@ module RAutomation
242
241
  string_buffer.read_string
243
242
  end
244
243
 
245
- def control_name(control_hwnd)
246
- string_buffer = FFI::MemoryPointer.new :char, 255
247
- if (get_control_name(control_hwnd, string_buffer) == Constants::S_OK)
248
- string_buffer.read_string
249
- else
250
- fail "Cannot get name for control with HWND 0x" + control_hwnd.to_s(16)
251
- end
252
- end
253
-
254
- def retrieve_table_strings_for_row(control_hwnd, row)
255
- hModule = load_library("oleacc.dll") # TODO should be done only one time
256
-
257
- strings_ptr = FFI::MemoryPointer.new :pointer
258
- columns_ptr = FFI::MemoryPointer.new :pointer
259
-
260
- get_table_row_strings(hModule, control_hwnd, strings_ptr, row, columns_ptr)
261
- str_ptr = strings_ptr.read_pointer
262
- columns = columns_ptr.read_long
263
-
264
- str_ptr.get_array_of_string(0, columns)
265
- end
266
-
267
244
  private
268
245
 
269
246
  def within_foreground_thread(hwnd)
@@ -4,67 +4,70 @@ module RAutomation
4
4
  class Keys
5
5
  KEYS = {
6
6
  # keycodes from http://msdn.microsoft.com/en-us/library/ms927178.aspx
7
- :null => 0x00,
8
- :cancel => 0x03,
9
- :help => 0x2F,
10
- :backspace => 0x08,
11
- :tab => 0x09,
12
- :clear => 0x0C,
13
- :return => 0x0D,
14
- :enter => 0x0D,
15
- :shift => 0x10,
16
- :left_shift => 0xA0,
17
- :control => 0x11,
18
- :left_control => 0xA2,
19
- :alt => 0x12,
20
- :left_alt => 0xA4,
21
- :pause => 0x13,
22
- :escape => 0x1B,
23
- :space => 0x20,
24
- :page_up => 0x21,
25
- :page_down => 0x22,
26
- :end => 0x23,
27
- :home => 0x24,
28
- :left => 0x25,
29
- :arrow_left => 0x25,
30
- :up => 0x26,
31
- :arrow_up => 0x26,
32
- :right => 0x27,
33
- :arrow_right => 0x27,
34
- :down => 0x28,
35
- :arrow_down => 0x28,
36
- :insert => 0x2D,
37
- :delete => 0x2E,
38
- :semicolon => 0x3B,
39
- :equals => 0x3D,
40
- :numpad0 => 0x60,
41
- :numpad1 => 0x61,
42
- :numpad2 => 0x62,
43
- :numpad3 => 0x63,
44
- :numpad4 => 0x64,
45
- :numpad5 => 0x65,
46
- :numpad6 => 0x66,
47
- :numpad7 => 0x67,
48
- :numpad8 => 0x68,
49
- :numpad9 => 0x69,
50
- :multiply => 0x6A,
51
- :add => 0x6B,
52
- :separator => 0x6C,
53
- :subtract => 0x6D,
54
- :decimal => 0x6E,
55
- :divide => 0x6F,
56
- :f1 => 0x70,
57
- :f2 => 0x71,
58
- :f3 => 0x72,
59
- :f4 => 0x73,
60
- :f5 => 0x74,
61
- :f6 => 0x75,
62
- :f7 => 0x76,
63
- :f8 => 0x77,
64
- :f9 => 0x78,
65
- :f10 => 0x79,
66
- :f11 => 0x7A,
67
- :f12 => 0x7B,
7
+ :null => 0x00,
8
+ :cancel => 0x03,
9
+ :help => 0x2F,
10
+ :backspace => 0x08,
11
+ :tab => 0x09,
12
+ :clear => 0x0C,
13
+ :return => 0x0D,
14
+ :enter => 0x0D,
15
+ :shift => 0x10,
16
+ :left_shift => 0xA0,
17
+ :control => 0x11,
18
+ :left_control => 0xA2,
19
+ :alt => 0x12,
20
+ :left_alt => 0xA4,
21
+ :left_bracket => 0xDB,
22
+ :right_bracket => 0xDD,
23
+ :single_quote => 0xDE,
24
+ :pause => 0x13,
25
+ :escape => 0x1B,
26
+ :space => 0x20,
27
+ :page_up => 0x21,
28
+ :page_down => 0x22,
29
+ :end => 0x23,
30
+ :home => 0x24,
31
+ :left => 0x25,
32
+ :arrow_left => 0x25,
33
+ :up => 0x26,
34
+ :arrow_up => 0x26,
35
+ :right => 0x27,
36
+ :arrow_right => 0x27,
37
+ :down => 0x28,
38
+ :arrow_down => 0x28,
39
+ :insert => 0x2D,
40
+ :delete => 0x2E,
41
+ :semicolon => 0x3B,
42
+ :equals => 0x3D,
43
+ :numpad0 => 0x60,
44
+ :numpad1 => 0x61,
45
+ :numpad2 => 0x62,
46
+ :numpad3 => 0x63,
47
+ :numpad4 => 0x64,
48
+ :numpad5 => 0x65,
49
+ :numpad6 => 0x66,
50
+ :numpad7 => 0x67,
51
+ :numpad8 => 0x68,
52
+ :numpad9 => 0x69,
53
+ :multiply => 0x6A,
54
+ :add => 0x6B,
55
+ :separator => 0x6C,
56
+ :subtract => 0x6D,
57
+ :decimal => 0x6E,
58
+ :divide => 0x6F,
59
+ :f1 => 0x70,
60
+ :f2 => 0x71,
61
+ :f3 => 0x72,
62
+ :f4 => 0x73,
63
+ :f5 => 0x74,
64
+ :f6 => 0x75,
65
+ :f7 => 0x76,
66
+ :f8 => 0x77,
67
+ :f9 => 0x78,
68
+ :f10 => 0x79,
69
+ :f11 => 0x7A,
70
+ :f12 => 0x7B,
68
71
  }
69
72
 
70
73
  SPECIAL_KEYS = {
data/rautomation.gemspec CHANGED
@@ -15,7 +15,12 @@ RAutomation provides:
15
15
  s.homepage = %q{http://github.com/jarmo/RAutomation}
16
16
  s.summary = %q{Automate windows and their controls through user-friendly API with Ruby}
17
17
 
18
- s.files = `git ls-files`.split("\n")
18
+ ext_binaries = [
19
+ "ext/IAccessibleDLL/Release/IAccessibleDLL.dll",
20
+ "ext/UiaDll/Release/UiaDll.dll",
21
+ "ext/WindowsForms/Release/WindowsForms.exe"
22
+ ]
23
+ s.files = `git ls-files`.split("\n") + ext_binaries
19
24
  s.test_files = `git ls-files -- spec/*`.split("\n")
20
25
  s.require_paths = ["lib"]
21
26
 
@@ -28,7 +28,7 @@ describe "AutoIt::Mouse", :if => SpecHelper.adapter == :autoit do
28
28
  window = RAutomation::Window.new(:title => "MainFormWindow")
29
29
  window.maximize
30
30
 
31
- text_field = window.text_field(:index => 1)
31
+ text_field = window.text_field(:index => 2)
32
32
  text_field.set("start string")
33
33
  text_field.value.should == "start string"
34
34
 
@@ -98,25 +98,4 @@ describe "MsUia::SelectList", :if => SpecHelper.adapter == :ms_uia do
98
98
  select_list.option(:text => "Orange").should be_selected
99
99
  label.value.should == "Orange"
100
100
  end
101
-
102
- # it "control by focus" do
103
- # window = RAutomation::Window.new(:title => /MainFormWindow/i)
104
- #
105
- # button = window.button(:value => "Reset")
106
- # button.set_focus
107
- #
108
- # element = window.get_focused_element
109
- # type =button.get_current_control_type(element)
110
- # puts "type :#{type}"
111
-
112
- # box1 = another_button.bounding_rectangle
113
- # box2 = button.bounding_rectangle
114
- #
115
- #
116
- # puts "#{box1}"
117
- # puts "#{box2}"
118
- #
119
- # sleep 10
120
- # box1.should == box2
121
- # end
122
101
  end
@@ -1,13 +1,14 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe "MsUia::Table", :if => SpecHelper.adapter == :ms_uia do
4
+ let(:table) { RAutomation::Window.new(:title => "DataEntryForm").table(:id => "personListView") }
5
+
4
6
  before :each do
5
7
  window = RAutomation::Window.new(:title => "MainFormWindow")
6
8
  window.button(:value => "Data Entry Form").click { RAutomation::Window.new(:title => "DataEntryForm").exists? }
7
9
  end
8
10
 
9
11
  it "#table" do
10
- table = RAutomation::Window.new(:title => "DataEntryForm").table(:id => "personListView")
11
12
  table.should exist
12
13
 
13
14
  RAutomation::Window.wait_timeout = 0.1
@@ -18,7 +19,6 @@ describe "MsUia::Table", :if => SpecHelper.adapter == :ms_uia do
18
19
 
19
20
  it "check for table class" do
20
21
  RAutomation::Window.new(:title => "DataEntryForm").table(:id => "deleteItemButton").should_not exist
21
- RAutomation::Window.new(:title => "DataEntryForm").table(:id => "personListView").should exist
22
22
  end
23
23
 
24
24
  it "#strings" do
@@ -28,7 +28,6 @@ describe "MsUia::Table", :if => SpecHelper.adapter == :ms_uia do
28
28
  end
29
29
 
30
30
  it "#strings with nested elements" do
31
- table = RAutomation::Window.new(:title => "DataEntryForm").table(:id => "personListView")
32
31
 
33
32
  table.strings.should == [
34
33
  ["Name", "Date of birth", "State"],
@@ -37,24 +36,27 @@ describe "MsUia::Table", :if => SpecHelper.adapter == :ms_uia do
37
36
  ]
38
37
  end
39
38
 
40
- it "#select" do
41
- table = RAutomation::Window.new(:title => "DataEntryForm").table(:id => "personListView")
39
+ it "#select by index" do
40
+ table.select(0)
41
+ table.should_not be_selected(1)
42
42
 
43
43
  table.select(1)
44
- table.should_not be_selected(2)
44
+ table.should be_selected(1)
45
+ end
45
46
 
46
- table.select(2)
47
- table.should be_selected(2)
47
+ it "#select by value" do
48
+ table.select "John Doe"
49
+ table.should_not be_selected(1)
50
+
51
+ table.select "Anna Doe"
52
+ table.should be_selected(1)
48
53
  end
49
54
 
50
55
  it "#row_count" do
51
- table = RAutomation::Window.new(:title => "DataEntryForm").table(:id => "personListView")
52
56
  table.row_count.should eq(2)
53
57
  end
54
58
 
55
59
  context "#rows" do
56
- let(:table) { RAutomation::Window.new(:title => "DataEntryForm").table(:id => "personListView") }
57
-
58
60
  it "has rows" do
59
61
  table.rows.size.should eq 2
60
62
  end