rautomation 0.6.3 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data/.gitignore +34 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +24 -0
  4. data/History.rdoc +21 -0
  5. data/LICENSE +1 -1
  6. data/README.rdoc +8 -7
  7. data/Rakefile +22 -32
  8. data/VERSION +1 -1
  9. data/ext/UiaDll/Release/UiaDll.dll +0 -0
  10. data/ext/UiaDll/UiaDll.suo +0 -0
  11. data/ext/UiaDll/UiaDll/UiaDll.cpp +236 -10
  12. data/lib/rautomation/adapter/autoit/locators.rb +1 -1
  13. data/lib/rautomation/adapter/autoit/text_field.rb +10 -1
  14. data/lib/rautomation/adapter/autoit/window.rb +50 -23
  15. data/lib/rautomation/adapter/helper.rb +6 -6
  16. data/lib/rautomation/adapter/ms_uia.rb +22 -0
  17. data/lib/rautomation/adapter/{win_ffi → ms_uia}/button.rb +3 -2
  18. data/lib/rautomation/adapter/ms_uia/button_helper.rb +25 -0
  19. data/lib/rautomation/adapter/ms_uia/checkbox.rb +27 -0
  20. data/lib/rautomation/adapter/{win_ffi → ms_uia}/constants.rb +20 -5
  21. data/lib/rautomation/adapter/ms_uia/control.rb +180 -0
  22. data/lib/rautomation/adapter/{win_ffi → ms_uia}/functions.rb +24 -26
  23. data/lib/rautomation/adapter/ms_uia/keystroke_converter.rb +122 -0
  24. data/lib/rautomation/adapter/{win_ffi → ms_uia}/label.rb +3 -2
  25. data/lib/rautomation/adapter/ms_uia/list_box.rb +91 -0
  26. data/lib/rautomation/adapter/ms_uia/list_item.rb +49 -0
  27. data/lib/rautomation/adapter/ms_uia/locators.rb +23 -0
  28. data/lib/rautomation/adapter/{win_ffi → ms_uia}/radio.rb +2 -2
  29. data/lib/rautomation/adapter/{win_ffi → ms_uia}/select_list.rb +41 -7
  30. data/lib/rautomation/adapter/ms_uia/table.rb +86 -0
  31. data/lib/rautomation/adapter/{win_ffi → ms_uia}/text_field.rb +5 -4
  32. data/lib/rautomation/adapter/ms_uia/uia_dll.rb +62 -0
  33. data/lib/rautomation/adapter/ms_uia/window.rb +364 -0
  34. data/lib/rautomation/adapter/win_32.rb +21 -0
  35. data/lib/rautomation/adapter/win_32/button.rb +14 -0
  36. data/lib/rautomation/adapter/{win_ffi → win_32}/button_helper.rb +1 -1
  37. data/lib/rautomation/adapter/win_32/checkbox.rb +14 -0
  38. data/lib/rautomation/adapter/win_32/constants.rb +68 -0
  39. data/lib/rautomation/adapter/{win_ffi → win_32}/control.rb +30 -23
  40. data/lib/rautomation/adapter/win_32/functions.rb +313 -0
  41. data/lib/rautomation/adapter/win_32/keys.rb +121 -0
  42. data/lib/rautomation/adapter/win_32/label.rb +10 -0
  43. data/lib/rautomation/adapter/win_32/list_box.rb +40 -0
  44. data/lib/rautomation/adapter/{win_ffi → win_32}/locators.rb +2 -2
  45. data/lib/rautomation/adapter/win_32/radio.rb +11 -0
  46. data/lib/rautomation/adapter/win_32/select_list.rb +97 -0
  47. data/lib/rautomation/adapter/win_32/table.rb +22 -0
  48. data/lib/rautomation/adapter/win_32/text_field.rb +42 -0
  49. data/lib/rautomation/adapter/{win_ffi → win_32}/window.rb +79 -62
  50. data/lib/rautomation/element_collections.rb +9 -1
  51. data/lib/rautomation/window.rb +17 -9
  52. data/rautomation.gemspec +24 -0
  53. data/spec/adapter/autoit/window_spec.rb +71 -0
  54. data/spec/adapter/{win_ffi → ms_uia}/button_spec.rb +1 -1
  55. data/spec/adapter/{win_ffi → ms_uia}/checkbox_spec.rb +9 -3
  56. data/spec/adapter/ms_uia/control_spec.rb +28 -0
  57. data/spec/adapter/ms_uia/keystroke_converter_spec.rb +50 -0
  58. data/spec/adapter/{win_ffi → ms_uia}/label_spec.rb +2 -2
  59. data/spec/adapter/ms_uia/list_item_spec.rb +14 -0
  60. data/spec/adapter/{win_ffi → ms_uia}/listbox_spec.rb +18 -5
  61. data/spec/adapter/{win_ffi → ms_uia}/radio_spec.rb +3 -1
  62. data/spec/adapter/ms_uia/select_list_spec.rb +109 -0
  63. data/spec/adapter/{win_ffi → ms_uia}/table_spec.rb +12 -1
  64. data/spec/adapter/{win_ffi → ms_uia}/text_field_spec.rb +2 -1
  65. data/spec/adapter/ms_uia/window_spec.rb +89 -0
  66. data/spec/adapter/win_32/button_spec.rb +30 -0
  67. data/spec/adapter/win_32/checkbox_spec.rb +48 -0
  68. data/spec/adapter/win_32/label_spec.rb +15 -0
  69. data/spec/adapter/win_32/listbox_spec.rb +42 -0
  70. data/spec/adapter/win_32/radio_spec.rb +32 -0
  71. data/spec/adapter/{win_ffi → win_32}/select_list_spec.rb +16 -16
  72. data/spec/adapter/win_32/table_spec.rb +28 -0
  73. data/spec/adapter/win_32/text_field_spec.rb +24 -0
  74. data/spec/adapter/{win_ffi → win_32}/window_spec.rb +19 -14
  75. data/spec/button_spec.rb +1 -0
  76. data/spec/buttons_spec.rb +4 -4
  77. data/spec/spec_helper.rb +30 -4
  78. data/spec/text_field_spec.rb +6 -7
  79. data/spec/window_spec.rb +12 -0
  80. data/spec/windows_spec.rb +19 -0
  81. metadata +116 -97
  82. data/lib/rautomation/adapter/win_ffi.rb +0 -21
  83. data/lib/rautomation/adapter/win_ffi/checkbox.rb +0 -19
  84. data/lib/rautomation/adapter/win_ffi/keystroke_converter.rb +0 -67
  85. data/lib/rautomation/adapter/win_ffi/list_box.rb +0 -60
  86. data/lib/rautomation/adapter/win_ffi/ms_uia/uia_dll.rb +0 -36
  87. data/lib/rautomation/adapter/win_ffi/table.rb +0 -57
  88. 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
