win_gui 0.2.3 → 0.2.5
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/HISTORY +8 -0
- data/VERSION +1 -1
- data/lib/win_gui/window.rb +47 -46
- data/lib/win_gui.rb +2 -2
- data/spec/spec_helper.rb +22 -1
- data/spec/win_gui/convenience_spec.rb +23 -19
- data/spec/win_gui/window_spec.rb +81 -34
- metadata +3 -3
data/HISTORY
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.5
|
data/lib/win_gui/window.rb
CHANGED
@@ -2,75 +2,75 @@ module WinGui
|
|
2
2
|
|
3
3
|
# This class is a wrapper around window handle
|
4
4
|
class Window
|
5
|
-
# Make convenience methods from both WinGui and Win::Gui available as both class and instance methods
|
6
|
-
# Looks a bit circular though...
|
7
|
-
# include WinGui
|
8
|
-
# extend WinGui
|
9
5
|
|
10
6
|
def initialize(handle)
|
11
7
|
@handle = handle
|
8
|
+
# puts "Window #{handle} created "
|
9
|
+
# p self.class.ancestors
|
12
10
|
end
|
13
11
|
|
14
12
|
attr_reader :handle
|
15
13
|
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
# :
|
20
|
-
#
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
timeout = opts[:timeout] # || LOOKUP_TIMEOUT ? # no timeout by default
|
26
|
-
|
27
|
-
if timeout
|
14
|
+
# Looks up window handle using code specified in attached block (either with or without :timeout)
|
15
|
+
# Returns either Window instance (for a found handle) or nil if nothing found
|
16
|
+
# Private method to dry up other window lookup methods
|
17
|
+
# :yields:
|
18
|
+
#
|
19
|
+
def self.lookup_window(opts)
|
20
|
+
# Need this to avoid handle considered local in begin..end block
|
21
|
+
handle = yield
|
22
|
+
if opts[:timeout]
|
28
23
|
begin
|
29
|
-
timeout(timeout) do
|
30
|
-
sleep SLEEP_DELAY
|
24
|
+
timeout(opts[:timeout]) do
|
25
|
+
sleep SLEEP_DELAY until handle = yield
|
31
26
|
end
|
32
27
|
rescue TimeoutError
|
33
28
|
nil
|
34
29
|
end
|
35
|
-
else
|
36
|
-
@handle = WinGui.find_window window_class, window_title
|
37
30
|
end
|
38
|
-
|
31
|
+
raise opts[:raise] if opts[:raise] && !handle
|
32
|
+
Window.new(handle) if handle
|
39
33
|
end
|
40
34
|
|
41
|
-
#
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
35
|
+
# Find top level window by title/class, returns wrapped Window object or nil.
|
36
|
+
# If timeout option given, waits for window to appear within timeout, returns nil if it didn't
|
37
|
+
# Options:
|
38
|
+
# :title:: window title
|
39
|
+
# :class:: window class
|
40
|
+
# :timeout:: timeout (seconds)
|
41
|
+
def self.top_level(opts={})
|
42
|
+
lookup_window(opts) { WinGui.find_window opts[:class], opts[:title] }
|
43
|
+
end
|
44
|
+
|
45
|
+
# Find DIRECT child window (control) by either control ID or window class/title.
|
46
|
+
def child(opts={})
|
47
|
+
self.class.lookup_window(opts) do
|
48
|
+
opts[:id] ? get_dlg_item(opts[:id]) : find_window_ex(0, opts[:class], opts[:title])
|
54
49
|
end
|
55
|
-
raise "Control '#{id}' not found" unless result
|
56
|
-
Window.new result
|
57
50
|
end
|
58
51
|
|
59
|
-
#
|
52
|
+
# Return array of Windows that are descendants (not only DIRECT children) of a given Window
|
60
53
|
def children
|
61
54
|
enum_child_windows.map{|child_handle| Window.new child_handle}
|
62
55
|
end
|
63
56
|
|
64
|
-
#
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
57
|
+
# Emulate click of the control identified by opts (:id, :title, :class)
|
58
|
+
# Return true if click was presumably successful, false if it failed (control was not found)
|
59
|
+
def click(opts={})
|
60
|
+
control = child(opts)
|
61
|
+
if control
|
62
|
+
left, top, right, bottom = control.get_window_rect
|
63
|
+
center = [(left + right) / 2, (top + bottom) / 2]
|
64
|
+
WinGui.set_cursor_pos *center
|
65
|
+
WinGui.mouse_event WinGui::MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0
|
66
|
+
WinGui.mouse_event WinGui::MOUSEEVENTF_LEFTUP, 0, 0, 0, 0
|
67
|
+
true
|
68
|
+
else
|
69
|
+
false
|
70
|
+
end
|
71
71
|
end
|
72
72
|
|
73
|
-
def wait_for_close(timeout
|
73
|
+
def wait_for_close(timeout=CLOSE_TIMEOUT )
|
74
74
|
timeout(timeout) do
|
75
75
|
sleep SLEEP_DELAY while window_visible?
|
76
76
|
end
|
@@ -97,7 +97,8 @@ module WinGui
|
|
97
97
|
# WinGui.function(*args)
|
98
98
|
def method_missing(name, *args, &block)
|
99
99
|
if WinGui.respond_to? name
|
100
|
-
|
100
|
+
# puts "Window #{@handle} calling: #{name} #{@handle} #{args} &#{block}"
|
101
|
+
WinGui.send(name, @handle, *args, &block)
|
101
102
|
else
|
102
103
|
super
|
103
104
|
end
|
data/lib/win_gui.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -75,7 +75,10 @@ module WinGuiTest
|
|
75
75
|
while @test_app && find_window(nil, WIN_TITLE)
|
76
76
|
@test_app.close
|
77
77
|
# Dealing with closing confirmation modal dialog
|
78
|
-
|
78
|
+
if dialog = dialog( title: "Steganos Locknote", timeout: SLEEP_DELAY)
|
79
|
+
dialog.set_foreground_window
|
80
|
+
keystroke("N")
|
81
|
+
end
|
79
82
|
end
|
80
83
|
@test_app = nil
|
81
84
|
end
|
@@ -87,4 +90,22 @@ module WinGuiTest
|
|
87
90
|
close_test_app
|
88
91
|
end
|
89
92
|
|
93
|
+
def with_dialog(type=:close)
|
94
|
+
case type
|
95
|
+
when :close
|
96
|
+
keystroke('A')
|
97
|
+
@app.close
|
98
|
+
title, key = "Steganos Locknote", "N"
|
99
|
+
when :save
|
100
|
+
keystroke(VK_ALT, 'F', 'A')
|
101
|
+
title, key = "Save As", VK_ESCAPE
|
102
|
+
end
|
103
|
+
sleep 0.01 until dialog = Window.top_level(title: title)
|
104
|
+
yield dialog
|
105
|
+
while dialog.window?
|
106
|
+
dialog.set_foreground_window
|
107
|
+
keystroke(key)
|
108
|
+
sleep 0.01
|
109
|
+
end
|
110
|
+
end
|
90
111
|
end
|
@@ -7,38 +7,43 @@ module WinGuiTest
|
|
7
7
|
after(:each) { close_test_app }
|
8
8
|
|
9
9
|
describe '#dialog' do
|
10
|
-
# Open "Save as" modal dialog
|
11
|
-
before(:each){ keystroke(VK_ALT, 'F', 'A') }
|
12
|
-
# Close modal dialog if it is opened
|
13
|
-
after(:each) { keystroke(VK_ESCAPE) if Window.top_level( title: "Save As", timeout: 0.1) }
|
14
|
-
|
15
10
|
it 'returns top-level dialog window with given title if no block attached' do
|
16
|
-
|
17
|
-
|
18
|
-
dialog_window.should be_a Window
|
19
|
-
dialog_window.text.should == DIALOG_TITLE
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'yields found dialog window to block if block is attached' do
|
23
|
-
dialog(title: DIALOG_TITLE) do |dialog_window|
|
11
|
+
with_dialog(:save) do
|
12
|
+
dialog_window = dialog(title: DIALOG_TITLE, timeout: 0.1)
|
24
13
|
dialog_window.should_not == nil
|
25
14
|
dialog_window.should be_a Window
|
26
15
|
dialog_window.text.should == DIALOG_TITLE
|
27
16
|
end
|
28
17
|
end
|
29
18
|
|
19
|
+
it 'yields found dialog window to block if block is attached' do
|
20
|
+
with_dialog(:save) do
|
21
|
+
dialog(title: DIALOG_TITLE) do |dialog_window|
|
22
|
+
dialog_window.should_not == nil
|
23
|
+
dialog_window.should be_a Window
|
24
|
+
dialog_window.text.should == DIALOG_TITLE
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
30
29
|
it 'returns nil if there is no dialog with given title' do
|
31
|
-
|
30
|
+
with_dialog(:save) do
|
31
|
+
dialog(title: IMPOSSIBLE, timeout: 0.1).should == nil
|
32
|
+
end
|
32
33
|
end
|
33
34
|
|
34
35
|
it 'yields nil to attached block if no dialog found' do
|
35
|
-
|
36
|
-
|
36
|
+
with_dialog(:save) do
|
37
|
+
dialog(title: IMPOSSIBLE, timeout: 0.1) do |dialog_window|
|
38
|
+
dialog_window.should == nil
|
39
|
+
end
|
37
40
|
end
|
38
41
|
end
|
39
42
|
|
40
43
|
it 'considers all arguments optional' do
|
41
|
-
|
44
|
+
with_dialog(:save) do
|
45
|
+
use { dialog_window = dialog() }
|
46
|
+
end
|
42
47
|
end
|
43
48
|
end # describe dialog
|
44
49
|
|
@@ -64,6 +69,5 @@ module WinGuiTest
|
|
64
69
|
end # describe '#type_in'
|
65
70
|
|
66
71
|
end # Input methods
|
67
|
-
|
68
|
-
end
|
72
|
+
end # Convenience methods
|
69
73
|
end
|
data/spec/win_gui/window_spec.rb
CHANGED
@@ -85,35 +85,75 @@ module WinGuiTest
|
|
85
85
|
Window.top_level( title: IMPOSSIBLE, timeout: 0.5).should == nil
|
86
86
|
(Time.now - start).should be_close 0.5, 0.02
|
87
87
|
end
|
88
|
-
|
88
|
+
|
89
|
+
it 'raises exception if asked to' do
|
90
|
+
expect{ Window.top_level( title: IMPOSSIBLE, raise: "Horror!")}.to raise_error "Horror!"
|
91
|
+
end
|
92
|
+
end # describe .top_level
|
89
93
|
|
90
94
|
describe '#child' do
|
91
|
-
spec { use { @
|
95
|
+
spec { use { @child = @app.child(title: "Title", class: "Class", id: 0) }}
|
92
96
|
|
93
|
-
it '
|
94
|
-
|
97
|
+
it 'returns nil immediately if specific child not found' do
|
98
|
+
start = Time.now
|
99
|
+
@app.child( title: IMPOSSIBLE).should == nil
|
100
|
+
(Time.now - start).should be_close 0, 0.02
|
95
101
|
end
|
96
102
|
|
97
|
-
it '
|
98
|
-
|
103
|
+
it 'returns nil after timeout if specific child not found' do
|
104
|
+
start = Time.now
|
105
|
+
@app.child( title: IMPOSSIBLE, timeout: 0.5).should == nil
|
106
|
+
(Time.now - start).should be_close 0.5, 0.02
|
99
107
|
end
|
100
108
|
|
101
|
-
it 'finds child window
|
102
|
-
|
103
|
-
@
|
109
|
+
it 'finds ANY child window without args' do
|
110
|
+
use { @child = @app.child() }
|
111
|
+
@child.should_not == nil
|
112
|
+
@app.child?(@child.handle).should == true
|
104
113
|
end
|
105
114
|
|
106
|
-
it 'finds child window
|
107
|
-
|
108
|
-
|
115
|
+
it 'finds child window by class and returns it as a Window object (no timeout)' do
|
116
|
+
child = @app.child( class: TEXTAREA_CLASS)
|
117
|
+
child.should_not == nil
|
118
|
+
@app.child?(child.handle).should == true
|
109
119
|
end
|
110
120
|
|
111
|
-
it '
|
112
|
-
|
121
|
+
it 'finds child window by class and returns it as a Window object (with timeout)' do
|
122
|
+
# p @app.find_window_ex(0, TEXTAREA_CLASS, nil)
|
123
|
+
# p @app.find_window_ex(0, STATUSBAR_CLASS, nil)
|
124
|
+
child = @app.child( class: TEXTAREA_CLASS, timeout: 0.5)
|
125
|
+
child.should_not == nil
|
126
|
+
|
127
|
+
@app.child?(child.handle).should == true
|
128
|
+
child = @app.child( class: STATUSBAR_CLASS, timeout: 0.5)
|
129
|
+
child.should_not == nil
|
130
|
+
@app.child?(child.handle).should == true
|
113
131
|
end
|
114
132
|
|
115
|
-
it '
|
116
|
-
|
133
|
+
it 'finds child with specific text and returns it as a Window object' do
|
134
|
+
with_dialog(:save) do |dialog|
|
135
|
+
# @dialog.children.each{|child| puts "#{child.handle}, #{child.class_name}, #{child.window_text}"}
|
136
|
+
child = dialog.child( title: "Cancel")
|
137
|
+
child.should_not == nil
|
138
|
+
dialog.child?(child.handle).should == true
|
139
|
+
child.get_dlg_ctrl_id.should == IDCANCEL
|
140
|
+
|
141
|
+
child = dialog.child( title: "&Save")
|
142
|
+
child.should_not == nil
|
143
|
+
dialog.child?(child.handle).should == true
|
144
|
+
child.get_dlg_ctrl_id.should == IDOK
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'finds child control with a given ID and returns it as a Window object' do
|
149
|
+
with_dialog(:save) do |dialog|
|
150
|
+
child = dialog.child( id: IDCANCEL)
|
151
|
+
child.should_not == nil
|
152
|
+
dialog.child?(child.handle).should == true
|
153
|
+
child.text.should == "Cancel"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end # describe child
|
117
157
|
|
118
158
|
describe '#children' do
|
119
159
|
spec { use { children = @app.children }}
|
@@ -126,26 +166,33 @@ module WinGuiTest
|
|
126
166
|
children.each{|child| child?(@app.handle, child.handle).should == true }
|
127
167
|
children.last.class_name.should == TEXTAREA_CLASS
|
128
168
|
end
|
169
|
+
end # describe #children
|
129
170
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
# end
|
139
|
-
#
|
140
|
-
# it 'raises error if wrong control is given' do
|
141
|
-
# expect { @app.child('Impossible Control')}.to raise_error "Control 'Impossible Control' not found"
|
142
|
-
# end
|
143
|
-
# it 'substitutes & for _ when searching by title ("&Yes" type controls)'
|
171
|
+
describe '#click' do
|
172
|
+
it 'emulates clicking of the control identified by id, returns true' do
|
173
|
+
with_dialog(:save) do |dialog|
|
174
|
+
dialog.click(id: IDCANCEL).should == true
|
175
|
+
sleep 0.5
|
176
|
+
dialog.window?.should == false
|
177
|
+
end
|
178
|
+
end
|
144
179
|
|
145
|
-
|
180
|
+
it 'emulates clicking of the control identified by title, returns true' do
|
181
|
+
with_dialog(:save) do |dialog|
|
182
|
+
dialog.click(title: "Cancel").should == true
|
183
|
+
sleep 0.5
|
184
|
+
dialog.window?.should == false
|
185
|
+
end
|
186
|
+
end
|
146
187
|
|
147
|
-
|
148
|
-
|
149
|
-
|
188
|
+
it 'returns false if the specified control was not found' do
|
189
|
+
with_dialog(:save) do |dialog|
|
190
|
+
dialog.click(title: "Shpancel").should == false
|
191
|
+
dialog.click(id: 66).should == false
|
192
|
+
sleep 0.5
|
193
|
+
dialog.window?.should == true
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end # describe #click
|
150
197
|
end
|
151
198
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 2
|
8
|
-
-
|
9
|
-
version: 0.2.
|
8
|
+
- 5
|
9
|
+
version: 0.2.5
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- arvicco
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-06-
|
17
|
+
date: 2010-06-04 00:00:00 +04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|