rautomation 2.0.1-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (202) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +41 -0
  4. data/.rspec +2 -0
  5. data/.yardopts +8 -0
  6. data/CHANGES.md +276 -0
  7. data/Gemfile +3 -0
  8. data/LICENSE +20 -0
  9. data/README.md +142 -0
  10. data/Rakefile +73 -0
  11. data/ext/AutoItX/AutoItX.chm +0 -0
  12. data/ext/AutoItX/AutoItX3.dll +0 -0
  13. data/ext/IAccessibleDLL/IAccessibleDLL/IAccessibleDLL.cpp +30 -0
  14. data/ext/IAccessibleDLL/IAccessibleDLL/IAccessibleDLL.vcxproj +179 -0
  15. data/ext/IAccessibleDLL/IAccessibleDLL/IAccessibleDLL.vcxproj.filters +42 -0
  16. data/ext/IAccessibleDLL/IAccessibleDLL/IAccessibleDLL.vcxproj.user +3 -0
  17. data/ext/IAccessibleDLL/IAccessibleDLL/ReadMe.txt +48 -0
  18. data/ext/IAccessibleDLL/IAccessibleDLL/dllmain.cpp +19 -0
  19. data/ext/IAccessibleDLL/IAccessibleDLL/stdafx.cpp +8 -0
  20. data/ext/IAccessibleDLL/IAccessibleDLL/stdafx.h +22 -0
  21. data/ext/IAccessibleDLL/IAccessibleDLL/table_support.cpp +282 -0
  22. data/ext/IAccessibleDLL/IAccessibleDLL/targetver.h +8 -0
  23. data/ext/IAccessibleDLL/IAccessibleDLL.sln +31 -0
  24. data/ext/IAccessibleDLL/IAccessibleDLL.suo +0 -0
  25. data/ext/IAccessibleDLL/Release/IAccessibleDLL.dll +0 -0
  26. data/ext/UiaDll/RAutomation.UIA/Controls/Clicker.cs +63 -0
  27. data/ext/UiaDll/RAutomation.UIA/Controls/SelectList.cs +116 -0
  28. data/ext/UiaDll/RAutomation.UIA/Controls/Spinner.cs +46 -0
  29. data/ext/UiaDll/RAutomation.UIA/Controls/TabControl.cs +54 -0
  30. data/ext/UiaDll/RAutomation.UIA/Controls/TableControl.cs +132 -0
  31. data/ext/UiaDll/RAutomation.UIA/Controls/TextControl.cs +50 -0
  32. data/ext/UiaDll/RAutomation.UIA/Expander.cs +59 -0
  33. data/ext/UiaDll/RAutomation.UIA/Extensions/Element.cs +166 -0
  34. data/ext/UiaDll/RAutomation.UIA/Extensions/Enumerable.cs +76 -0
  35. data/ext/UiaDll/RAutomation.UIA/Extensions/Property.cs +27 -0
  36. data/ext/UiaDll/RAutomation.UIA/Properties/AssemblyInfo.cs +36 -0
  37. data/ext/UiaDll/RAutomation.UIA/Properties/AutomationProperties.cs +18 -0
  38. data/ext/UiaDll/RAutomation.UIA/RAutomation.UIA.csproj +77 -0
  39. data/ext/UiaDll/Release/RAutomation.UIA.dll +0 -0
  40. data/ext/UiaDll/Release/UiaDll.dll +0 -0
  41. data/ext/UiaDll/UiaDll/ArrayHelper.cpp +14 -0
  42. data/ext/UiaDll/UiaDll/ArrayHelper.h +7 -0
  43. data/ext/UiaDll/UiaDll/AssemblyInfo.cpp +40 -0
  44. data/ext/UiaDll/UiaDll/ControlMethods.cpp +16 -0
  45. data/ext/UiaDll/UiaDll/DynamicAssemblyResolver.cpp +24 -0
  46. data/ext/UiaDll/UiaDll/DynamicAssemblyResolver.h +16 -0
  47. data/ext/UiaDll/UiaDll/Locator.cpp +93 -0
  48. data/ext/UiaDll/UiaDll/Locator.h +55 -0
  49. data/ext/UiaDll/UiaDll/MenuItemSelector.cpp +75 -0
  50. data/ext/UiaDll/UiaDll/MenuItemSelector.h +24 -0
  51. data/ext/UiaDll/UiaDll/MenuMethods.cpp +62 -0
  52. data/ext/UiaDll/UiaDll/ReadMe.txt +38 -0
  53. data/ext/UiaDll/UiaDll/SelectListMethods.cpp +84 -0
  54. data/ext/UiaDll/UiaDll/SpinnerMethods.cpp +61 -0
  55. data/ext/UiaDll/UiaDll/StringHelper.cpp +57 -0
  56. data/ext/UiaDll/UiaDll/StringHelper.h +15 -0
  57. data/ext/UiaDll/UiaDll/StringMethods.cpp +8 -0
  58. data/ext/UiaDll/UiaDll/TabControlMethods.cpp +40 -0
  59. data/ext/UiaDll/UiaDll/TableMethods.cpp +108 -0
  60. data/ext/UiaDll/UiaDll/TextMethods.cpp +25 -0
  61. data/ext/UiaDll/UiaDll/ToggleStateHelper.h +10 -0
  62. data/ext/UiaDll/UiaDll/UiaDll.cpp +216 -0
  63. data/ext/UiaDll/UiaDll/UiaDll.h +13 -0
  64. data/ext/UiaDll/UiaDll/UiaDll.vcxproj +167 -0
  65. data/ext/UiaDll/UiaDll/UiaDll.vcxproj.filters +110 -0
  66. data/ext/UiaDll/UiaDll/app.ico +0 -0
  67. data/ext/UiaDll/UiaDll/app.rc +0 -0
  68. data/ext/UiaDll/UiaDll/dllmain.cpp +1 -0
  69. data/ext/UiaDll/UiaDll/resource.h +3 -0
  70. data/ext/UiaDll/UiaDll/stdafx.cpp +5 -0
  71. data/ext/UiaDll/UiaDll/stdafx.h +41 -0
  72. data/ext/UiaDll/UiaDll/targetver.h +8 -0
  73. data/ext/UiaDll/UiaDll.sln +57 -0
  74. data/ext/WindowsForms/.nuget/NuGet.Config +6 -0
  75. data/ext/WindowsForms/.nuget/NuGet.exe +0 -0
  76. data/ext/WindowsForms/.nuget/NuGet.targets +136 -0
  77. data/ext/WindowsForms/Release/FizzWare.NBuilder.dll +0 -0
  78. data/ext/WindowsForms/Release/UIA.Extensions.dll +0 -0
  79. data/ext/WindowsForms/Release/WindowsForms.exe +0 -0
  80. data/ext/WindowsForms/WindowsForms/AboutBox.Designer.cs +168 -0
  81. data/ext/WindowsForms/WindowsForms/AboutBox.cs +103 -0
  82. data/ext/WindowsForms/WindowsForms/AboutBox.resx +123 -0
  83. data/ext/WindowsForms/WindowsForms/DataEntryForm.Designer.cs +218 -0
  84. data/ext/WindowsForms/WindowsForms/DataEntryForm.cs +52 -0
  85. data/ext/WindowsForms/WindowsForms/DataEntryForm.resx +120 -0
  86. data/ext/WindowsForms/WindowsForms/DataGridView.Designer.cs +77 -0
  87. data/ext/WindowsForms/WindowsForms/DataGridView.cs +43 -0
  88. data/ext/WindowsForms/WindowsForms/DataGridView.resx +120 -0
  89. data/ext/WindowsForms/WindowsForms/FizzWare.NBuilder.dll +0 -0
  90. data/ext/WindowsForms/WindowsForms/MainFormWindow.Designer.cs +527 -0
  91. data/ext/WindowsForms/WindowsForms/MainFormWindow.cs +109 -0
  92. data/ext/WindowsForms/WindowsForms/MainFormWindow.resx +126 -0
  93. data/ext/WindowsForms/WindowsForms/PersonForm.Designer.cs +119 -0
  94. data/ext/WindowsForms/WindowsForms/PersonForm.cs +34 -0
  95. data/ext/WindowsForms/WindowsForms/PersonForm.resx +120 -0
  96. data/ext/WindowsForms/WindowsForms/Program.cs +21 -0
  97. data/ext/WindowsForms/WindowsForms/Properties/AssemblyInfo.cs +36 -0
  98. data/ext/WindowsForms/WindowsForms/Properties/Resources.Designer.cs +71 -0
  99. data/ext/WindowsForms/WindowsForms/Properties/Resources.resx +117 -0
  100. data/ext/WindowsForms/WindowsForms/Properties/Settings.Designer.cs +30 -0
  101. data/ext/WindowsForms/WindowsForms/Properties/Settings.settings +7 -0
  102. data/ext/WindowsForms/WindowsForms/SimpleElementsForm.Designer.cs +93 -0
  103. data/ext/WindowsForms/WindowsForms/SimpleElementsForm.cs +19 -0
  104. data/ext/WindowsForms/WindowsForms/SimpleElementsForm.resx +120 -0
  105. data/ext/WindowsForms/WindowsForms/UIA.Extensions.dll +0 -0
  106. data/ext/WindowsForms/WindowsForms/ValueMonthCalendar.cs +28 -0
  107. data/ext/WindowsForms/WindowsForms/WindowsForms.csproj +166 -0
  108. data/ext/WindowsForms/WindowsForms/packages.config +4 -0
  109. data/ext/WindowsForms/WindowsForms.sln +46 -0
  110. data/lib/rautomation/adapter/autoit/button.rb +59 -0
  111. data/lib/rautomation/adapter/autoit/locators.rb +22 -0
  112. data/lib/rautomation/adapter/autoit/mouse.rb +38 -0
  113. data/lib/rautomation/adapter/autoit/text_field.rb +70 -0
  114. data/lib/rautomation/adapter/autoit/window.rb +197 -0
  115. data/lib/rautomation/adapter/autoit.rb +8 -0
  116. data/lib/rautomation/adapter/helper.rb +64 -0
  117. data/lib/rautomation/adapter/ms_uia/button.rb +21 -0
  118. data/lib/rautomation/adapter/ms_uia/button_helper.rb +19 -0
  119. data/lib/rautomation/adapter/ms_uia/checkbox.rb +23 -0
  120. data/lib/rautomation/adapter/ms_uia/constants.rb +111 -0
  121. data/lib/rautomation/adapter/ms_uia/control.rb +134 -0
  122. data/lib/rautomation/adapter/ms_uia/functions.rb +279 -0
  123. data/lib/rautomation/adapter/ms_uia/keys.rb +121 -0
  124. data/lib/rautomation/adapter/ms_uia/keystroke_converter.rb +122 -0
  125. data/lib/rautomation/adapter/ms_uia/label.rb +18 -0
  126. data/lib/rautomation/adapter/ms_uia/list_box.rb +46 -0
  127. data/lib/rautomation/adapter/ms_uia/list_item.rb +22 -0
  128. data/lib/rautomation/adapter/ms_uia/locators.rb +23 -0
  129. data/lib/rautomation/adapter/ms_uia/menu.rb +36 -0
  130. data/lib/rautomation/adapter/ms_uia/radio.rb +23 -0
  131. data/lib/rautomation/adapter/ms_uia/select_list.rb +85 -0
  132. data/lib/rautomation/adapter/ms_uia/spinner.rb +31 -0
  133. data/lib/rautomation/adapter/ms_uia/tab_control.rb +46 -0
  134. data/lib/rautomation/adapter/ms_uia/table.rb +140 -0
  135. data/lib/rautomation/adapter/ms_uia/text_field.rb +39 -0
  136. data/lib/rautomation/adapter/ms_uia/uia_dll.rb +428 -0
  137. data/lib/rautomation/adapter/ms_uia/value_control.rb +21 -0
  138. data/lib/rautomation/adapter/ms_uia/window.rb +289 -0
  139. data/lib/rautomation/adapter/ms_uia.rb +27 -0
  140. data/lib/rautomation/adapter/win_32/button.rb +14 -0
  141. data/lib/rautomation/adapter/win_32/button_helper.rb +24 -0
  142. data/lib/rautomation/adapter/win_32/checkbox.rb +14 -0
  143. data/lib/rautomation/adapter/win_32/constants.rb +73 -0
  144. data/lib/rautomation/adapter/win_32/control.rb +86 -0
  145. data/lib/rautomation/adapter/win_32/functions.rb +336 -0
  146. data/lib/rautomation/adapter/win_32/keys.rb +146 -0
  147. data/lib/rautomation/adapter/win_32/label.rb +10 -0
  148. data/lib/rautomation/adapter/win_32/list_box.rb +40 -0
  149. data/lib/rautomation/adapter/win_32/locators.rb +22 -0
  150. data/lib/rautomation/adapter/win_32/mouse.rb +59 -0
  151. data/lib/rautomation/adapter/win_32/password_field.rb +15 -0
  152. data/lib/rautomation/adapter/win_32/radio.rb +11 -0
  153. data/lib/rautomation/adapter/win_32/select_list.rb +97 -0
  154. data/lib/rautomation/adapter/win_32/table.rb +25 -0
  155. data/lib/rautomation/adapter/win_32/text_field.rb +52 -0
  156. data/lib/rautomation/adapter/win_32/window.rb +277 -0
  157. data/lib/rautomation/adapter/win_32.rb +23 -0
  158. data/lib/rautomation/button.rb +55 -0
  159. data/lib/rautomation/element_collections.rb +55 -0
  160. data/lib/rautomation/platform.rb +15 -0
  161. data/lib/rautomation/text_field.rb +60 -0
  162. data/lib/rautomation/version.rb +3 -0
  163. data/lib/rautomation/wait_helper.rb +23 -0
  164. data/lib/rautomation/window.rb +248 -0
  165. data/lib/rautomation.rb +8 -0
  166. data/rautomation.gemspec +52 -0
  167. data/spec/adapter/autoit/mouse_spec.rb +53 -0
  168. data/spec/adapter/autoit/window_spec.rb +17 -0
  169. data/spec/adapter/ms_uia/button_spec.rb +39 -0
  170. data/spec/adapter/ms_uia/checkbox_spec.rb +55 -0
  171. data/spec/adapter/ms_uia/control_spec.rb +88 -0
  172. data/spec/adapter/ms_uia/functions_spec.rb +39 -0
  173. data/spec/adapter/ms_uia/keystroke_converter_spec.rb +48 -0
  174. data/spec/adapter/ms_uia/label_spec.rb +18 -0
  175. data/spec/adapter/ms_uia/list_item_spec.rb +14 -0
  176. data/spec/adapter/ms_uia/listbox_spec.rb +73 -0
  177. data/spec/adapter/ms_uia/radio_spec.rb +39 -0
  178. data/spec/adapter/ms_uia/select_list_spec.rb +118 -0
  179. data/spec/adapter/ms_uia/spinner_spec.rb +44 -0
  180. data/spec/adapter/ms_uia/tab_control_spec.rb +53 -0
  181. data/spec/adapter/ms_uia/table_spec.rb +197 -0
  182. data/spec/adapter/ms_uia/text_field_spec.rb +43 -0
  183. data/spec/adapter/ms_uia/value_control_spec.rb +11 -0
  184. data/spec/adapter/ms_uia/window_spec.rb +81 -0
  185. data/spec/adapter/win_32/button_spec.rb +31 -0
  186. data/spec/adapter/win_32/checkbox_spec.rb +46 -0
  187. data/spec/adapter/win_32/label_spec.rb +13 -0
  188. data/spec/adapter/win_32/listbox_spec.rb +41 -0
  189. data/spec/adapter/win_32/mouse_spec.rb +49 -0
  190. data/spec/adapter/win_32/radio_spec.rb +33 -0
  191. data/spec/adapter/win_32/select_list_spec.rb +65 -0
  192. data/spec/adapter/win_32/table_spec.rb +27 -0
  193. data/spec/adapter/win_32/text_field_spec.rb +24 -0
  194. data/spec/adapter/win_32/window_spec.rb +61 -0
  195. data/spec/button_spec.rb +67 -0
  196. data/spec/buttons_spec.rb +21 -0
  197. data/spec/spec_helper.rb +128 -0
  198. data/spec/text_field_spec.rb +64 -0
  199. data/spec/text_fields_spec.rb +22 -0
  200. data/spec/window_spec.rb +150 -0
  201. data/spec/windows_spec.rb +76 -0
  202. metadata +369 -0
