rautomation 0.6.3 → 0.7.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.
- data/.gitignore +34 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +24 -0
- data/History.rdoc +21 -0
- data/LICENSE +1 -1
- data/README.rdoc +8 -7
- data/Rakefile +22 -32
- data/VERSION +1 -1
- data/ext/UiaDll/Release/UiaDll.dll +0 -0
- data/ext/UiaDll/UiaDll.suo +0 -0
- data/ext/UiaDll/UiaDll/UiaDll.cpp +236 -10
- data/lib/rautomation/adapter/autoit/locators.rb +1 -1
- data/lib/rautomation/adapter/autoit/text_field.rb +10 -1
- data/lib/rautomation/adapter/autoit/window.rb +50 -23
- data/lib/rautomation/adapter/helper.rb +6 -6
- data/lib/rautomation/adapter/ms_uia.rb +22 -0
- data/lib/rautomation/adapter/{win_ffi → ms_uia}/button.rb +3 -2
- data/lib/rautomation/adapter/ms_uia/button_helper.rb +25 -0
- data/lib/rautomation/adapter/ms_uia/checkbox.rb +27 -0
- data/lib/rautomation/adapter/{win_ffi → ms_uia}/constants.rb +20 -5
- data/lib/rautomation/adapter/ms_uia/control.rb +180 -0
- data/lib/rautomation/adapter/{win_ffi → ms_uia}/functions.rb +24 -26
- data/lib/rautomation/adapter/ms_uia/keystroke_converter.rb +122 -0
- data/lib/rautomation/adapter/{win_ffi → ms_uia}/label.rb +3 -2
- data/lib/rautomation/adapter/ms_uia/list_box.rb +91 -0
- data/lib/rautomation/adapter/ms_uia/list_item.rb +49 -0
- data/lib/rautomation/adapter/ms_uia/locators.rb +23 -0
- data/lib/rautomation/adapter/{win_ffi → ms_uia}/radio.rb +2 -2
- data/lib/rautomation/adapter/{win_ffi → ms_uia}/select_list.rb +41 -7
- data/lib/rautomation/adapter/ms_uia/table.rb +86 -0
- data/lib/rautomation/adapter/{win_ffi → ms_uia}/text_field.rb +5 -4
- data/lib/rautomation/adapter/ms_uia/uia_dll.rb +62 -0
- data/lib/rautomation/adapter/ms_uia/window.rb +364 -0
- data/lib/rautomation/adapter/win_32.rb +21 -0
- data/lib/rautomation/adapter/win_32/button.rb +14 -0
- data/lib/rautomation/adapter/{win_ffi → win_32}/button_helper.rb +1 -1
- data/lib/rautomation/adapter/win_32/checkbox.rb +14 -0
- data/lib/rautomation/adapter/win_32/constants.rb +68 -0
- data/lib/rautomation/adapter/{win_ffi → win_32}/control.rb +30 -23
- data/lib/rautomation/adapter/win_32/functions.rb +313 -0
- data/lib/rautomation/adapter/win_32/keys.rb +121 -0
- data/lib/rautomation/adapter/win_32/label.rb +10 -0
- data/lib/rautomation/adapter/win_32/list_box.rb +40 -0
- data/lib/rautomation/adapter/{win_ffi → win_32}/locators.rb +2 -2
- data/lib/rautomation/adapter/win_32/radio.rb +11 -0
- data/lib/rautomation/adapter/win_32/select_list.rb +97 -0
- data/lib/rautomation/adapter/win_32/table.rb +22 -0
- data/lib/rautomation/adapter/win_32/text_field.rb +42 -0
- data/lib/rautomation/adapter/{win_ffi → win_32}/window.rb +79 -62
- data/lib/rautomation/element_collections.rb +9 -1
- data/lib/rautomation/window.rb +17 -9
- data/rautomation.gemspec +24 -0
- data/spec/adapter/autoit/window_spec.rb +71 -0
- data/spec/adapter/{win_ffi → ms_uia}/button_spec.rb +1 -1
- data/spec/adapter/{win_ffi → ms_uia}/checkbox_spec.rb +9 -3
- data/spec/adapter/ms_uia/control_spec.rb +28 -0
- data/spec/adapter/ms_uia/keystroke_converter_spec.rb +50 -0
- data/spec/adapter/{win_ffi → ms_uia}/label_spec.rb +2 -2
- data/spec/adapter/ms_uia/list_item_spec.rb +14 -0
- data/spec/adapter/{win_ffi → ms_uia}/listbox_spec.rb +18 -5
- data/spec/adapter/{win_ffi → ms_uia}/radio_spec.rb +3 -1
- data/spec/adapter/ms_uia/select_list_spec.rb +109 -0
- data/spec/adapter/{win_ffi → ms_uia}/table_spec.rb +12 -1
- data/spec/adapter/{win_ffi → ms_uia}/text_field_spec.rb +2 -1
- data/spec/adapter/ms_uia/window_spec.rb +89 -0
- data/spec/adapter/win_32/button_spec.rb +30 -0
- data/spec/adapter/win_32/checkbox_spec.rb +48 -0
- data/spec/adapter/win_32/label_spec.rb +15 -0
- data/spec/adapter/win_32/listbox_spec.rb +42 -0
- data/spec/adapter/win_32/radio_spec.rb +32 -0
- data/spec/adapter/{win_ffi → win_32}/select_list_spec.rb +16 -16
- data/spec/adapter/win_32/table_spec.rb +28 -0
- data/spec/adapter/win_32/text_field_spec.rb +24 -0
- data/spec/adapter/{win_ffi → win_32}/window_spec.rb +19 -14
- data/spec/button_spec.rb +1 -0
- data/spec/buttons_spec.rb +4 -4
- data/spec/spec_helper.rb +30 -4
- data/spec/text_field_spec.rb +6 -7
- data/spec/window_spec.rb +12 -0
- data/spec/windows_spec.rb +19 -0
- metadata +116 -97
- data/lib/rautomation/adapter/win_ffi.rb +0 -21
- data/lib/rautomation/adapter/win_ffi/checkbox.rb +0 -19
- data/lib/rautomation/adapter/win_ffi/keystroke_converter.rb +0 -67
- data/lib/rautomation/adapter/win_ffi/list_box.rb +0 -60
- data/lib/rautomation/adapter/win_ffi/ms_uia/uia_dll.rb +0 -36
- data/lib/rautomation/adapter/win_ffi/table.rb +0 -57
- data/spec/adapter/win_ffi/keystroke_converter_spec.rb +0 -47
@@ -0,0 +1,86 @@
|
|
1
|
+
module RAutomation
|
2
|
+
module Adapter
|
3
|
+
module MsUia
|
4
|
+
class Table < Control
|
5
|
+
include WaitHelper
|
6
|
+
include Locators
|
7
|
+
|
8
|
+
def strings
|
9
|
+
rows = []
|
10
|
+
header_columns = []
|
11
|
+
|
12
|
+
raise "Not a list control" unless UiaDll::current_control_type(uia_element) == Constants::UIA_LIST_CONTROL_TYPE
|
13
|
+
|
14
|
+
|
15
|
+
children_count = count_children(uia_element)
|
16
|
+
|
17
|
+
children = FFI::MemoryPointer.new :pointer, children_count
|
18
|
+
UiaDll::find_children(uia_element, children)
|
19
|
+
|
20
|
+
|
21
|
+
children.read_array_of_pointer(children_count).each do |child|
|
22
|
+
grandchildren_count = count_children(child)
|
23
|
+
|
24
|
+
if grandchildren_count > 0
|
25
|
+
|
26
|
+
grandchildren = FFI::MemoryPointer.new :pointer, grandchildren_count
|
27
|
+
UiaDll::find_children(child, grandchildren)
|
28
|
+
|
29
|
+
grandchildren.read_array_of_pointer(grandchildren_count).each do |grandchild|
|
30
|
+
grandchild_name = FFI::MemoryPointer.new :char, UiaDll::get_name(grandchild, nil) + 1
|
31
|
+
UiaDll::get_name(grandchild, grandchild_name)
|
32
|
+
header_columns.push grandchild_name.read_string
|
33
|
+
end
|
34
|
+
else
|
35
|
+
grandchild_name = FFI::MemoryPointer.new :char, UiaDll::get_name(child, nil) + 1
|
36
|
+
UiaDll::get_name(child, grandchild_name)
|
37
|
+
header_columns = grandchild_name.read_string
|
38
|
+
end
|
39
|
+
|
40
|
+
rows.push header_columns
|
41
|
+
header_columns = []
|
42
|
+
end
|
43
|
+
|
44
|
+
rows
|
45
|
+
end
|
46
|
+
|
47
|
+
# def select(row)
|
48
|
+
# Functions.select_table_row(Window.oleacc_module_handle, Functions.control_hwnd(@window.hwnd, @locators), row)
|
49
|
+
# end
|
50
|
+
|
51
|
+
def select(index)
|
52
|
+
children = FFI::MemoryPointer.new :pointer, row_count
|
53
|
+
|
54
|
+
length = UiaDll::find_children(uia_element, children)
|
55
|
+
|
56
|
+
target_element = children.read_array_of_pointer(length)[index]
|
57
|
+
|
58
|
+
UiaDll::select(target_element)
|
59
|
+
end
|
60
|
+
|
61
|
+
#todo - replace with UIA version
|
62
|
+
def selected?(row)
|
63
|
+
state = Functions.get_table_row_state(Window.oleacc_module_handle, Functions.control_hwnd(@window.hwnd, @locators), row)
|
64
|
+
state & Constants::STATE_SYSTEM_SELECTED != 0
|
65
|
+
end
|
66
|
+
|
67
|
+
def row_count
|
68
|
+
UiaDll::find_children(uia_element, nil)
|
69
|
+
end
|
70
|
+
|
71
|
+
def exist?
|
72
|
+
super && matches_type?(Constants::UIA_LIST_CONTROL_TYPE)
|
73
|
+
end
|
74
|
+
|
75
|
+
alias_method :exists?, :exist?
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def count_children(element)
|
80
|
+
UiaDll::find_children(element, nil)
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module RAutomation
|
2
2
|
module Adapter
|
3
|
-
module
|
3
|
+
module MsUia
|
4
4
|
class TextField < Control
|
5
5
|
include WaitHelper
|
6
6
|
include Locators
|
@@ -8,6 +8,7 @@ module RAutomation
|
|
8
8
|
# Default locators used for searching text fields.
|
9
9
|
DEFAULT_LOCATORS = {:class => /edit/i}
|
10
10
|
|
11
|
+
#todo - replace with UIA version
|
11
12
|
# @see RAutomation::TextField#set
|
12
13
|
def set(text)
|
13
14
|
raise "Cannot set value on a disabled text field" if disabled?
|
@@ -28,24 +29,24 @@ module RAutomation
|
|
28
29
|
set ""
|
29
30
|
end
|
30
31
|
|
32
|
+
#todo - replace with UIA version
|
31
33
|
# @see RAutomation::TextField#value
|
32
34
|
def value
|
33
35
|
Functions.control_value(hwnd)
|
34
36
|
end
|
35
37
|
|
38
|
+
#todo - replace with UIA version
|
36
39
|
# @see RAutomation::TextField#hwnd
|
37
40
|
def hwnd
|
38
41
|
Functions.control_hwnd(@window.hwnd, @locators)
|
39
42
|
end
|
40
43
|
|
41
44
|
def exist?
|
42
|
-
|
45
|
+
super && matches_type?(Constants::UIA_EDIT_CONTROL_TYPE)
|
43
46
|
end
|
44
47
|
|
45
48
|
alias_method :exists?, :exist?
|
46
49
|
|
47
|
-
|
48
|
-
|
49
50
|
end
|
50
51
|
end
|
51
52
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
#todo - move this file up to the same level as the others
|
2
|
+
#todo - organize the methods better
|
3
|
+
|
4
|
+
module RAutomation
|
5
|
+
module Adapter
|
6
|
+
module MsUia
|
7
|
+
module UiaDll
|
8
|
+
extend FFI::Library
|
9
|
+
|
10
|
+
ffi_lib File.dirname(__FILE__) + '/../../../../ext/UiaDll/Release/UiaDll.dll'
|
11
|
+
ffi_convention :stdcall
|
12
|
+
|
13
|
+
attach_function :find_window, :RA_FindWindow,
|
14
|
+
[:string], :pointer
|
15
|
+
attach_function :is_offscreen, :RA_IsOffscreen,
|
16
|
+
[:pointer], :bool
|
17
|
+
attach_function :element_from_handle, :RA_ElementFromHandle,
|
18
|
+
[:long], :pointer
|
19
|
+
attach_function :element_from_point, :RA_ElementFromPoint,
|
20
|
+
[:int, :int], :pointer
|
21
|
+
attach_function :get_focused_element, :RA_GetFocusedElement,
|
22
|
+
[], :pointer
|
23
|
+
attach_function :find_child_by_id, :RA_FindChildById,
|
24
|
+
[:pointer, :string], :pointer
|
25
|
+
attach_function :find_child_by_name, :RA_FindChildByName,
|
26
|
+
[:pointer, :string], :pointer
|
27
|
+
attach_function :current_native_window_handle, :RA_CurrentNativeWindowHandle,
|
28
|
+
[:pointer], :long
|
29
|
+
attach_function :set_focus, :RA_SetFocus,
|
30
|
+
[:pointer], :bool
|
31
|
+
attach_function :current_control_type, :RA_GetCurrentControlType,
|
32
|
+
[:pointer], :int
|
33
|
+
attach_function :desktop_handle, :RA_GetDesktopHandle,
|
34
|
+
[], :long
|
35
|
+
attach_function :move_mouse, :RA_MoveMouse,
|
36
|
+
[:int,:int], :long
|
37
|
+
attach_function :click_mouse, :RA_ClickMouse,
|
38
|
+
[], :long
|
39
|
+
attach_function :bounding_rectangle, :RA_CurrentBoundingRectangle,
|
40
|
+
[:pointer, :pointer], :int
|
41
|
+
attach_function :is_offscreen, :RA_CurrentIsOffscreen,
|
42
|
+
[:pointer, :pointer], :int
|
43
|
+
attach_function :find_children, :RA_FindChildren,
|
44
|
+
[:pointer, :pointer], :int
|
45
|
+
attach_function :get_name, :RA_GetName,
|
46
|
+
[:pointer, :pointer], :int
|
47
|
+
attach_function :get_class_name, :RA_GetClassName,
|
48
|
+
[:pointer, :pointer], :int
|
49
|
+
attach_function :get_is_selected, :RA_GetIsSelected,
|
50
|
+
[:pointer], :bool
|
51
|
+
attach_function :select, :RA_Select,
|
52
|
+
[:pointer], :int
|
53
|
+
attach_function :set_value, :RA_Set_Value,
|
54
|
+
[:pointer, :pointer], :int
|
55
|
+
attach_function :find_window_by_pid, :RA_FindWindowByPID,
|
56
|
+
[:int], :pointer
|
57
|
+
attach_function :current_process_id, :RA_GetCurrentProcessId,
|
58
|
+
[:pointer], :int
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,364 @@
|
|
1
|
+
module RAutomation
|
2
|
+
module Adapter
|
3
|
+
module MsUia
|
4
|
+
autoload :UiaDll, File.dirname(__FILE__) + "/uia_dll"
|
5
|
+
|
6
|
+
class Window
|
7
|
+
include WaitHelper
|
8
|
+
include Locators
|
9
|
+
extend ElementCollections
|
10
|
+
|
11
|
+
has_many :controls
|
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
|
+
# Locators of the window.
|
25
|
+
attr_reader :locators
|
26
|
+
|
27
|
+
# Possible locators are :title, :text, :hwnd, :pid, :class and :index.
|
28
|
+
#todo - update list of valid locators for UIA
|
29
|
+
# Creates the window object.
|
30
|
+
# @note this method is not meant to be accessed directly, but only through {RAutomation::Window#initialize}!
|
31
|
+
# @param [Hash] locators for searching the window.
|
32
|
+
# @option locators [String, Regexp] :title Title of the window
|
33
|
+
# @option locators [String, Regexp] :text Visible text of the window
|
34
|
+
# @option locators [String, Regexp] :class Internal class name of the window
|
35
|
+
# @option locators [String, Fixnum] :hwnd Window handle in decimal format
|
36
|
+
# @option locators [String, Fixnum] :pid Window process ID (PID)
|
37
|
+
# @option locators [String, Fixnum] :index 0-based index to specify n-th window if all other criteria match
|
38
|
+
# all other criteria match
|
39
|
+
# @see RAutomation::Window#initialize
|
40
|
+
def initialize(container, locators)
|
41
|
+
@container = container
|
42
|
+
extract(locators)
|
43
|
+
end
|
44
|
+
|
45
|
+
#todo - replace with UIA version
|
46
|
+
# Retrieves handle of the window.
|
47
|
+
# @note Searches only for visible windows.
|
48
|
+
# @see RAutomation::Window#hwnd
|
49
|
+
def hwnd
|
50
|
+
@hwnd ||= Functions.window_hwnd(@locators)
|
51
|
+
end
|
52
|
+
|
53
|
+
#todo - replace with UIA version
|
54
|
+
# @see RAutomation::Window#pid
|
55
|
+
def pid
|
56
|
+
Functions.window_pid(hwnd)
|
57
|
+
end
|
58
|
+
|
59
|
+
#todo - replace with UIA version
|
60
|
+
# @see RAutomation::Window#title
|
61
|
+
def title
|
62
|
+
Functions.window_title(hwnd)
|
63
|
+
end
|
64
|
+
|
65
|
+
# @see RAutomation::Window#class_names
|
66
|
+
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
|
76
|
+
end
|
77
|
+
|
78
|
+
# @see RAutomation::Window#activate
|
79
|
+
def activate
|
80
|
+
return if !exists? || active?
|
81
|
+
restore if minimized?
|
82
|
+
Functions.activate_window(hwnd)
|
83
|
+
restore if minimized?
|
84
|
+
sleep 1
|
85
|
+
end
|
86
|
+
|
87
|
+
#todo - replace with UIA version
|
88
|
+
# @see RAutomation::Window#active?
|
89
|
+
def active?
|
90
|
+
exists? && Functions.foreground_window == hwnd
|
91
|
+
end
|
92
|
+
|
93
|
+
#todo - replace with UIA version
|
94
|
+
# @see RAutomation::Window#text
|
95
|
+
def text
|
96
|
+
Functions.window_text(hwnd)
|
97
|
+
end
|
98
|
+
|
99
|
+
#todo - replace with UIA version
|
100
|
+
# @see RAutomation::Window#exists?
|
101
|
+
def exists?
|
102
|
+
hwnd && Functions.window_exists(hwnd)
|
103
|
+
end
|
104
|
+
|
105
|
+
#todo - replace with UIA version
|
106
|
+
# @see RAutomation::Window#visible?
|
107
|
+
def visible?
|
108
|
+
Functions.window_visible(hwnd)
|
109
|
+
end
|
110
|
+
|
111
|
+
#todo - replace with UIA version
|
112
|
+
# @see RAutomation::Window#maximize
|
113
|
+
def maximize
|
114
|
+
Functions.show_window(hwnd, Constants::SW_MAXIMIZE)
|
115
|
+
sleep 1
|
116
|
+
end
|
117
|
+
|
118
|
+
#todo - replace with UIA version
|
119
|
+
# @see RAutomation::Window#minimize
|
120
|
+
def minimize
|
121
|
+
Functions.show_window(hwnd, Constants::SW_MINIMIZE)
|
122
|
+
sleep 1
|
123
|
+
end
|
124
|
+
|
125
|
+
#todo - replace with UIA version
|
126
|
+
# @see RAutomation::Window#minimized?
|
127
|
+
def minimized?
|
128
|
+
Functions.minimized(hwnd)
|
129
|
+
end
|
130
|
+
|
131
|
+
#todo - replace with UIA version
|
132
|
+
# @see RAutomation::Window#restore
|
133
|
+
def restore
|
134
|
+
Functions.show_window(hwnd, Constants::SW_RESTORE)
|
135
|
+
sleep 1
|
136
|
+
end
|
137
|
+
|
138
|
+
#todo - replace with UIA version if possible
|
139
|
+
# Activates the window and sends keys to it.
|
140
|
+
#
|
141
|
+
# Refer to KeystrokeConverter#convert_special_characters for the special keycodes.
|
142
|
+
# @see RAutomation::Window#send_keys
|
143
|
+
def send_keys(keys)
|
144
|
+
shift_pressed = false
|
145
|
+
KeystrokeConverter.convert(keys[0]).each do |key|
|
146
|
+
wait_until do
|
147
|
+
activate
|
148
|
+
active?
|
149
|
+
end
|
150
|
+
press_key key
|
151
|
+
|
152
|
+
if key == Constants::VK_LSHIFT
|
153
|
+
shift_pressed = true
|
154
|
+
next
|
155
|
+
end
|
156
|
+
|
157
|
+
release_key key
|
158
|
+
|
159
|
+
if shift_pressed
|
160
|
+
shift_pressed = false
|
161
|
+
release_key Constants::VK_LSHIFT
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
#todo - replace with UIA version
|
167
|
+
# @see RAutomation::Window#close
|
168
|
+
def close
|
169
|
+
Functions.close_window(hwnd)
|
170
|
+
end
|
171
|
+
|
172
|
+
# @see Button#initialize
|
173
|
+
# @see RAutomation::Window#button
|
174
|
+
def button(locator)
|
175
|
+
Button.new(self, locator)
|
176
|
+
end
|
177
|
+
|
178
|
+
# @see TextField#initialize
|
179
|
+
# @see RAutomation::Window#text_field
|
180
|
+
def text_field(locator)
|
181
|
+
TextField.new(self, locator)
|
182
|
+
end
|
183
|
+
|
184
|
+
# Redirects all method calls not part of the public API to the {Functions} directly.
|
185
|
+
# @see RAutomation::Window#method_missing
|
186
|
+
def method_missing(name, *args)
|
187
|
+
Functions.respond_to?(name) ? Functions.send(name, *args) : super
|
188
|
+
end
|
189
|
+
|
190
|
+
# MsUia adapter specific API methods
|
191
|
+
def element
|
192
|
+
case
|
193
|
+
when @locators[:focus]
|
194
|
+
uia_control = UiaDll::get_focused_element
|
195
|
+
when @locators[:id]
|
196
|
+
uia_control = UiaDll::find_window(@locators[:id].to_s)
|
197
|
+
raise UnknownElementException, "#{@locators[:id]} does not exist" if uia_control.nil?
|
198
|
+
when @locators[:point]
|
199
|
+
uia_control = UiaDll::element_from_point(@locators[:point][0], @locators[:point][1])
|
200
|
+
raise UnknownElementException, "#{@locators[:point]} does not exist" if uia_control.nil?
|
201
|
+
else
|
202
|
+
hwnd = find_hwnd(locators, window_hwnd) do |hwnd|
|
203
|
+
locators_match?(locators, control_properties(hwnd, locators))
|
204
|
+
end
|
205
|
+
raise UnknownElementException, "Element with #{locators.inspect} does not exist" if (hwnd == 0) or (hwnd == nil)
|
206
|
+
uia_control = UiaDll::element_from_handle(hwnd)
|
207
|
+
end
|
208
|
+
uia_control
|
209
|
+
end
|
210
|
+
|
211
|
+
def new_pid
|
212
|
+
UiaDll::current_process_id(uia_control())
|
213
|
+
end
|
214
|
+
|
215
|
+
def display_tree
|
216
|
+
root_element = UiaDll::element_from_handle(hwnd)
|
217
|
+
|
218
|
+
root_name = FFI::MemoryPointer.new :char, UiaDll::get_name(root_element, nil) + 1
|
219
|
+
UiaDll::get_name(root_element, root_name)
|
220
|
+
|
221
|
+
[root_name.read_string.inspect, gather_children(root_element)]
|
222
|
+
end
|
223
|
+
|
224
|
+
def gather_children(root_element)
|
225
|
+
element_tree = []
|
226
|
+
|
227
|
+
child_count = count_children(root_element)
|
228
|
+
children = FFI::MemoryPointer.new :pointer, child_count
|
229
|
+
UiaDll::find_children(root_element, children)
|
230
|
+
|
231
|
+
children.read_array_of_pointer(child_count).each do |child|
|
232
|
+
child_name = FFI::MemoryPointer.new :char, UiaDll::get_name(child, nil) + 1
|
233
|
+
UiaDll::get_name(child, child_name)
|
234
|
+
|
235
|
+
grandchild_count = count_children(child)
|
236
|
+
|
237
|
+
if grandchild_count > 0
|
238
|
+
element_tree << [child_name.read_string, gather_children(child)]
|
239
|
+
else
|
240
|
+
element_tree << child_name.read_string
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
element_tree
|
245
|
+
end
|
246
|
+
|
247
|
+
def count_children(element)
|
248
|
+
UiaDll::find_children(element, nil)
|
249
|
+
end
|
250
|
+
|
251
|
+
def gather_children_classes(root_element)
|
252
|
+
element_tree = []
|
253
|
+
|
254
|
+
child_count = count_children(root_element)
|
255
|
+
children = FFI::MemoryPointer.new :pointer, child_count
|
256
|
+
UiaDll::find_children(root_element, children)
|
257
|
+
|
258
|
+
children.read_array_of_pointer(child_count).each do |child|
|
259
|
+
child_name = FFI::MemoryPointer.new :char, UiaDll::get_class_name(child, nil) + 1
|
260
|
+
UiaDll::get_class_name(child, child_name)
|
261
|
+
|
262
|
+
grandchild_count = count_children(child)
|
263
|
+
|
264
|
+
if grandchild_count > 0
|
265
|
+
element_tree << [child_name.read_string, gather_children_classes(child)]
|
266
|
+
else
|
267
|
+
element_tree << child_name.read_string
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
element_tree
|
272
|
+
end
|
273
|
+
|
274
|
+
def get_focused_element
|
275
|
+
UiaDll::get_focused_element()
|
276
|
+
end
|
277
|
+
|
278
|
+
def bounding_rectangle
|
279
|
+
window = UiaDll::element_from_handle(hwnd)
|
280
|
+
|
281
|
+
boundary = FFI::MemoryPointer.new :long, 4
|
282
|
+
UiaDll::bounding_rectangle(window, boundary)
|
283
|
+
|
284
|
+
boundary.read_array_of_long(4)
|
285
|
+
end
|
286
|
+
|
287
|
+
def move_mouse(x, y)
|
288
|
+
UiaDll::move_mouse(x, y)
|
289
|
+
end
|
290
|
+
|
291
|
+
def click_mouse()
|
292
|
+
UiaDll::click_mouse
|
293
|
+
end
|
294
|
+
|
295
|
+
def label(locator)
|
296
|
+
@container.wait_until_present
|
297
|
+
Label.new(self, locator)
|
298
|
+
end
|
299
|
+
|
300
|
+
def control(locator)
|
301
|
+
@container.wait_until_present
|
302
|
+
Control.new(self, locator)
|
303
|
+
end
|
304
|
+
|
305
|
+
def controls(locator)
|
306
|
+
@container.wait_until_present
|
307
|
+
Controls.new(self, locator)
|
308
|
+
end
|
309
|
+
|
310
|
+
def list_box(locator)
|
311
|
+
@container.wait_until_present
|
312
|
+
ListBox.new(self, locator)
|
313
|
+
end
|
314
|
+
|
315
|
+
def list_item(locator)
|
316
|
+
@container.wait_until_present
|
317
|
+
ListItem.new(self, locator)
|
318
|
+
end
|
319
|
+
|
320
|
+
def select_list(locator)
|
321
|
+
@container.wait_until_present
|
322
|
+
SelectList.new(self, locator)
|
323
|
+
end
|
324
|
+
|
325
|
+
def checkbox(locator)
|
326
|
+
@container.wait_until_present
|
327
|
+
Checkbox.new(self, locator)
|
328
|
+
end
|
329
|
+
|
330
|
+
def radio(locator)
|
331
|
+
@container.wait_until_present
|
332
|
+
Radio.new(self, locator)
|
333
|
+
end
|
334
|
+
|
335
|
+
def table(locator)
|
336
|
+
@container.wait_until_present
|
337
|
+
Table.new(self, locator)
|
338
|
+
end
|
339
|
+
|
340
|
+
#todo - replace with UIA version
|
341
|
+
# Creates the child window object.
|
342
|
+
# @note This is an Win32 adapter specific method, not part of the public API
|
343
|
+
# @example
|
344
|
+
# RAutomation::Window.new(:title => /Windows Internet Explorer/i).
|
345
|
+
# child(:title => /some popup/)
|
346
|
+
# @param (see Window#initialize)
|
347
|
+
# @return [RAutomation::Window] child window, popup or regular window.
|
348
|
+
def child(locators)
|
349
|
+
RAutomation::Window.new Functions.child_window_locators(hwnd, locators)
|
350
|
+
end
|
351
|
+
|
352
|
+
private
|
353
|
+
|
354
|
+
def press_key key
|
355
|
+
Functions.send_key(key, 0, 0, nil)
|
356
|
+
end
|
357
|
+
|
358
|
+
def release_key key
|
359
|
+
Functions.send_key(key, 0, Constants::KEYEVENTF_KEYUP, nil)
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
end
|
364
|
+
end
|