rautomation 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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