@@ -0,0 +1,97 @@
1
+ module RAutomation
2
+ module Adapter
3
+ module Win32
4
+ class SelectList < Control
5
+ include WaitHelper
6
+ include Locators
7
+
8
+ # Default locators used for searching buttons.
9
+ DEFAULT_LOCATORS = {:class => /combobox/i}
10
+
11
+ class SelectListOption
12
+ attr_accessor :text, :index
13
+
14
+ def initialize(select_list, text, index)
15
+ @select_list = select_list
16
+ @text = text
17
+ @index = index
18
+ end
19
+
20
+ def selected?
21
+ selected_idx = Functions.send_message(@select_list.hwnd, Constants::CB_GETCURSEL, 0, nil)
22
+ return false if selected_idx == Constants::CB_ERR
23
+ @text == Functions.retrieve_combobox_item_text(@select_list.hwnd, selected_idx)
24
+ end
25
+
26
+ def select
27
+ @select_list.send :assert_enabled
28
+ Functions.send_message(@select_list.hwnd, Constants::CB_SETCURSEL, @index, nil) != Constants::CB_ERR
29
+ end
30
+
31
+ alias_method :set, :select
32
+ end
33
+
34
+ def options(options = {})
35
+ items = []
36
+
37
+ item_count.times do |item_no|
38
+ item = Functions.retrieve_combobox_item_text(hwnd, item_no)
39
+
40
+ if options[:text]
41
+ items.push(SelectListOption.new(self, item, item_no)) if options[:text] == item
42
+ else
43
+ items.push(SelectListOption.new(self, item, item_no))
44
+ end
45
+ end
46
+
47
+ items
48
+ end
49
+
50
+ def value
51
+ selected_option = options.find { |option| option.selected? }
52
+ selected_option ? selected_option.text : ""
53
+ end
54
+
55
+ def option(options)
56
+ item_count.times do |item_no|
57
+ item = Functions.retrieve_combobox_item_text(hwnd, item_no)
58
+ return SelectListOption.new(self, item, item_no) if options[:text] == item
59
+ end
60
+
61
+ nil
62
+ end
63
+
64
+ def select(index)
65
+ Functions.send_message(hwnd, Constants::CB_SETCURSEL, index, nil) != Constants::CB_ERR
66
+ end
67
+
68
+ def set(text)
69
+ option(:text => text).set
70
+ end
71
+
72
+ def list_item_height
73
+ Functions.send_message(hwnd, Constants::CB_GETITEMHEIGHT, 0 ,nil)
74
+ end
75
+
76
+ def dropbox_boundary
77
+ boundary = FFI::MemoryPointer.new :long, 4
78
+
79
+ Functions.send_message(hwnd, Constants::CB_GETDROPPEDCONTROLRECT, 0 ,boundary)
80
+
81
+ boundary.read_array_of_long(4)
82
+ end
83
+
84
+ def get_top_index
85
+ Functions.send_message(hwnd, Constants::CB_GETTOPINDEX, 0 ,nil)
86
+ end
87
+
88
+ private
89
+
90
+ def item_count
91
+ Functions.send_message(hwnd, Constants::CB_GETCOUNT, 0, nil)
92
+ end
93
+
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,25 @@
1
+ module RAutomation
2
+ module Adapter
3
+ module Win32
4
+ class Table < Control
5
+ include WaitHelper
6
+ include Locators
7
+
8
+ # Default locators used for searching buttons.
9
+ DEFAULT_LOCATORS = {:class => /syslistview/i}
10
+
11
+ def select(row)
12
+ Functions.select_table_row(Window.oleacc_module_handle, Functions.control_hwnd(@window.hwnd, @locators), row)
13
+ end
14
+
15
+ def selected?(row)
16
+ handle = Window.oleacc_module_handle
17
+ control_hwnd = Functions.control_hwnd(@window.hwnd, @locators)
18
+
19
+ state = Functions.get_table_row_state(handle, control_hwnd, row)
20
+ state & Constants::STATE_SYSTEM_SELECTED != 0
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,52 @@
1
+ module RAutomation
2
+ module Adapter
3
+ module Win32
4
+ class TextField < Control
5
+ include WaitHelper
6
+ include Locators
7
+
8
+ # Default locators used for searching text fields.
9
+ DEFAULT_LOCATORS = {:class => /edit/i}
10
+
11
+ # @see RAutomation::TextField#set
12
+ def set(text)
13
+ assert_enabled
14
+
15
+ wait_until do
16
+ hwnd = Functions.control_hwnd(@window.hwnd, @locators)
17
+ @window.activate
18
+ @window.active? &&
19
+ focus &&
20
+ Functions.set_control_text(hwnd, text) &&
21
+ set?(text)
22
+ end
23
+ end
24
+
25
+ # @see RAutomation::TextField#clear
26
+ def clear
27
+ assert_enabled
28
+ set ""
29
+ end
30
+
31
+ # @see RAutomation::Window#send_keys
32
+ def send_keys(*keys)
33
+ @window.container.wait_until_present
34
+ assert_enabled
35
+ @window.activate
36
+ focus
37
+ @window.send_keys(keys)
38
+ end
39
+
40
+ private
41
+
42
+ def set?(text)
43
+ value == text
44
+ end
45
+
46
+ def assert_enabled
47
+ raise "Cannot set value on a disabled text field" if disabled?
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,277 @@
1
+ module RAutomation
2
+ module Adapter
3
+ module Win32
4
+ class Window
5
+ include WaitHelper
6
+ include Locators
7
+ extend ElementCollections
8
+
9
+ has_many :controls
10
+
11
+ class << self
12
+ def oleacc_module_handle
13
+ @oleacc_module_handle ||= begin
14
+ oleacc = Functions.load_library("oleacc.dll")
15
+ Functions.co_initialize nil
16
+ oleacc
17
+ end
18
+ end
19
+ end
20
+
21
+ attr_reader :container
22
+
23
+ # Locators of the window.
24
+ attr_reader :locators
25
+
26
+ # Possible locators are :title, :text, :hwnd, :pid, :class and :index.
27
+
28
+ # Creates the window object.
29
+ # @note this method is not meant to be accessed directly, but only through {RAutomation::Window#initialize}!
30
+ # @param [Hash] locators for searching the window.
31
+ # @option locators [String, Regexp] :title Title of the window
32
+ # @option locators [String, Regexp] :text Visible text of the window
33
+ # @option locators [String, Regexp] :class Internal class name of the window
34
+ # @option locators [String, Integer] :hwnd Window handle in decimal format
35
+ # @option locators [String, Integer] :pid Window process ID (PID)
36
+ # @option locators [String, Integer] :index 0-based index to specify n-th window if all other criteria match
37
+ # all other criteria match
38
+ # @see RAutomation::Window#initialize
39
+ def initialize(container, locators)
40
+ @container = container
41
+ extract(locators)
42
+ end
43
+
44
+ # Retrieves handle of the window.
45
+ # @note Searches only for visible windows.
46
+ # @see RAutomation::Window#hwnd
47
+ def hwnd
48
+ @hwnd ||= Functions.window_hwnd(@locators)
49
+ end
50
+
51
+ # @see RAutomation::Window#pid
52
+ def pid
53
+ Functions.window_pid(hwnd)
54
+ end
55
+
56
+ # @see RAutomation::Window#title
57
+ def title
58
+ Functions.window_title(hwnd)
59
+ end
60
+
61
+ # @see RAutomation::Window#class_names
62
+ def class_names
63
+ classes = []
64
+ controls.each do |control|
65
+ classes << control.class_name
66
+ end
67
+ classes.sort
68
+ end
69
+
70
+ # @see RAutomation::Window#activate
71
+ def activate
72
+ return if !exists? || active?
73
+ restore if minimized?
74
+ Functions.activate_window(hwnd)
75
+ sleep 0.1
76
+ end
77
+
78
+ # @see RAutomation::Window#active?
79
+ def active?
80
+ exists? && Functions.foreground_window == hwnd
81
+ end
82
+
83
+ # @see RAutomation::Window#text
84
+ def text
85
+ Functions.window_text(hwnd)
86
+ end
87
+
88
+ # @see RAutomation::Window#exists?
89
+ def exists?
90
+ result = hwnd && Functions.window_exists(hwnd)
91
+ !!result
92
+ end
93
+
94
+ # @see RAutomation::Window#visible?
95
+ def visible?
96
+ Functions.window_visible(hwnd)
97
+ end
98
+
99
+ # @see RAutomation::Window#maximize
100
+ def maximize
101
+ Functions.show_window(hwnd, Constants::SW_MAXIMIZE)
102
+ sleep 1
103
+ end
104
+
105
+ # @see RAutomation::Window#minimize
106
+ def minimize
107
+ Functions.show_window(hwnd, Constants::SW_MINIMIZE)
108
+ sleep 1
109
+ end
110
+
111
+ # @see RAutomation::Window#minimized?
112
+ def minimized?
113
+ Functions.minimized(hwnd)
114
+ end
115
+
116
+ # @see RAutomation::Window#restore
117
+ def restore
118
+ Functions.show_window(hwnd, Constants::SW_RESTORE)
119
+ sleep 1
120
+ end
121
+
122
+ # Moves/resizes the window.
123
+ # @note All coordinates are optional and if not specified current coordinates will be used
124
+ # @param [Hash] coords for specifying the coordinates.
125
+ # @option coords [Integer] :left Window coordinate from the left side of screen
126
+ # @option coords [Integer] :top Window coordinate from the top of the screen
127
+ # @option coords [Integer] :width Width of window
128
+ # @option coords [Integer] :height Height of window
129
+ def move(coords={})
130
+ @container.wait_until_present
131
+ rect = dimensions.merge(coords)
132
+ Functions.move_window(hwnd, rect[:left], rect[:top], rect[:width], rect[:height])
133
+ sleep 1
134
+ end
135
+
136
+ # @return [Hash] Hash[:left, :top, :width, :height] with window coordinates
137
+ def dimensions
138
+ @container.wait_until_present
139
+ left, top, right, bottom = Functions.window_rect(hwnd)
140
+ {:left => left, :top => top, :width => right - left, :height => bottom - top}
141
+ end
142
+
143
+
144
+ # Activates the window and sends keys to it.
145
+ #
146
+ # @example
147
+ # RAutomation::Window.new(:title => //).send_keys "hello!"
148
+ # RAutomation::Window.new(:title => //).send_keys [:control, "a"], "world!"
149
+ # Refer to {Keys::KEYS} for all the special keycodes.
150
+ # @see RAutomation::Window#send_keys
151
+ def send_keys(args)
152
+ Keys.encode(args).each do |arg|
153
+ wait_until do
154
+ activate
155
+ active?
156
+ end
157
+
158
+ if arg.is_a?(Array)
159
+ arg.reduce([]) do |pressed_keys, k|
160
+ if k == Keys[:null]
161
+ pressed_keys.each {|pressed_key| release_key pressed_key}
162
+ pressed_keys = []
163
+ else
164
+ pressed_keys << press_key(k)
165
+ end
166
+ pressed_keys
167
+ end
168
+ else
169
+ send_key arg
170
+ end
171
+ end
172
+ sleep 1
173
+ end
174
+
175
+ # @see RAutomation::Window#close
176
+ def close
177
+ Functions.close_window(hwnd)
178
+ end
179
+
180
+ # Retrieves the {Mouse} object for automating mouse movements and clicks
181
+ # @raise [UnknownWindowException] if the window doesn't exist.
182
+ def mouse
183
+ @container.wait_until_present
184
+ Mouse.new(self)
185
+ end
186
+
187
+ # @see Button#initialize
188
+ # @see RAutomation::Window#button
189
+ def button(locator)
190
+ Button.new(self, locator)
191
+ end
192
+
193
+ # @see TextField#initialize
194
+ # @see RAutomation::Window#text_field
195
+ def text_field(locator)
196
+ TextField.new(self, locator)
197
+ end
198
+
199
+ # Redirects all method calls not part of the public API to the {Functions} directly.
200
+ # @see RAutomation::Window#method_missing
201
+ def method_missing(name, *args)
202
+ Functions.respond_to?(name) ? Functions.send(name, *args) : super
203
+ end
204
+
205
+ # Win32 adapter specific API methods
206
+ def label(locator={})
207
+ @container.wait_until_present
208
+ Label.new(self, locator)
209
+ end
210
+
211
+ def password_field(locator)
212
+ @container.wait_until_present
213
+ PasswordField.new(self, locator)
214
+ end
215
+
216
+ def control(locator={})
217
+ @container.wait_until_present
218
+ Control.new(self, locator)
219
+ end
220
+
221
+ def list_box(locator={})
222
+ @container.wait_until_present
223
+ ListBox.new(self, locator)
224
+ end
225
+
226
+ def select_list(locator={})
227
+ @container.wait_until_present
228
+ SelectList.new(self, locator)
229
+ end
230
+
231
+ def checkbox(locator={})
232
+ @container.wait_until_present
233
+ Checkbox.new(self, locator)
234
+ end
235
+
236
+ def radio(locator={})
237
+ @container.wait_until_present
238
+ Radio.new(self, locator)
239
+ end
240
+
241
+ def table(locator={})
242
+ @container.wait_until_present
243
+ Table.new(self, locator)
244
+ end
245
+
246
+ # Creates the child window object.
247
+ # @note This is an Win32 adapter specific method, not part of the public API
248
+ # @example
249
+ # RAutomation::Window.new(:title => /Windows Internet Explorer/i).
250
+ # child(:title => /some popup/)
251
+ # @param (see Window#initialize)
252
+ # @return [RAutomation::Window] child window, popup or regular window.
253
+ def child(locators)
254
+ RAutomation::Window.new Functions.child_window_locators(hwnd, locators)
255
+ end
256
+
257
+ private
258
+
259
+ def press_key key
260
+ Functions.send_key(key, 0, 0, nil)
261
+ key
262
+ end
263
+
264
+ def release_key key
265
+ Functions.send_key(key, 0, Constants::KEYEVENTF_KEYUP, nil)
266
+ key
267
+ end
268
+
269
+ def send_key key
270
+ press_key key
271
+ release_key key
272
+ key
273
+ end
274
+ end
275
+ end
276
+ end
277
+ end
@@ -0,0 +1,23 @@
1
+ begin
2
+ gem "ffi"
3
+ rescue Gem::LoadError
4
+ raise Gem::LoadError, "Unable to load FFI gem. Install it with:\n\tgem install ffi"
5
+ end
6
+ require "ffi"
7
+ require File.dirname(__FILE__) + "/win_32/constants"
8
+ require File.dirname(__FILE__) + "/win_32/keys"
9
+ require File.dirname(__FILE__) + "/win_32/functions"
10
+ require File.dirname(__FILE__) + "/win_32/locators"
11
+ require File.dirname(__FILE__) + "/win_32/window"
12
+ require File.dirname(__FILE__) + "/win_32/button_helper"
13
+ require File.dirname(__FILE__) + "/win_32/control"
14
+ require File.dirname(__FILE__) + "/win_32/button"
15
+ require File.dirname(__FILE__) + "/win_32/checkbox"
16
+ require File.dirname(__FILE__) + "/win_32/radio"
17
+ require File.dirname(__FILE__) + "/win_32/text_field"
18
+ require File.dirname(__FILE__) + "/win_32/select_list"
19
+ require File.dirname(__FILE__) + "/win_32/table"
20
+ require File.dirname(__FILE__) + "/win_32/label"
21
+ require File.dirname(__FILE__) + "/win_32/list_box"
22
+ require File.dirname(__FILE__) + "/win_32/mouse"
23
+ require File.dirname(__FILE__) + "/win_32/password_field"
@@ -0,0 +1,55 @@
1
+ module RAutomation
2
+ class Button
3
+ # @private
4
+ # This constructor is meant to be accessed only through {Window#button} method.
5
+ def initialize(window, locators)
6
+ @window = window
7
+ @locators = locators
8
+ @button = @window.button(@locators)
9
+ end
10
+
11
+ # Performs a click on the button.
12
+ # By default click is considered successful if the button doesn't exist after clicking (e.g. window has closed)
13
+ # @yield [button] optional block specifying successful clicking condition.
14
+ # @yieldparam [Button] button which is being clicked on.
15
+ # @yieldreturn [Boolean] true if clicking on the button is successful, false otherwise.
16
+ # @raise [UnknownButtonException] if the button doesn't exist.
17
+ def click
18
+ wait_until_exists
19
+ if block_given?
20
+ @button.click {yield self}
21
+ else
22
+ @button.click
23
+ end
24
+ end
25
+
26
+ # Retrieves the value (text) of the button, usually the visible text.
27
+ # @return [String] the value (text) of the button.
28
+ # @raise [UnknownButtonException] if the button doesn't exist.
29
+ def value
30
+ wait_until_exists
31
+ @button.value
32
+ end
33
+
34
+ # Checks if the button exists.
35
+ # @return [Boolean] true if button exists, false otherwise.
36
+ def exists?
37
+ @button.exists?
38
+ end
39
+
40
+ alias_method :exist?, :exists?
41
+
42
+ # Allows to execute specific {Adapter} methods not part of the public API.
43
+ def method_missing(name, *args)
44
+ @button.send(name, *args)
45
+ end
46
+
47
+ private
48
+
49
+ def wait_until_exists
50
+ WaitHelper.wait_until {exists?}
51
+ rescue WaitHelper::TimeoutError
52
+ raise UnknownButtonException, "Button #{@locators.inspect} doesn't exist on window #{@window.locators.inspect}!"
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,55 @@
1
+ module RAutomation
2
+ # @private
3
+ module ElementCollections
4
+ class UnsupportedLocatorException < RuntimeError
5
+ end
6
+
7
+ # Creates collection classes and methods for elements.
8
+ # @param [Array<Symbol>] elements for which to create collection classes
9
+ # and methods.
10
+ def has_many(*elements)
11
+ elements.each do |element|
12
+ class_name_plural = element.to_s.split("_").map {|e| e.capitalize}.join
13
+ class_name = class_name_plural.chop
14
+ adapter_class = self.to_s.scan(/(.*)::/).flatten.first
15
+ clazz = RAutomation.constants.include?(class_name) ? RAutomation : class_eval(adapter_class)
16
+ clazz.class_eval %Q{
17
+ class #{class_name_plural}
18
+ include Enumerable
19
+
20
+ def initialize(window, locators)
21
+ if locators[:hwnd] || locators[:pid]
22
+ raise UnsupportedLocatorException,
23
+ ":hwnd or :pid in " + locators.inspect + " are not supported for #{adapter_class}::#{class_name_plural}"
24
+ end
25
+
26
+ @window = window
27
+ @locators = locators
28
+ end
29
+
30
+ def each
31
+ i = -1
32
+ while true
33
+ args = [@window, @locators.merge(:index => i += 1)].compact
34
+ object = #{clazz}::#{class_name}.new(*args)
35
+ break unless object.exists?
36
+ yield object
37
+ end
38
+ end
39
+
40
+ def method_missing(name, *args)
41
+ ary = self.to_a
42
+ ary.respond_to?(name) ? ary.send(name, *args) : super
43
+ end
44
+ end
45
+ }
46
+
47
+ class_eval %Q{
48
+ def #{element}(locators = {})
49
+ #{adapter_class}::#{class_name_plural}.new(@window || self, locators)
50
+ end
51
+ }
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,15 @@
1
+ module Platform
2
+ extend self
3
+
4
+ def architecture
5
+ if is_x86?
6
+ 'x86'
7
+ else
8
+ 'x64'
9
+ end
10
+ end
11
+
12
+ def is_x86?
13
+ %w[x86 i386].any? { |p| RUBY_PLATFORM =~ /#{p}/i }
14
+ end
15
+ end
@@ -0,0 +1,60 @@
1
+ module RAutomation
2
+ class TextField
3
+ # @private
4
+ # This constructor is meant to be accessed only through {Window#text_field} method.
5
+ def initialize(window, locators) #:nodoc:
6
+ @window = window
7
+ @locators = locators
8
+ @text_field = @window.text_field(@locators)
9
+ end
10
+
11
+ # Sets text of the text field.
12
+ # @param [String] text of the field to set.
13
+ # @raise [UnknownTextFieldException] if the text field doesn't exist.
14
+ def set(text)
15
+ wait_until_exists
16
+ @text_field.set(text)
17
+ end
18
+
19
+ # Clears text field's text.
20
+ # @raise [UnknownTextFieldException] if the text field doesn't exist.
21
+ def clear
22
+ wait_until_exists
23
+ @text_field.clear
24
+ end
25
+
26
+ # Returns text field's current value (text).
27
+ # @return [String] the value (text) of the text field.
28
+ # @raise [UnknownTextFieldException] if the text field doesn't exist.
29
+ def value
30
+ wait_until_exists
31
+ @text_field.value
32
+ end
33
+
34
+ # Checks if the text field exists.
35
+ # @return [Boolean] true if text field exists, false otherwise.
36
+ def exists?
37
+ @text_field.exists?
38
+ end
39
+
40
+ def hwnd
41
+ wait_until_exists
42
+ @text_field.hwnd
43
+ end
44
+
45
+ alias_method :exist?, :exists?
46
+
47
+ # Allows to execute specific {Adapter} methods not part of the public API.
48
+ def method_missing(name, *args)
49
+ @text_field.send(name, *args)
50
+ end
51
+
52
+ private
53
+
54
+ def wait_until_exists
55
+ WaitHelper.wait_until {exists?}
56
+ rescue WaitHelper::TimeoutError
57
+ raise UnknownTextFieldException, "Text field #{@locators.inspect} doesn't exist on window #{@window.locators.inspect}!" unless exists?
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,3 @@
1
+ module RAutomation
2
+ VERSION = "2.0.1"
3
+ end
@@ -0,0 +1,23 @@
1
+ module RAutomation
2
+ # Waiting with timeout
3
+ module WaitHelper
4
+ extend self
5
+
6
+ class TimeoutError < StandardError
7
+ end
8
+
9
+ # @private
10
+ # Wait until the block evaluates to true or times out.
11
+ def wait_until(timeout = Window.wait_timeout, &block)
12
+ end_time = ::Time.now + timeout
13
+
14
+ until ::Time.now > end_time
15
+ result = yield(self)
16
+ return result if result
17
+ sleep 0.5
18
+ end
19
+
20
+ raise TimeoutError, "timed out after #{timeout} seconds"
21
+ end
22
+ end
23
+ end