- not Window.autoit.ControlGetHandle(@window.locator_hwnd, "", @autoit_locators).empty?
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
- [:title, Regexp] => :regexptitle,
34
- :index => :instance,
35
- :hwnd => :handle
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
- locators = @autoit_locators
61
- if @locator_index || @locator_pid
62
- # @todo Come up with some better solution for this case
63
- locators = "[regexptitle:]" # match all, needed for the case when only :index or :pid is used
64
- end
65
- windows = @@autoit.WinList(locators, @locator_text).pop.compact.
66
- map {|handle| self.class.new(:hwnd => handle.hex)}
67
- windows.delete_if {|window| !window.visible?}
68
-
69
- if @locator_pid
70
- window = windows.find {|win| win.pid == @locator_pid}
71
- else
72
- window = windows[@locator_index || 0]
73
- end
74
- window ? window.hwnd : nil
75
- end
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 :WinFfi, File.dirname(__FILE__) + "/win_ffi.rb"
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
- case RUBY_PLATFORM
13
- when /mswin|msys|mingw32/
14
- :win_ffi
15
- else
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 WinFfi
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
- @locators[:id].nil? ? super : super && matches_type(Constants::UIA_BUTTON_CONTROL_TYPE)
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 WinFfi
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
- UIA_LABEL_CONTROL_TYPE = 50020
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 = 50035
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