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
@@ -8,7 +8,7 @@ module RAutomation
|
|
8
8
|
|
9
9
|
def extract(locators)
|
10
10
|
locators = self.class::DEFAULT_LOCATORS.merge(locators) if self.class.const_defined?(:DEFAULT_LOCATORS)
|
11
|
-
@locators = locators
|
11
|
+
@locators = {:index => 0}.merge(locators)
|
12
12
|
@autoit_locators = "[#{@locators.map do |locator, value|
|
13
13
|
locator_key = self.class::LOCATORS[locator] || self.class::LOCATORS[[locator, value.class]]
|
14
14
|
value = value.to_i + 1 if locator == :index # use 0-based indexing
|
@@ -30,6 +30,10 @@ module RAutomation
|
|
30
30
|
extract(locators)
|
31
31
|
end
|
32
32
|
|
33
|
+
def hwnd
|
34
|
+
Window.autoit.ControlGetHandle(@window.locator_hwnd, "", @autoit_locators).hex
|
35
|
+
end
|
36
|
+
|
33
37
|
# @see RAutomation::TextField#set
|
34
38
|
def set(text)
|
35
39
|
wait_until do
|
@@ -53,7 +57,12 @@ module RAutomation
|
|
53
57
|
|
54
58
|
# @see RAutomation::TextField#exists?
|
55
59
|
def exists?
|
56
|
-
|
60
|
+
hwnd != 0
|
61
|
+
end
|
62
|
+
|
63
|
+
def hwnd
|
64
|
+
handle = Window.autoit.ControlGetHandle(@window.locator_hwnd, "", @autoit_locators)
|
65
|
+
handle.to_i(16)
|
57
66
|
end
|
58
67
|
end
|
59
68
|
end
|
@@ -30,9 +30,9 @@ module RAutomation
|
|
30
30
|
# @private
|
31
31
|
# Special-cased locators
|
32
32
|
LOCATORS = {
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
[:title, Regexp] => :regexptitle,
|
34
|
+
:index => :instance,
|
35
|
+
:hwnd => :handle
|
36
36
|
}
|
37
37
|
|
38
38
|
# Creates the window object.
|
@@ -44,7 +44,8 @@ module RAutomation
|
|
44
44
|
# @option locators [String, Fixnum] :hwnd Window handle in decimal format
|
45
45
|
# @option locators [String, Fixnum] :index 0-based index to specify n-th window if all other criteria match
|
46
46
|
# @see RAutomation::Window#initialize
|
47
|
-
def initialize(locators)
|
47
|
+
def initialize(container, locators)
|
48
|
+
@container = container
|
48
49
|
@hwnd = locators[:hwnd]
|
49
50
|
@locator_index = locators.delete(:index) if locators[:index] && locators.size == 1
|
50
51
|
@locator_pid = locators.delete(:pid).to_i if locators[:pid]
|
@@ -57,22 +58,22 @@ module RAutomation
|
|
57
58
|
# @see RAutomation::Window#hwnd
|
58
59
|
def hwnd
|
59
60
|
@hwnd ||= begin
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
61
|
+
locators = @autoit_locators
|
62
|
+
if @locator_index || @locator_pid
|
63
|
+
# @todo Come up with some better solution for this case
|
64
|
+
locators = "[regexptitle:]" # match all, needed for the case when only :index or :pid is used
|
65
|
+
end
|
66
|
+
windows = @@autoit.WinList(locators, @locator_text).pop.compact.
|
67
|
+
map { |handle| RAutomation::Window.new(:hwnd => handle.hex) }
|
68
|
+
windows.delete_if { |window| !window.visible? }
|
69
|
+
|
70
|
+
if @locator_pid
|
71
|
+
window = windows.find { |win| win.pid == @locator_pid }
|
72
|
+
else
|
73
|
+
window = windows[@locator_index || 0]
|
74
|
+
end
|
75
|
+
window ? window.hwnd : nil
|
76
|
+
end
|
76
77
|
end
|
77
78
|
|
78
79
|
# @see RAutomation::Window#pid
|
@@ -85,6 +86,11 @@ module RAutomation
|
|
85
86
|
@@autoit.WinGetTitle(locator_hwnd)
|
86
87
|
end
|
87
88
|
|
89
|
+
# @see RAutomation::Window#class_names
|
90
|
+
def class_names
|
91
|
+
@@autoit.WinGetClassList(locator_hwnd).split("\n").sort
|
92
|
+
end
|
93
|
+
|
88
94
|
# @see RAutomation::Window#activate
|
89
95
|
def activate
|
90
96
|
@@autoit.WinWait(locator_hwnd, "", 1)
|
@@ -145,7 +151,7 @@ module RAutomation
|
|
145
151
|
activate
|
146
152
|
active?
|
147
153
|
end
|
148
|
-
@@autoit.Send(keys)
|
154
|
+
@@autoit.Send(keys[0])
|
149
155
|
end
|
150
156
|
|
151
157
|
# @see RAutomation::Window#close
|
@@ -156,13 +162,13 @@ module RAutomation
|
|
156
162
|
|
157
163
|
# @see Button#initialize
|
158
164
|
# @see RAutomation::Window#button
|
159
|
-
def button(locator)
|
165
|
+
def button(locator={})
|
160
166
|
Button.new(self, locator)
|
161
167
|
end
|
162
168
|
|
163
169
|
# @see TextField#initialize
|
164
170
|
# @see RAutomation::Window#text_field
|
165
|
-
def text_field(locator)
|
171
|
+
def text_field(locator={})
|
166
172
|
TextField.new(self, locator)
|
167
173
|
end
|
168
174
|
|
@@ -174,6 +180,27 @@ module RAutomation
|
|
174
180
|
@@autoit.send(name, *args)
|
175
181
|
end
|
176
182
|
|
183
|
+
# AutoIt adapter specific API methods
|
184
|
+
def move_mouse(x_coord, y_coord)
|
185
|
+
@@autoit.MouseMove(x_coord, y_coord)
|
186
|
+
end
|
187
|
+
|
188
|
+
def mouse_position
|
189
|
+
[@@autoit.MouseGetPosX, @@autoit.MouseGetPosY]
|
190
|
+
end
|
191
|
+
|
192
|
+
def click_mouse(button = "left")
|
193
|
+
@@autoit.MouseClick(button)
|
194
|
+
end
|
195
|
+
|
196
|
+
def press_mouse(button = "left")
|
197
|
+
@@autoit.MouseDown(button)
|
198
|
+
end
|
199
|
+
|
200
|
+
def release_mouse(button = "left")
|
201
|
+
@@autoit.MouseUp(button)
|
202
|
+
end
|
203
|
+
|
177
204
|
# @private
|
178
205
|
def locator_hwnd
|
179
206
|
"[HANDLE:#{hwnd.to_i.to_s(16)}]"
|
@@ -1,7 +1,8 @@
|
|
1
1
|
module RAutomation
|
2
2
|
module Adapter
|
3
3
|
autoload :Autoit, File.dirname(__FILE__) + "/autoit.rb"
|
4
|
-
autoload :
|
4
|
+
autoload :MsUia, File.dirname(__FILE__) + "/ms_uia.rb"
|
5
|
+
autoload :Win32, File.dirname(__FILE__) + "/win_32.rb"
|
5
6
|
|
6
7
|
module Helper
|
7
8
|
extend self
|
@@ -9,11 +10,10 @@ module RAutomation
|
|
9
10
|
# @private
|
10
11
|
# Retrieves default {Adapter} for the current platform.
|
11
12
|
def default_adapter
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
raise "unsupported platform for RAutomation: #{RUBY_PLATFORM}"
|
13
|
+
if ENV['OS'] == 'Windows_NT'
|
14
|
+
:win_32
|
15
|
+
else
|
16
|
+
raise "unsupported platform for RAutomation: #{RUBY_PLATFORM}"
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
@@ -0,0 +1,22 @@
|
|
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__) + "/ms_uia/constants"
|
8
|
+
require File.dirname(__FILE__) + "/ms_uia/keystroke_converter"
|
9
|
+
require File.dirname(__FILE__) + "/ms_uia/functions"
|
10
|
+
require File.dirname(__FILE__) + "/ms_uia/locators"
|
11
|
+
require File.dirname(__FILE__) + "/ms_uia/window"
|
12
|
+
require File.dirname(__FILE__) + "/ms_uia/button_helper"
|
13
|
+
require File.dirname(__FILE__) + "/ms_uia/control"
|
14
|
+
require File.dirname(__FILE__) + "/ms_uia/button"
|
15
|
+
require File.dirname(__FILE__) + "/ms_uia/checkbox"
|
16
|
+
require File.dirname(__FILE__) + "/ms_uia/radio"
|
17
|
+
require File.dirname(__FILE__) + "/ms_uia/text_field"
|
18
|
+
require File.dirname(__FILE__) + "/ms_uia/select_list"
|
19
|
+
require File.dirname(__FILE__) + "/ms_uia/table"
|
20
|
+
require File.dirname(__FILE__) + "/ms_uia/label"
|
21
|
+
require File.dirname(__FILE__) + "/ms_uia/list_box"
|
22
|
+
require File.dirname(__FILE__) + "/ms_uia/list_item"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module RAutomation
|
2
2
|
module Adapter
|
3
|
-
module
|
3
|
+
module MsUia
|
4
4
|
class Button < Control
|
5
5
|
include WaitHelper
|
6
6
|
include Locators
|
@@ -8,13 +8,14 @@ module RAutomation
|
|
8
8
|
# Default locators used for searching buttons.
|
9
9
|
DEFAULT_LOCATORS = {:class => /button/i}
|
10
10
|
|
11
|
+
#todo - replace with UIA version
|
11
12
|
# @see RAutomation::Button#value
|
12
13
|
def value
|
13
14
|
Functions.control_value(Functions.control_hwnd(@window.hwnd, @locators))
|
14
15
|
end
|
15
16
|
|
16
17
|
def exist?
|
17
|
-
|
18
|
+
super && matches_type?(Constants::UIA_BUTTON_CONTROL_TYPE)
|
18
19
|
end
|
19
20
|
|
20
21
|
alias_method :exists?, :exist?
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module RAutomation
|
2
|
+
module Adapter
|
3
|
+
module MsUia
|
4
|
+
module ButtonHelper
|
5
|
+
|
6
|
+
#todo - replace with UIA version
|
7
|
+
def set?
|
8
|
+
control_hwnd = Functions.control_hwnd(@window.hwnd, @locators)
|
9
|
+
Functions.control_set? control_hwnd
|
10
|
+
end
|
11
|
+
|
12
|
+
# @todo call a windows function to do this without clicking
|
13
|
+
def clear
|
14
|
+
click {!set?} if set?
|
15
|
+
end
|
16
|
+
|
17
|
+
# @todo call a windows function to do this without clicking
|
18
|
+
def set
|
19
|
+
click {set?} unless set?
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module RAutomation
|
2
|
+
module Adapter
|
3
|
+
module MsUia
|
4
|
+
class Checkbox < Control
|
5
|
+
include WaitHelper
|
6
|
+
include Locators
|
7
|
+
include ButtonHelper
|
8
|
+
|
9
|
+
def value
|
10
|
+
hwnd = Functions.control_hwnd(@window.hwnd, @locators)
|
11
|
+
checkbox = UiaDll::element_from_handle(hwnd)
|
12
|
+
|
13
|
+
checkbox_value = FFI::MemoryPointer.new :char, UiaDll::get_name(checkbox, nil) + 1
|
14
|
+
UiaDll::get_name(checkbox, checkbox_value)
|
15
|
+
checkbox_value.read_string
|
16
|
+
end
|
17
|
+
|
18
|
+
def exist?
|
19
|
+
super && matches_type?(Constants::UIA_CHECKBOX_CONTROL_TYPE)
|
20
|
+
end
|
21
|
+
|
22
|
+
alias_method :exists?, :exist?
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module RAutomation
|
2
2
|
module Adapter
|
3
|
-
module
|
4
|
-
# @private
|
3
|
+
module MsUia
|
5
4
|
module Constants
|
6
5
|
WM_GETTEXT = 0xD
|
7
6
|
WM_SETTEXT = 0xC
|
@@ -50,6 +49,8 @@ module RAutomation
|
|
50
49
|
VK_NUMLOCK = 0x90
|
51
50
|
VK_DELETE = 0x2E
|
52
51
|
VK_INSERT = 0x2D
|
52
|
+
VK_NEXT = 0x22
|
53
|
+
VK_PRIOR = 0x21
|
53
54
|
|
54
55
|
# GetWindow constants
|
55
56
|
GW_ENABLEDPOPUP = 6
|
@@ -65,11 +66,23 @@ module RAutomation
|
|
65
66
|
|
66
67
|
# Combobox
|
67
68
|
CB_GETCOUNT = 0x0146
|
69
|
+
CB_GETTOPINDEX = 0x015b
|
68
70
|
CB_GETLBTEXTLEN = 0x0149
|
69
71
|
CB_GETLBTEXT = 0x0148
|
70
72
|
CB_GETCURSEL = 0x0147
|
73
|
+
CB_GETDROPPEDCONTROLRECT = 0x0152
|
74
|
+
CB_GETITEMHEIGHT = 0x0154
|
71
75
|
CB_ERR = -1
|
72
76
|
CB_SETCURSEL = 0x14E
|
77
|
+
CB_SELECTSTRING = 0x14D
|
78
|
+
CB_SETEDITSEL = 0x142
|
79
|
+
CB_SETTOPINDEX = 0x015c
|
80
|
+
|
81
|
+
#ListBox
|
82
|
+
LB_SETTOPINDEX = 0x0197
|
83
|
+
LB_GETITEMHEIGHT = 0x01A1
|
84
|
+
LB_GETITEMRECT = 0x0198
|
85
|
+
LB_GETTOPINDEX = 0x018E
|
73
86
|
|
74
87
|
# listview
|
75
88
|
LVM_FIRST = 0x1000
|
@@ -78,15 +91,17 @@ module RAutomation
|
|
78
91
|
# UI Automation control type IDs
|
79
92
|
UIA_LIST_CONTROL_TYPE = 50008
|
80
93
|
UIA_LIST_ITEM_CONTROL_TYPE = 50007
|
94
|
+
UIA_DATA_ITEM_CONTROL_TYPE =50029
|
81
95
|
UIA_CHECKBOX_CONTROL_TYPE = 50002
|
82
96
|
UIA_BUTTON_CONTROL_TYPE = 50000
|
83
|
-
|
97
|
+
UIA_TEXT_CONTROL_TYPE = 50020
|
84
98
|
UIA_RADIO_BUTTON_CONTROL_TYPE = 50013
|
85
99
|
UIA_COMBOBOX_CONTROL_TYPE = 50003
|
86
100
|
UIA_EDIT_CONTROL_TYPE = 50004
|
87
101
|
UIA_HEADER_CONTROL_TYPE = 50034
|
88
|
-
UIA_HEADER_ITEM_CONTROL_TYPE
|
89
|
-
|
102
|
+
UIA_HEADER_ITEM_CONTROL_TYPE = 50035
|
103
|
+
UIA_WINDOW_CONTROL_TYPE = 50032
|
104
|
+
UIA_PANE_CONTROL_TYPE = 50033
|
90
105
|
|
91
106
|
end
|
92
107
|
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
module RAutomation
|
2
|
+
module Adapter
|
3
|
+
module MsUia
|
4
|
+
class Control
|
5
|
+
include WaitHelper
|
6
|
+
include Locators
|
7
|
+
|
8
|
+
# Creates the control object.
|
9
|
+
# @note this method is not meant to be accessed directly
|
10
|
+
# @param [RAutomation::Window] window this button belongs to.
|
11
|
+
# @param [Hash] locators for searching the button.
|
12
|
+
# @option locators [String, Regexp] :value Value (text) of the button
|
13
|
+
# @option locators [String, Regexp] :class Internal class name of the button
|
14
|
+
# @option locators [String, Fixnum] :id Internal ID of the button
|
15
|
+
# @option locators [String, Fixnum] :index 0-based index to specify n-th button if all other criteria match
|
16
|
+
# @see RAutomation::Window#button
|
17
|
+
def initialize(window, locators)
|
18
|
+
@window = window
|
19
|
+
extract(locators)
|
20
|
+
end
|
21
|
+
|
22
|
+
#todo - replace with UIA version
|
23
|
+
def hwnd
|
24
|
+
Functions.control_hwnd(@window.hwnd, @locators)
|
25
|
+
end
|
26
|
+
|
27
|
+
def uia_element
|
28
|
+
# puts "finding element with #{@locators.inspect}"
|
29
|
+
|
30
|
+
case
|
31
|
+
#Causes a bug for some reason
|
32
|
+
# when @locators[:value]
|
33
|
+
# uia_window = UiaDll::element_from_handle(@window.hwnd)
|
34
|
+
# begin
|
35
|
+
# uia_window.read_pointer
|
36
|
+
# rescue FFI::NullPointerError => e
|
37
|
+
# raise UnknownElementException, "Window with handle #{@window.hwnd} does not exist"
|
38
|
+
# end
|
39
|
+
# uia_control = UiaDll::find_child_by_name(uia_window, @locators[:value].to_s)
|
40
|
+
# begin
|
41
|
+
# uia_control.read_pointer
|
42
|
+
# rescue FFI::NullPointerError => e
|
43
|
+
# raise UnknownElementException, "#{@locators[:value]} does not exist"
|
44
|
+
# end
|
45
|
+
when @locators[:focus]
|
46
|
+
uia_control = UiaDll::get_focused_element
|
47
|
+
begin
|
48
|
+
uia_control.read_pointer
|
49
|
+
rescue FFI::NullPointerError => e
|
50
|
+
raise UnknownElementException, "Focused element does not exist"
|
51
|
+
end
|
52
|
+
when @locators[:id]
|
53
|
+
uia_window = UiaDll::element_from_handle(@window.hwnd)
|
54
|
+
uia_control = UiaDll::find_child_by_id(uia_window, @locators[:id].to_s)
|
55
|
+
begin
|
56
|
+
uia_control.read_pointer
|
57
|
+
rescue FFI::NullPointerError => e
|
58
|
+
raise UnknownElementException, "#{@locators[:id]} does not exist"
|
59
|
+
end
|
60
|
+
when @locators[:point]
|
61
|
+
uia_control = UiaDll::element_from_point(@locators[:point][0], @locators[:point][1])
|
62
|
+
begin
|
63
|
+
uia_control.read_pointer
|
64
|
+
rescue FFI::NullPointerError => e
|
65
|
+
raise UnknownElementException, "#{@locators[:point]} does not exist"
|
66
|
+
end
|
67
|
+
else
|
68
|
+
handle= hwnd
|
69
|
+
raise UnknownElementException, "Element with #{@locators.inspect} does not exist" if (handle == 0) or (handle == nil)
|
70
|
+
uia_control = UiaDll::element_from_handle(handle)
|
71
|
+
end
|
72
|
+
uia_control
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
#todo - replace with UIA version
|
77
|
+
def click
|
78
|
+
assert_enabled
|
79
|
+
clicked = false
|
80
|
+
wait_until do
|
81
|
+
@window.activate
|
82
|
+
@window.active? &&
|
83
|
+
Functions.set_control_focus(hwnd) &&
|
84
|
+
Functions.control_click(hwnd) &&
|
85
|
+
clicked = true # is clicked at least once
|
86
|
+
|
87
|
+
block_given? ? yield : clicked && !exist?
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def exist?
|
92
|
+
begin
|
93
|
+
!!uia_element
|
94
|
+
rescue UnknownElementException
|
95
|
+
false
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def enabled?
|
100
|
+
!disabled?
|
101
|
+
end
|
102
|
+
|
103
|
+
#todo - replace with UIA version
|
104
|
+
def disabled?
|
105
|
+
Functions.unavailable?(hwnd)
|
106
|
+
end
|
107
|
+
|
108
|
+
#todo - replace with UIA version
|
109
|
+
def has_focus?
|
110
|
+
Functions.has_focus?(hwnd)
|
111
|
+
end
|
112
|
+
|
113
|
+
def set_focus
|
114
|
+
assert_enabled
|
115
|
+
uia_control = UiaDll::element_from_handle(hwnd)
|
116
|
+
UiaDll::set_focus(uia_control)
|
117
|
+
end
|
118
|
+
|
119
|
+
def bounding_rectangle
|
120
|
+
control = uia_element
|
121
|
+
|
122
|
+
boundary = FFI::MemoryPointer.new :long, 4
|
123
|
+
UiaDll::bounding_rectangle(control, boundary)
|
124
|
+
|
125
|
+
boundary.read_array_of_long(4)
|
126
|
+
end
|
127
|
+
|
128
|
+
def visible?
|
129
|
+
element = UiaDll::element_from_handle(hwnd)
|
130
|
+
|
131
|
+
off_screen = FFI::MemoryPointer.new :int
|
132
|
+
|
133
|
+
if UiaDll::is_offscreen(element, off_screen) == 0
|
134
|
+
fail "Could not check element"
|
135
|
+
end
|
136
|
+
|
137
|
+
# puts "return #{off_screen.read_int}"
|
138
|
+
if off_screen.read_int == 0
|
139
|
+
return true
|
140
|
+
end
|
141
|
+
false
|
142
|
+
end
|
143
|
+
|
144
|
+
def matches_type?(clazz)
|
145
|
+
get_current_control_type == clazz
|
146
|
+
end
|
147
|
+
|
148
|
+
def get_current_control_type
|
149
|
+
UiaDll::current_control_type(uia_element)
|
150
|
+
end
|
151
|
+
|
152
|
+
def new_pid
|
153
|
+
UiaDll::current_process_id(uia_element)
|
154
|
+
end
|
155
|
+
|
156
|
+
def control_name
|
157
|
+
uia_control = uia_element
|
158
|
+
element_name = FFI::MemoryPointer.new :char, UiaDll::get_name(uia_control, nil) + 1
|
159
|
+
|
160
|
+
UiaDll::get_name(uia_control, element_name)
|
161
|
+
element_name.read_string
|
162
|
+
end
|
163
|
+
|
164
|
+
def control_class
|
165
|
+
uia_control = uia_element
|
166
|
+
element_class = FFI::MemoryPointer.new :char, UiaDll::get_class_name(uia_control, nil) + 1
|
167
|
+
|
168
|
+
UiaDll::get_class_name(uia_control, element_class)
|
169
|
+
element_class.read_string
|
170
|
+
end
|
171
|
+
|
172
|
+
alias_method :exists?, :exist?
|
173
|
+
|
174
|
+
def assert_enabled
|
175
|
+
raise "Cannot interact with disabled control #{@locators.inspect} on window #{@window.locators.inspect}!" if disabled?
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|