rautomation 2.0.1-x86-mingw32

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 (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