win_gui 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +21 -14
- data/VERSION +1 -1
- data/lib/win_gui/def_api.rb +46 -30
- data/lib/win_gui/win_gui.rb +54 -16
- data/spec/spec_helper.rb +16 -9
- data/spec/win_gui/def_api_spec.rb +17 -2
- data/spec/win_gui/win_gui_spec.rb +218 -167
- data/win_gui.gemspec +2 -2
- metadata +2 -2
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= win_gui
|
2
2
|
by: Arvicco
|
3
|
-
url: http://github.com/arvicco/
|
3
|
+
url: http://github.com/arvicco/win_gui
|
4
4
|
|
5
5
|
== DESCRIPTION:
|
6
6
|
|
@@ -12,30 +12,32 @@ In addition to straightforward API wrappers, it also defines more Ruby-like
|
|
12
12
|
abstractions and convenience methods for manipulating windows and other GUI
|
13
13
|
elements (such as WinGui::Window class and its methods).
|
14
14
|
|
15
|
-
It is still work in progress, only a small number of API functions wrapped so far...
|
15
|
+
It is still work in progress, only a small number of user32 API functions wrapped so far...
|
16
16
|
|
17
17
|
== SUMMARY
|
18
18
|
|
19
19
|
So you want to write a simple program that makes some Win32 API function calls.
|
20
|
-
You searched MSDN and you know what functions you
|
21
|
-
|
22
|
-
|
20
|
+
You searched MSDN high and low and you now know exactly what functions you need.
|
21
|
+
All you want is just putting those function calls into your Ruby code without too
|
22
|
+
much pain. You'd love this to be more or less natural extension of your Ruby code,
|
23
|
+
preferably not turning your code base into an ugly C++ like spaghetty
|
23
24
|
of CamelCase calls, String/Array pack/unpack gymnastics, buffer allocations,
|
24
25
|
extracting return values from [in/out] parameters and checking return codes for 0.
|
26
|
+
|
25
27
|
You can definitely use excellent 'win32-api' gem by Daniel J. Berger and Park Heesob
|
26
28
|
that allows you to define Win32 API objects for any function you can find on MSDN,
|
27
29
|
execute calls on them and even define callback objects that some of those API functions expect.
|
28
30
|
|
29
|
-
However,
|
31
|
+
However, that gem will only take you so far. You'll still have to handle (somewhat)
|
30
32
|
gory details of argument preparation, mimicking pointers with Strings and stuff.
|
31
33
|
For example, consider the amount of code needed to complete a task as simple as
|
32
34
|
getting unicode title text for the window that you already have handle for:
|
33
35
|
|
34
36
|
api = Win32::API.new( 'GetWindowTextW', ['L', 'P', 'I'], 'L', 'user32' )
|
35
|
-
buffer = "\x00" * 1024
|
37
|
+
buffer = "\x00" * 1024 # I just hope it will be enough...
|
36
38
|
num_chars = api.call( window_handle, buffer, buffer.size)
|
37
39
|
title = if num_chars == 0
|
38
|
-
nil
|
40
|
+
nil
|
39
41
|
else
|
40
42
|
buffer.force_encoding('utf-16LE').encode('utf-8').rstrip
|
41
43
|
end
|
@@ -45,7 +47,7 @@ Ew, ugly. What about getting information about process id for a known window?
|
|
45
47
|
api = Win32::API.new( 'GetWindowThreadProcessId', ['L', 'P'], 'L' , 'user32' )
|
46
48
|
process_packed = [1].pack('L')
|
47
49
|
thread = api.call(window_handle, process_packed)
|
48
|
-
process =
|
50
|
+
process = process_packed.unpack('L').first
|
49
51
|
|
50
52
|
Wow, packing and unpacking arrays into String to get hold of a simple integer id.
|
51
53
|
Just great. Now, wouldn't it be MUCH better if you can just say something like this:
|
@@ -57,9 +59,9 @@ What about API functions expecting callbacks? Well, something like this may be n
|
|
57
59
|
|
58
60
|
enum_child_windows( parent_handle, message ){|child_handle, message| puts child_handle }
|
59
61
|
|
60
|
-
If you think about it, callbacks are not much
|
61
|
-
|
62
|
-
|
62
|
+
If you think about it, callbacks are not much more than code blocks, so let's not be afraid
|
63
|
+
to treat them as such. It would be also good if test functions return true/false instead of
|
64
|
+
zero/nonzero, find functions return nil if nothing was found etc...
|
63
65
|
|
64
66
|
So this is an idea behind WinGui library - make Win32 API functions more fun to use
|
65
67
|
and feel more natural inside Ruby code. Following the principle of least surprise, we
|
@@ -70,7 +72,12 @@ Well, we even keep a backup solution for those diehard Win32 API longtimers who
|
|
70
72
|
allocate their buffer strings by hand and mess with obscure return codes. If you use original
|
71
73
|
CamelCase method name instead of Rubyesque snake_case one, it will expect those standard
|
72
74
|
parameters you know and love from MSDN, return your zeroes instead of nils and support no
|
73
|
-
other enhancements.
|
75
|
+
other enhancements.
|
76
|
+
|
77
|
+
And if you do not see your favorite Windows API function amoung those already defined, it is
|
78
|
+
quite easy to define new one with def_api class method that does a lot of heavy lifting for
|
79
|
+
you and can be customized with options and code blocks to give you reusable API wrapper method
|
80
|
+
with the exact behavior you need.
|
74
81
|
|
75
82
|
== DOCUMENTATION:
|
76
83
|
|
@@ -83,7 +90,7 @@ arguments given to block, etc...)
|
|
83
90
|
|
84
91
|
== FEATURES/PROBLEMS:
|
85
92
|
|
86
|
-
This project is quite new, so it
|
93
|
+
This project is quite new, so it may be not suitable for production-quality systems yet.
|
87
94
|
Contributors always welcome!
|
88
95
|
|
89
96
|
== INSTALL:
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.4
|
data/lib/win_gui/def_api.rb
CHANGED
@@ -33,37 +33,53 @@ module WinGui
|
|
33
33
|
# :zeronil:: Forces method to return nil if function result is zero
|
34
34
|
#
|
35
35
|
def def_api(function, params, returns, options={}, &define_block)
|
36
|
+
name, aliases = generate_names(function, options)
|
37
|
+
boolean = options[:boolean]
|
38
|
+
zeronil = options[:zeronil]
|
39
|
+
proto = params.respond_to?(:join) ? params.join : params # Convert params into prototype string
|
40
|
+
api = Win32::API.new(function, proto.upcase, returns.upcase, options[:dll] || DEFAULT_DLL)
|
41
|
+
|
42
|
+
define_method(function) {|*args| api.call(*args)} # define CamelCase method wrapper for api call
|
43
|
+
|
44
|
+
define_method(name) do |*args, &runtime_block| # define snake_case method with enhanced api
|
45
|
+
return api if args == [:api]
|
46
|
+
return define_block[api, *args, &runtime_block] if define_block
|
47
|
+
WinGui.enforce_count(args, proto)
|
48
|
+
result = api.call(*args)
|
49
|
+
result = runtime_block[result] if runtime_block
|
50
|
+
return result != 0 if boolean # Boolean function returns true/false instead of nonzero/zero
|
51
|
+
return nil if zeronil && result == 0 # Zeronil function returns nil instead of zero
|
52
|
+
result
|
53
|
+
end
|
54
|
+
aliases.each {|ali| alias_method ali, name } # define aliases
|
55
|
+
end
|
56
|
+
|
57
|
+
# Generates name and aliases for defined method based on function name,
|
58
|
+
# sets boolean flag for test functions (Is...)
|
59
|
+
#
|
60
|
+
def generate_names(function, options)
|
36
61
|
aliases = ([options[:alias]] + [options[:aliases]]).flatten.compact
|
37
62
|
name = options[:rename] || function.snake_case
|
38
63
|
case name
|
39
64
|
when /^is_/
|
40
65
|
aliases << name.sub(/^is_/, '') + '?'
|
41
|
-
boolean = true
|
66
|
+
options[:boolean] = true
|
42
67
|
when /^set_/
|
43
68
|
aliases << name.sub(/^set_/, '')+ '='
|
44
69
|
when /^get_/
|
45
70
|
aliases << name.sub(/^get_/, '')
|
46
71
|
end
|
47
|
-
|
48
|
-
|
49
|
-
proto = params.respond_to?(:join) ? params.join : params # Converts params into prototype string
|
50
|
-
api = Win32::API.new(function, proto.upcase, returns.upcase, options[:dll] || DEFAULT_DLL)
|
51
|
-
|
52
|
-
define_method(function) {|*args| api.call(*args)} # defines CamelCase method wrapper for api call
|
72
|
+
[name, aliases]
|
73
|
+
end
|
53
74
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
result = runtime_block[result] if runtime_block
|
62
|
-
return result != 0 if boolean # Boolean function returns true/false instead of nonzero/zero
|
63
|
-
return nil if zeronil && result == 0
|
64
|
-
result
|
75
|
+
# Ensures that args count is equal to params count plus diff
|
76
|
+
#
|
77
|
+
def enforce_count(args, params, diff = 0)
|
78
|
+
num_args = args.size
|
79
|
+
num_params = params == 'V' ? 0 : params.size + diff
|
80
|
+
if num_args != num_params
|
81
|
+
raise ArgumentError, "wrong number of parameters: expected #{num_params}, got #{num_args}"
|
65
82
|
end
|
66
|
-
aliases.each {|ali| alias_method ali, name } unless aliases == []
|
67
83
|
end
|
68
84
|
|
69
85
|
# Converts block into API::Callback object that can be used as API callback argument
|
@@ -80,15 +96,19 @@ module WinGui
|
|
80
96
|
code * size
|
81
97
|
end
|
82
98
|
|
99
|
+
# Returns array of given args if none of them is zero,
|
100
|
+
# if any arg is zero, returns array of nils
|
101
|
+
#
|
102
|
+
def nonzero_array(*args)
|
103
|
+
args.any?{|arg| arg == 0 } ? args.map{||nil} : args
|
104
|
+
end
|
105
|
+
|
83
106
|
# Procedure that returns (possibly encoded) string as a result of api function call
|
84
107
|
# or nil if zero characters was returned by api call
|
85
108
|
#
|
86
109
|
def return_string( encode = nil )
|
87
110
|
lambda do |api, *args|
|
88
|
-
|
89
|
-
unless args.size == num_params
|
90
|
-
raise ArgumentError, "wrong number of parameters: expected #{num_params}, got #{args.size}"
|
91
|
-
end
|
111
|
+
WinGui.enforce_count( args, api.prototype, -2)
|
92
112
|
args += [string = buffer, string.length]
|
93
113
|
num_chars = api.call(*args)
|
94
114
|
return nil if num_chars == 0
|
@@ -103,10 +123,7 @@ module WinGui
|
|
103
123
|
#
|
104
124
|
def return_enum
|
105
125
|
lambda do |api, *args, &block|
|
106
|
-
|
107
|
-
unless args.size == num_params
|
108
|
-
raise ArgumentError, "wrong number of parameters: expected #{num_params}, got #{args.size}"
|
109
|
-
end
|
126
|
+
WinGui.enforce_count( args, api.prototype, -1)
|
110
127
|
handles = []
|
111
128
|
cb = if block
|
112
129
|
callback('LP', 'I', &block)
|
@@ -131,10 +148,9 @@ module WinGui
|
|
131
148
|
lambda do |api, id=0, cmd, &block|
|
132
149
|
raise ArgumentError, 'No callback block' unless block
|
133
150
|
callback = callback 'IIPPPPPP', 'L', &block
|
134
|
-
id = [id].pack('L')
|
135
151
|
|
136
|
-
status = api.call(id, callback, cmd, 0)
|
137
|
-
|
152
|
+
status = api.call(id = [id].pack('L'), callback, cmd, 0)
|
153
|
+
nonzero_array(*id.unpack('L'), status)
|
138
154
|
end
|
139
155
|
end
|
140
156
|
|
data/lib/win_gui/win_gui.rb
CHANGED
@@ -15,7 +15,6 @@ require 'window'
|
|
15
15
|
module WinGui
|
16
16
|
extend DefApi
|
17
17
|
|
18
|
-
|
19
18
|
# Windows GUI API definitions:
|
20
19
|
|
21
20
|
##
|
@@ -78,7 +77,7 @@ module WinGui
|
|
78
77
|
# title matches the win_title parameter.
|
79
78
|
# win_name (P) - String that specifies the window name (title). If nil, all names match.
|
80
79
|
# Return Value (L): found window handle or NIL if nothing found
|
81
|
-
|
80
|
+
#
|
82
81
|
# :call-seq:
|
83
82
|
# win_handle = find_window( class_name, win_name )
|
84
83
|
#
|
@@ -107,7 +106,7 @@ module WinGui
|
|
107
106
|
# win_class (P), win_title (P) - Strings that specify window class and name(title). If nil, anything matches.
|
108
107
|
# Returns (L): found child window handle or NIL if nothing found
|
109
108
|
#
|
110
|
-
|
109
|
+
# :call-seq:
|
111
110
|
# win_handle = find_window_ex( win_handle, after_child, class_name, win_name )
|
112
111
|
#
|
113
112
|
def_api 'FindWindowEx', 'LLPP', 'L', zeronil: true
|
@@ -221,7 +220,7 @@ module WinGui
|
|
221
220
|
SW_SHOWMINIMIZED = 2
|
222
221
|
# Activates the window and displays it as a maximized window.
|
223
222
|
SW_SHOWMAXIMIZED = 3
|
224
|
-
#
|
223
|
+
# Activates the window and displays it as a maximized window.
|
225
224
|
SW_MAXIMIZE = 3
|
226
225
|
# Displays a window in its most recent size and position. Similar to SW_SHOWNORMAL, but the window is not activated.
|
227
226
|
SW_SHOWNOACTIVATE = 4
|
@@ -243,8 +242,15 @@ module WinGui
|
|
243
242
|
# flag when minimizing windows from a different thread.
|
244
243
|
SW_FORCEMINIMIZE = 11
|
245
244
|
|
246
|
-
|
247
|
-
|
245
|
+
# Hides the window and activates another window
|
246
|
+
def hide_window(win_handle)
|
247
|
+
show_window(win_handle, SW_HIDE)
|
248
|
+
end
|
249
|
+
|
250
|
+
return_thread_process = lambda do |api, *args|
|
251
|
+
WinGui.enforce_count( args, api.prototype, -1)
|
252
|
+
thread = api.call(args.first, process = [1].pack('L'))
|
253
|
+
nonzero_array(thread, *process.unpack('L'))
|
248
254
|
end
|
249
255
|
|
250
256
|
##
|
@@ -265,10 +271,13 @@ module WinGui
|
|
265
271
|
#:call-seq:
|
266
272
|
# thread, process_id = get_window_tread_process_id( win_handle )
|
267
273
|
#
|
268
|
-
def_api 'GetWindowThreadProcessId', 'LP', 'L'
|
269
|
-
|
270
|
-
|
271
|
-
|
274
|
+
def_api 'GetWindowThreadProcessId', 'LP', 'L', &return_thread_process
|
275
|
+
|
276
|
+
return_rect = lambda do |api, *args|
|
277
|
+
WinGui.enforce_count( args, api.prototype, -1)
|
278
|
+
rectangle = [0, 0, 0, 0].pack('L*')
|
279
|
+
res = api.call args.first, rectangle
|
280
|
+
res == 0 ? [nil, nil, nil, nil] : rectangle.unpack('L*')
|
272
281
|
end
|
273
282
|
|
274
283
|
##
|
@@ -293,12 +302,7 @@ module WinGui
|
|
293
302
|
#:call-seq:
|
294
303
|
# rect = get_window_rect( win_handle )
|
295
304
|
#
|
296
|
-
def_api 'GetWindowRect', 'LP', 'I'
|
297
|
-
raise 'Invalid args count' unless args.size == api.prototype.size-1
|
298
|
-
rectangle = [0, 0, 0, 0].pack 'L*'
|
299
|
-
api.call args.first, rectangle
|
300
|
-
rectangle.unpack 'L*'
|
301
|
-
end
|
305
|
+
def_api 'GetWindowRect', 'LP', 'I', &return_rect
|
302
306
|
|
303
307
|
##
|
304
308
|
# The EnumWindows function enumerates all top-level windows on the screen by passing the handle to
|
@@ -356,9 +360,43 @@ module WinGui
|
|
356
360
|
#
|
357
361
|
#:call-seq:
|
358
362
|
# enum_windows( parent_handle, message ) {|win_handle, message| callback procedure }
|
363
|
+
#
|
359
364
|
def_api 'EnumChildWindows', 'LKP', 'L', &return_enum
|
360
365
|
|
366
|
+
##
|
367
|
+
# GetForegroundWindow function returns a handle to the foreground window (the window with which the user
|
368
|
+
# is currently working). The system assigns a slightly higher priority to the thread that creates the
|
369
|
+
# foreground window than it does to other threads.
|
370
|
+
#
|
371
|
+
# Syntax: HWND GetForegroundWindow(VOID);
|
372
|
+
#
|
373
|
+
# Return Value: The return value is a handle to the foreground window. The foreground window can be NULL in
|
374
|
+
# certain circumstances, such as when a window is losing activation.
|
375
|
+
#
|
376
|
+
#:call-seq:
|
377
|
+
# win_handle = (get_)foreground_window()
|
378
|
+
#
|
361
379
|
def_api 'GetForegroundWindow', 'V', 'L'
|
380
|
+
|
381
|
+
def foreground?(win_handle)
|
382
|
+
win_handle == foreground_window
|
383
|
+
end
|
384
|
+
|
385
|
+
##
|
386
|
+
# The GetActiveWindow function retrieves the window handle to the active window attached to
|
387
|
+
# the calling thread's message queue.
|
388
|
+
#
|
389
|
+
# Syntax: HWND GetActiveWindow(VOID);
|
390
|
+
#
|
391
|
+
# Return Value: The return value is the handle to the active window attached to the calling
|
392
|
+
# thread's message queue. Otherwise, the return value is NULL.
|
393
|
+
#
|
394
|
+
# Remarks: To get the handle to the foreground window, you can use GetForegroundWindow.
|
395
|
+
# To get the window handle to the active window in the message queue for another thread, use GetGUIThreadInfo.
|
396
|
+
#
|
397
|
+
#:call-seq:
|
398
|
+
# win_handle = (get_)active_window()
|
399
|
+
#
|
362
400
|
def_api 'GetActiveWindow', 'V', 'L'
|
363
401
|
|
364
402
|
def_api 'keybd_event', 'IILL', 'V'
|
data/spec/spec_helper.rb
CHANGED
@@ -38,6 +38,7 @@ module GuiTest
|
|
38
38
|
TEST_MAX_RECT = [-4, -4, 1924, 1204] # on my 1920x1200 display
|
39
39
|
TEST_MIN_RECT = [-32000, -32000, -31840, -31976]
|
40
40
|
TEST_TEXTAREA_CLASS = 'ATL:00434310'
|
41
|
+
TEST_STATUSBAR_CLASS = 'msctls_statusbar32'
|
41
42
|
TEST_IMPOSSIBLE = 'Impossible'
|
42
43
|
TEST_ERROR_CONVERSION = /Can.t convert/
|
43
44
|
|
@@ -60,23 +61,29 @@ module GuiTest
|
|
60
61
|
end
|
61
62
|
|
62
63
|
def hide_method(*names) # hide original method(s) if it is defined
|
63
|
-
names.each do |name|
|
64
|
+
names.map(&:to_s).each do |name|
|
64
65
|
WinGui.module_eval do
|
65
|
-
|
66
|
-
|
67
|
-
|
66
|
+
aliases = generate_names(name, {}).flatten + [name]
|
67
|
+
aliases.map(&:to_s).each do |ali|
|
68
|
+
if method_defined? ali
|
69
|
+
alias_method "orig_#{ali}".to_sym, ali
|
70
|
+
remove_method ali
|
71
|
+
end
|
68
72
|
end
|
69
73
|
end
|
70
74
|
end
|
71
75
|
end
|
72
76
|
|
73
77
|
def restore_method(*names) # restore original method if it was hidden
|
74
|
-
names.each do |name|
|
78
|
+
names.map(&:to_s).each do |name|
|
75
79
|
WinGui.module_eval do
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
+
aliases = generate_names(name, {}).flatten + [name]
|
81
|
+
aliases.map(&:to_s).each do |ali|
|
82
|
+
temp = "orig_#{ali}".to_sym
|
83
|
+
if method_defined? temp
|
84
|
+
alias_method ali, temp
|
85
|
+
remove_method temp
|
86
|
+
end
|
80
87
|
end
|
81
88
|
end
|
82
89
|
end
|
@@ -13,14 +13,14 @@ module GuiTest
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def redefined_methods
|
16
|
-
[:
|
16
|
+
[:FindWindow, :IsWindow, :EnumWindows, :GetComputerName, :GetForegroundWindow]
|
17
17
|
end
|
18
18
|
|
19
19
|
def should_count_args(*methods, rights, wrongs)
|
20
20
|
rights = [rights].flatten
|
21
21
|
wrongs = [wrongs].flatten
|
22
22
|
methods.each do |method|
|
23
|
-
(
|
23
|
+
(0..8).each do |n|
|
24
24
|
if n == rights.size
|
25
25
|
expect {send method, *rights}.to_not raise_error
|
26
26
|
else
|
@@ -302,6 +302,21 @@ module GuiTest
|
|
302
302
|
end
|
303
303
|
end
|
304
304
|
|
305
|
+
context 'defining API function without arguments - f(VOID)' do
|
306
|
+
it 'should enforce argument count to 0, NOT 1 (enhanced methods)' do
|
307
|
+
WinGui.def_api 'GetForegroundWindow', 'V', 'L', zeronil: true
|
308
|
+
should_count_args :get_foreground_window, :foreground_window, [], [nil, 0, 123]
|
309
|
+
end
|
310
|
+
|
311
|
+
it 'should NOT enforce argument count (raw method)' do
|
312
|
+
WinGui.def_api 'GetForegroundWindow', 'V', 'L', zeronil: true
|
313
|
+
expect {GetForegroundWindow()}.to_not raise_error
|
314
|
+
expect {GetForegroundWindow(nil)}.to_not raise_error
|
315
|
+
expect {GetForegroundWindow(1,2)}.to_not raise_error
|
316
|
+
expect {GetForegroundWindow(1,2,3)}.to_not raise_error
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
305
320
|
context 'working with API function callbacks' do
|
306
321
|
it '#callback method creates a valid callback object' do
|
307
322
|
expect { @callback = WinGui.callback('LP', 'I') {|handle, message| true} }.to_not raise_error
|
@@ -1,41 +1,64 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), "..", "spec_helper" )
|
2
2
|
|
3
3
|
module GuiTest
|
4
|
+
def test_show_window *cmds, tests
|
5
|
+
cmds.each do |cmd|
|
6
|
+
test_app do |app|
|
7
|
+
show_window(app.handle, cmd)
|
8
|
+
tests.each{|test, result| send(test.to_sym, app.handle).should == result}
|
9
|
+
|
10
|
+
hide_window(app.handle) # hiding window first
|
11
|
+
show_window(app.handle, cmd)
|
12
|
+
tests.each{|test, result| send(test.to_sym, app.handle).should == result}
|
13
|
+
|
14
|
+
show_window(app.handle, SW_MAXIMIZE) # now maximizing window
|
15
|
+
show_window(app.handle, cmd)
|
16
|
+
tests.each{|test, result| send(test.to_sym, app.handle).should == result}
|
17
|
+
|
18
|
+
show_window(app.handle, SW_MINIMIZE) # now minimizing window
|
19
|
+
show_window(app.handle, cmd)
|
20
|
+
tests.each{|test, result| send(test.to_sym, app.handle).should == result}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
4
25
|
describe WinGui, ' contains a set of pre-defined GUI functions' do
|
5
26
|
describe '#window?' do
|
6
|
-
spec{ use{
|
27
|
+
spec{ use{ IsWindow(any_handle) }}
|
28
|
+
spec{ use{ is_window(any_handle) }}
|
29
|
+
spec{ use{ window?(any_handle) }}
|
7
30
|
|
8
31
|
it 'returns true if window exists' do
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
32
|
+
window?(any_handle).should == true
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'returns false for invalid window handle' do
|
36
|
+
window?(not_a_handle).should == false
|
13
37
|
end
|
14
38
|
|
15
|
-
it '
|
39
|
+
it 'changes from true to false when existing window is closed' do
|
16
40
|
test_app do |app|
|
17
41
|
@app_handle = app.handle
|
18
42
|
@ta_handle = app.textarea.handle
|
43
|
+
window?(@app_handle).should == true
|
44
|
+
window?(@ta_handle).should == true
|
19
45
|
end
|
20
46
|
window?(@app_handle).should == false
|
21
47
|
window?(@ta_handle).should == false
|
22
48
|
end
|
23
49
|
end
|
24
50
|
|
25
|
-
describe '#window_visible?' do
|
26
|
-
spec{ use{
|
27
|
-
spec{ use{
|
51
|
+
describe '#window_visible?' do
|
52
|
+
spec{ use{ IsWindowVisible(any_handle) }}
|
53
|
+
spec{ use{ is_window_visible(any_handle) }}
|
54
|
+
spec{ use{ window_visible?(any_handle) }}
|
55
|
+
spec{ use{ visible?(any_handle) }}
|
28
56
|
|
29
|
-
it 'returns true
|
57
|
+
it 'returns true when window is visible, false when window is hidden' do
|
30
58
|
test_app do |app|
|
31
59
|
visible?(app.handle).should == true
|
32
60
|
window_visible?(app.handle).should == true
|
33
61
|
window_visible?(app.textarea.handle).should == true
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
it 'returns false if window is not visible' do
|
38
|
-
test_app do |app|
|
39
62
|
hide_window(app.handle)
|
40
63
|
visible?(app.handle).should == false
|
41
64
|
window_visible?(app.handle).should == false
|
@@ -45,19 +68,15 @@ module GuiTest
|
|
45
68
|
end
|
46
69
|
|
47
70
|
describe '#maximized?' do
|
48
|
-
spec{ use{
|
49
|
-
spec{ use{
|
50
|
-
|
71
|
+
spec{ use{ IsZoomed(any_handle) }}
|
72
|
+
spec{ use{ is_zoomed(any_handle) }}
|
73
|
+
spec{ use{ zoomed?(any_handle) }}
|
74
|
+
spec{ use{ maximized?(any_handle) }}
|
51
75
|
|
52
|
-
it 'returns
|
76
|
+
it 'returns true if the window is maximized, false otherwise' do
|
53
77
|
test_app do |app|
|
54
78
|
zoomed?(app.handle).should == false
|
55
79
|
maximized?(app.handle).should == false
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
it 'returns true if the window is maximized' do
|
60
|
-
test_app do |app|
|
61
80
|
show_window(app.handle, SW_MAXIMIZE)
|
62
81
|
maximized?(app.handle).should == true
|
63
82
|
zoomed?(app.handle).should == true
|
@@ -66,19 +85,15 @@ module GuiTest
|
|
66
85
|
end
|
67
86
|
|
68
87
|
describe '#minimized?' do
|
69
|
-
spec{ use{
|
70
|
-
spec{ use{
|
71
|
-
|
88
|
+
spec{ use{ IsIconic(any_handle) }}
|
89
|
+
spec{ use{ is_iconic(any_handle) }}
|
90
|
+
spec{ use{ iconic?(any_handle) }}
|
91
|
+
spec{ use{ minimized?(any_handle) }}
|
72
92
|
|
73
|
-
it 'returns
|
93
|
+
it 'returns true if the window is minimized, false otherwise' do
|
74
94
|
test_app do |app|
|
75
95
|
iconic?(app.handle).should == false
|
76
96
|
minimized?(app.handle).should == false
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
it 'returns true if the window is minimized' do
|
81
|
-
test_app do |app|
|
82
97
|
show_window(app.handle, SW_MINIMIZE)
|
83
98
|
iconic?(app.handle).should == true
|
84
99
|
minimized?(app.handle).should == true
|
@@ -87,74 +102,57 @@ module GuiTest
|
|
87
102
|
end
|
88
103
|
|
89
104
|
describe '#child?' do
|
105
|
+
spec{ use{ IsChild(parent_handle = any_handle, handle = any_handle) }}
|
106
|
+
spec{ use{ is_child(parent_handle = any_handle, handle = any_handle) }}
|
90
107
|
spec{ use{ child?(parent_handle = any_handle, handle = any_handle) }}
|
91
|
-
# Tests whether a window is a child (or descendant) window of a specified parent window. A child window is the direct descendant
|
92
|
-
# of a specified parent window if that parent window is in the chain of parent windows; the chain of parent windows leads from
|
93
|
-
# the original overlapped or pop-up window to the child window.
|
94
108
|
|
95
|
-
it 'returns true if the window is a child' do
|
109
|
+
it 'returns true if the window is a child of given parent, false otherwise' do
|
96
110
|
test_app do |app|
|
97
111
|
child?(app.handle, app.textarea.handle).should == true
|
98
|
-
end
|
99
|
-
end
|
100
|
-
it 'returns false if window is not a child' do
|
101
|
-
test_app do |app|
|
102
112
|
child?(app.handle, any_handle).should == false
|
103
113
|
end
|
104
114
|
end
|
105
115
|
end
|
106
116
|
|
107
|
-
describe '#find_window' do
|
117
|
+
describe '#find_window(w)' do
|
118
|
+
spec{ use{ FindWindow(class_name = nil, win_name = nil) }}
|
108
119
|
spec{ use{ find_window(class_name = nil, win_name = nil) }}
|
120
|
+
# Widebyte (unicode) version
|
121
|
+
spec{ use{ FindWindowW(class_name = nil, win_name = nil) }}
|
122
|
+
spec{ use{ find_window_w(class_name = nil, win_name = nil) }}
|
109
123
|
|
110
124
|
it 'returns either Integer Window handle or nil' do
|
111
125
|
find_window(nil, nil).should be_a_kind_of Integer
|
112
|
-
|
126
|
+
find_window(TEST_IMPOSSIBLE, nil).should == nil
|
113
127
|
end
|
114
128
|
|
115
129
|
it 'returns nil if Window is not found' do
|
116
130
|
find_window(TEST_IMPOSSIBLE, nil).should == nil
|
117
131
|
find_window(nil, TEST_IMPOSSIBLE).should == nil
|
118
132
|
find_window(TEST_IMPOSSIBLE, TEST_IMPOSSIBLE).should == nil
|
119
|
-
end
|
120
|
-
|
121
|
-
it 'finds at least one window if both args are nils' do
|
122
|
-
find_window(nil, nil).should_not == nil
|
123
|
-
end
|
124
|
-
|
125
|
-
it 'finds top-level window by window class' do
|
126
|
-
test_app {|app| find_window(TEST_WIN_CLASS, nil).should == app.handle }
|
127
|
-
end
|
128
|
-
|
129
|
-
it 'finds top-level window by title' do
|
130
|
-
test_app {|app| find_window(nil, TEST_WIN_TITLE).should == app.handle }
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
describe '#find_window_w' do
|
135
|
-
spec{ use{ find_window_w(class_name = nil, win_name = nil) }}
|
136
|
-
|
137
|
-
it 'returns zero if Window is not found' do
|
138
133
|
find_window_w(TEST_IMPOSSIBLE, nil).should == nil
|
139
134
|
find_window_w(nil, TEST_IMPOSSIBLE).should == nil
|
140
135
|
find_window_w(TEST_IMPOSSIBLE, TEST_IMPOSSIBLE).should == nil
|
141
136
|
end
|
142
137
|
|
143
|
-
it 'finds at least one window if
|
138
|
+
it 'finds at least one window if both args are nils' do
|
139
|
+
find_window(nil, nil).should_not == nil
|
144
140
|
find_window_w(nil, nil).should_not == nil
|
145
141
|
end
|
146
142
|
|
147
|
-
it 'finds top-level window by window class' do
|
148
|
-
test_app
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
143
|
+
it 'finds top-level window by window class or title' do
|
144
|
+
test_app do |app|
|
145
|
+
find_window(TEST_WIN_CLASS, nil).should == app.handle
|
146
|
+
find_window(nil, TEST_WIN_TITLE).should == app.handle
|
147
|
+
find_window_w(TEST_WIN_CLASS.to_w, nil).should == app.handle
|
148
|
+
find_window_w(nil, TEST_WIN_TITLE.to_w).should == app.handle
|
149
|
+
end
|
153
150
|
end
|
154
151
|
end
|
155
152
|
|
156
153
|
describe '#find_window_ex' do
|
157
|
-
spec{ use{
|
154
|
+
spec{ use{ FindWindowEx(parent = any_handle, after_child = 0, win_class = nil, win_title = nil) }}
|
155
|
+
spec{ use{ find_window_ex(parent = any_handle, after_child = 0, win_class = nil, win_title = nil) }}
|
158
156
|
|
159
157
|
it 'returns nil if wrong control is given' do
|
160
158
|
parent_handle = any_handle
|
@@ -182,67 +180,115 @@ module GuiTest
|
|
182
180
|
end
|
183
181
|
end
|
184
182
|
|
185
|
-
describe '#
|
186
|
-
|
187
|
-
|
183
|
+
describe '#get_foreground_window' do
|
184
|
+
# ! Different from GetActiveWindow !
|
185
|
+
spec{ use{ handle = GetForegroundWindow() }}
|
186
|
+
spec{ use{ handle = get_foreground_window }}
|
187
|
+
spec{ use{ handle = foreground_window }}
|
188
188
|
|
189
|
-
it 'returns
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
189
|
+
it 'returns handle to window that is currently in foreground' do
|
190
|
+
test_app do |app|
|
191
|
+
@app_handle = app.handle
|
192
|
+
fg1 = foreground_window
|
193
|
+
@app_handle.should == fg1
|
194
|
+
end
|
195
|
+
fg2 = foreground_window
|
196
|
+
@app_handle.should_not == fg2
|
195
197
|
end
|
196
|
-
end
|
197
|
-
|
198
|
-
describe '#get_window_text' do
|
199
|
-
spec{ use{ text = get_window_text(handle = 0)}}
|
200
|
-
# Improved with block to accept window handle as a single arg and return (rstripped) text string
|
201
198
|
|
202
|
-
it '
|
203
|
-
|
199
|
+
it 'defines #foreground? test function ' do
|
200
|
+
test_app do |app|
|
201
|
+
@app_handle = app.handle
|
202
|
+
foreground?(@app_handle).should == true
|
203
|
+
end
|
204
|
+
foreground?(@app_handle).should == false
|
204
205
|
end
|
206
|
+
end
|
205
207
|
|
206
|
-
|
207
|
-
|
208
|
+
describe '#get_active_window' do
|
209
|
+
# ! Different from GetForegroundWindow !
|
210
|
+
spec{ use{ handle = GetActiveWindow() }}
|
211
|
+
spec{ use{ handle = get_active_window }}
|
212
|
+
spec{ use{ handle = active_window }}
|
213
|
+
|
214
|
+
it 'returns handle to the active window attached to the calling thread`s message queue' do
|
215
|
+
pending 'No idea how to test it'
|
216
|
+
test_app do |app|
|
217
|
+
@app_handle = app.handle
|
218
|
+
fg1 = active_window
|
219
|
+
@app_handle.should == fg1
|
220
|
+
end
|
221
|
+
fg2 = active_window
|
222
|
+
@app_handle.should_not == fg2
|
208
223
|
end
|
209
224
|
end
|
210
225
|
|
211
|
-
describe '#
|
212
|
-
spec{ use{
|
226
|
+
describe '#get_window_text(w)' do
|
227
|
+
spec{ use{ GetWindowText(any_handle, buffer = "\00"* 1024, buffer.size)}}
|
228
|
+
# Improved with block to accept window handle as a single arg and return (rstripped) text string
|
229
|
+
spec{ use{ text = get_window_text(handle = 0)}}
|
213
230
|
# Unicode version of get_window_text (strings returned encoded as utf-8)
|
231
|
+
spec{ use{ GetWindowTextW(any_handle, buffer = "\00"* 1024, buffer.size)}}
|
232
|
+
spec{ use{ text = get_window_text_w(any_handle)}} # result encoded as utf-8
|
214
233
|
|
215
234
|
it 'returns nil if incorrect window handle given' do
|
216
|
-
get_window_text(
|
235
|
+
get_window_text(not_a_handle).should == nil
|
236
|
+
get_window_text_w(not_a_handle).should == nil
|
217
237
|
end
|
218
238
|
|
219
239
|
it 'returns correct window text' do
|
220
|
-
test_app
|
240
|
+
test_app do |app|
|
241
|
+
get_window_text(app.handle).should == TEST_WIN_TITLE
|
242
|
+
get_window_text_w(app.handle).should == TEST_WIN_TITLE
|
243
|
+
end
|
221
244
|
end
|
222
245
|
end
|
223
246
|
|
224
|
-
describe '#get_class_name' do
|
225
|
-
spec{ use{
|
226
|
-
# Improved with block to accept window handle as a single arg and return class name string
|
247
|
+
describe '#get_class_name(w)' do
|
248
|
+
spec{ use{ GetClassName(any_handle, buffer = "\00"* 1024, buffer.size)}}
|
249
|
+
# Improved with block to accept window handle as a single arg and return class name string
|
250
|
+
spec{ use{ class_name = get_class_name(any_handle)}}
|
251
|
+
# Unicode version of get_class_name (strings returned encoded as utf-8)
|
252
|
+
spec{ use{ GetClassNameW(any_handle, buffer = "\00"* 1024, buffer.size)}}
|
253
|
+
spec{ use{ class_name = get_class_name_w(handle = 0)}} # result encoded as utf-8
|
227
254
|
|
228
255
|
it 'returns correct window class name' do
|
229
|
-
test_app
|
256
|
+
test_app do |app|
|
257
|
+
get_class_name(app.handle).should == TEST_WIN_CLASS
|
258
|
+
get_class_name_w(app.handle).should == TEST_WIN_CLASS
|
259
|
+
end
|
230
260
|
end
|
231
261
|
end
|
232
262
|
|
233
|
-
describe '#
|
234
|
-
spec{ use{
|
235
|
-
|
263
|
+
describe '#get_window_thread_process_id' do
|
264
|
+
spec{ use{ thread = GetWindowThreadProcessId(any_handle, process_buffer = [1].pack('L')) }}
|
265
|
+
spec{ use{ thread, process = get_window_thread_process_id(any_handle) }}
|
266
|
+
# Improved with block to accept window handle as a single arg and return a pair of [thread, process]
|
236
267
|
|
237
|
-
it 'returns
|
238
|
-
|
268
|
+
it 'returns a pair of nonzero Integer ids (thread and process) for valid window' do
|
269
|
+
thread, process = get_window_thread_process_id(any_handle)
|
270
|
+
thread.should be_a_kind_of Integer
|
271
|
+
thread.should be > 0
|
272
|
+
process.should be_a_kind_of Integer
|
273
|
+
process.should be > 0
|
274
|
+
end
|
275
|
+
|
276
|
+
it 'returns a pair of nils (thread and process) for invalid window' do
|
277
|
+
thread, process = get_window_thread_process_id(not_a_handle)
|
278
|
+
thread.should == nil
|
279
|
+
process.should == nil
|
239
280
|
end
|
240
281
|
end
|
241
282
|
|
242
283
|
describe '#get_window_rect' do
|
284
|
+
spec{ use{ success = GetWindowRect(any_handle, rectangle = [0, 0, 0, 0].pack('L*'))}}
|
243
285
|
spec{ use{ left, top, right, bottom = get_window_rect(any_handle)}}
|
244
286
|
|
245
|
-
it 'returns
|
287
|
+
it 'returns array of nils for invalid window' do
|
288
|
+
get_window_rect(not_a_handle).should == [nil, nil, nil, nil]
|
289
|
+
end
|
290
|
+
|
291
|
+
it 'returns window`s border rectangle' do
|
246
292
|
test_app do |app|
|
247
293
|
get_window_rect(app.handle).should == TEST_WIN_RECT
|
248
294
|
end
|
@@ -252,84 +298,66 @@ module GuiTest
|
|
252
298
|
describe '#show_window ', 'LI', 'I' do
|
253
299
|
spec{ use{ was_visible = show_window(handle = any_handle, cmd = SW_SHOWNA) }}
|
254
300
|
|
255
|
-
it 'was_visible = hide_window(handle = any_handle) #
|
301
|
+
it 'was_visible = hide_window(handle = any_handle) # derived method (not a separate API function)' do
|
256
302
|
test_app do |app|
|
257
|
-
use{ hide_window(app.handle) }
|
303
|
+
use{ @was_visible = hide_window(app.handle) }
|
304
|
+
@was_visible.should == true
|
305
|
+
visible?(app.handle).should == false
|
306
|
+
hide_window(app.handle).should == false
|
258
307
|
visible?(app.handle).should == false
|
259
308
|
end
|
260
309
|
end
|
261
310
|
|
262
|
-
it 'returns true if the window was PREVIOUSLY visible' do
|
263
|
-
test_app {|app| show_window(app.handle, SW_HIDE).should == true }
|
264
|
-
end
|
265
|
-
|
266
|
-
it 'returns false if the window was PREVIOUSLY not visible' do
|
311
|
+
it 'returns true if the window was PREVIOUSLY visible, false otherwise' do
|
267
312
|
test_app do |app|
|
268
|
-
show_window(app.handle, SW_HIDE)
|
313
|
+
show_window(app.handle, SW_HIDE).should == true
|
269
314
|
show_window(app.handle, SW_HIDE).should == false
|
270
315
|
end
|
271
316
|
end
|
272
317
|
|
273
|
-
it 'SW_HIDE command
|
318
|
+
it 'hides window with SW_HIDE command ' do
|
274
319
|
test_app do |app|
|
275
320
|
show_window(app.handle, SW_HIDE)
|
276
321
|
visible?(app.handle).should == false
|
277
322
|
end
|
278
323
|
end
|
279
324
|
|
280
|
-
it '
|
325
|
+
it 'shows hidden window with SW_SHOW command' do
|
281
326
|
test_app do |app|
|
282
|
-
|
327
|
+
hide_window(app.handle)
|
283
328
|
show_window(app.handle, SW_SHOW)
|
284
329
|
visible?(app.handle).should == true
|
285
330
|
end
|
286
331
|
end
|
287
332
|
|
288
|
-
it 'SW_MAXIMIZE
|
289
|
-
|
290
|
-
|
291
|
-
maximized?(app.handle).should == true
|
292
|
-
end
|
293
|
-
pending 'Need to make sure window is maximized but NOT activated '
|
333
|
+
it 'SW_MAXIMIZE, SW_SHOWMAXIMIZED maximize window and activate it' do
|
334
|
+
test_show_window SW_MAXIMIZE, SW_SHOWMAXIMIZED,
|
335
|
+
:minimized? => false, :maximized? => true, :visible? => true, :foreground? => true
|
294
336
|
end
|
295
337
|
|
296
338
|
it 'SW_MINIMIZE minimizes window and activates the next top-level window in the Z order' do
|
297
|
-
|
298
|
-
|
299
|
-
minimized?(app.handle).should == true
|
300
|
-
end
|
339
|
+
test_show_window SW_MINIMIZE,
|
340
|
+
:minimized? => true, :maximized? => false, :visible? => true, :foreground? => false
|
301
341
|
end
|
302
342
|
|
303
|
-
it '
|
304
|
-
|
305
|
-
|
306
|
-
show_window(app.handle, SW_SHOWMAXIMIZED)
|
307
|
-
get_window_rect(app.handle)
|
308
|
-
#.should == TEST_MAX_RECT
|
309
|
-
end
|
310
|
-
|
343
|
+
it 'SW_SHOWMINNOACTIVE, SW_SHOWMINIMIZED displays the window as a minimized foreground window' do
|
344
|
+
test_show_window SW_SHOWMINNOACTIVE, SW_SHOWMINIMIZED,
|
345
|
+
:minimized? => true, :maximized? => false, :visible? => true, :foreground? => true
|
311
346
|
end
|
312
|
-
it 'SW_SHOWMINIMIZED activates the window and displays it as a minimized window' do
|
313
|
-
pending 'Need to make sure window is minimized AND activated '
|
314
|
-
test_app do |app|
|
315
|
-
show_window(app.handle, SW_SHOWMINIMIZED)
|
316
|
-
p get_window_rect(app.handle)
|
317
|
-
#.should == TEST_MAX_RECT
|
318
|
-
end
|
319
347
|
|
348
|
+
it 'SW_SHOWNORMAL, SW_RESTORE, SW_SHOWNOACTIVATE activate/display a window(if min/maximized it is restored' do
|
349
|
+
test_show_window SW_SHOWNORMAL, SW_RESTORE, SW_SHOWNOACTIVATE,
|
350
|
+
:minimized? => false, :maximized? => false, :visible? => true, :foreground? => true
|
320
351
|
end
|
321
|
-
|
352
|
+
|
322
353
|
it 'SW_SHOWNA displays the window in its current size and position (similar to SW_SHOW, but window is not activated)'
|
323
|
-
it 'SW_SHOWNOACTIVATE displays the window in its current size and position (similar to SW_SHOW, but window is not activated)'
|
324
|
-
it 'SW_SHOWNORMAL activates and displays a window. Restores minimized/maximized window to original size/position. Use it to show window for the first time'
|
325
|
-
it 'SW_RESTORE activates and displays the window. Restores minimized/maximized window to original size/position. Use it to restore minimized windows'
|
326
354
|
it 'SW_SHOWDEFAULT sets the show state based on the SW_ value specified in the STARTUPINFO structure passed to the CreateProcess function by the program that started the application'
|
327
355
|
it 'SW_FORCEMINIMIZE minimizes a window, even if the thread that owns the window is not responding - only Win2000/XP'
|
328
356
|
end
|
329
357
|
|
330
358
|
describe '#keydb_event' do
|
331
359
|
spec{ use{ keybd_event(vkey = 0, bscan = 0, flags = 0, extra_info = 0) }}
|
332
|
-
# vkey (I) - Specifies a virtual-key code. The code must be a value in the range 1 to 254. For a complete list, see msdn:Virtual Key Codes.
|
360
|
+
# vkey (I) - Specifies a virtual-key code. The code must be a value in the range 1 to 254. For a complete list, see msdn:Virtual Key Codes.
|
333
361
|
# bscan (I) - Specifies a hardware scan code for the key.
|
334
362
|
# flags (L) - Specifies various aspects of function operation. This parameter can be one or more of the following values.
|
335
363
|
# KEYEVENTF_EXTENDEDKEY - If specified, the scan code was preceded by a prefix byte having the value 0xE0 (224).
|
@@ -337,10 +365,10 @@ module GuiTest
|
|
337
365
|
# extra_info (L) - Specifies an additional value associated with the key stroke.
|
338
366
|
# no return value
|
339
367
|
|
340
|
-
it 'synthesizes a numeric
|
368
|
+
it 'synthesizes a numeric keystrokes, emulating keyboard driver' do
|
341
369
|
test_app do |app|
|
342
370
|
text = '123 456'
|
343
|
-
text.upcase.each_byte do |b| # upcase needed since user32 keybd_event expects upper case chars
|
371
|
+
text.upcase.each_byte do |b| # upcase needed since user32 keybd_event expects upper case chars
|
344
372
|
keybd_event(b.ord, 0, KEYEVENTF_KEYDOWN, 0)
|
345
373
|
sleep TEST_KEY_DELAY
|
346
374
|
keybd_event(b.ord, 0, KEYEVENTF_KEYUP, 0)
|
@@ -356,8 +384,8 @@ module GuiTest
|
|
356
384
|
|
357
385
|
describe '#post_message' do
|
358
386
|
spec{ use{ success = post_message(handle = 0, msg = 0, w_param = 0, l_param = 0) }}
|
359
|
-
# handle (L) - Handle to the window whose window procedure will receive the message.
|
360
|
-
# If this parameter is HWND_BROADCAST, the message is sent to all top-level windows in the system, including disabled or
|
387
|
+
# handle (L) - Handle to the window whose window procedure will receive the message.
|
388
|
+
# If this parameter is HWND_BROADCAST, the message is sent to all top-level windows in the system, including disabled or
|
361
389
|
# invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows.
|
362
390
|
# msg (L) - Specifies the message to be posted.
|
363
391
|
# w_param (L) - Specifies additional message-specific information.
|
@@ -371,7 +399,7 @@ module GuiTest
|
|
371
399
|
describe '#send_message' do
|
372
400
|
spec{ use{ success = send_message(handle = 0, msg = 0, w_param = 1024, l_param = "\x0"*1024) }}
|
373
401
|
# handle (L) - Handle to the window whose window procedure is to receive the message. The following values have special meanings.
|
374
|
-
# HWND_BROADCAST - The message is posted to all top-level windows in the system, including disabled or invisible unowned windows,
|
402
|
+
# HWND_BROADCAST - The message is posted to all top-level windows in the system, including disabled or invisible unowned windows,
|
375
403
|
# overlapped windows, and pop-up windows. The message is not posted to child windows.
|
376
404
|
# NULL - The function behaves like a call to PostThreadMessage with the dwThreadId parameter set to the identifier of the current thread.
|
377
405
|
# msg (L) - Specifies the message to be posted.
|
@@ -385,13 +413,13 @@ module GuiTest
|
|
385
413
|
|
386
414
|
describe '#get_dlg_item' do
|
387
415
|
spec{ use{ control_handle = get_dlg_item(handle = 0, item_id = 1) }}
|
388
|
-
# handle (L) - Handle of the dialog box that contains the control.
|
389
|
-
# item_id (I) - Specifies the identifier of the control to be retrieved.
|
416
|
+
# handle (L) - Handle of the dialog box that contains the control.
|
417
|
+
# item_id (I) - Specifies the identifier of the control to be retrieved.
|
390
418
|
# Returns (L) - handle of the specified control if success or nil for invalid dialog box handle or a nonexistent control.
|
391
419
|
# To get extended error information, call GetLastError.
|
392
|
-
# You can use the GetDlgItem function with any parent-child window pair, not just with dialog boxes. As long as the handle
|
393
|
-
# parameter specifies a parent window and the child window has a unique id (as specified by the hMenu parameter in the
|
394
|
-
# CreateWindow or CreateWindowEx function that created the child window), GetDlgItem returns a valid handle to the child window.
|
420
|
+
# You can use the GetDlgItem function with any parent-child window pair, not just with dialog boxes. As long as the handle
|
421
|
+
# parameter specifies a parent window and the child window has a unique id (as specified by the hMenu parameter in the
|
422
|
+
# CreateWindow or CreateWindowEx function that created the child window), GetDlgItem returns a valid handle to the child window.
|
395
423
|
|
396
424
|
it 'returns handle to correctly specified control'
|
397
425
|
end
|
@@ -400,13 +428,15 @@ module GuiTest
|
|
400
428
|
spec{ use{ enum_windows(message = 'Message') }}
|
401
429
|
|
402
430
|
it 'return an array of top-level window handles if block is not given' do
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
431
|
+
test_app do |app|
|
432
|
+
enum = enum_windows(message = 'Message')
|
433
|
+
enum.should be_a_kind_of Array
|
434
|
+
enum.should_not be_empty
|
435
|
+
enum.should have_at_least(60).elements # typical number of top windows in WinXP system?
|
436
|
+
enum.each{|handle| handle.should be_an Integer }
|
437
|
+
enum.any?{|handle| handle == app.handle}.should == true
|
438
|
+
end
|
408
439
|
end
|
409
|
-
|
410
440
|
it 'iterates through all the top-level windows, passing each found window handle and message to a given block'
|
411
441
|
|
412
442
|
end
|
@@ -418,25 +448,46 @@ module GuiTest
|
|
418
448
|
test_app do |app|
|
419
449
|
enum = enum_child_windows(app.handle, message = 'Message')
|
420
450
|
enum.should be_a_kind_of Array
|
421
|
-
enum.should_not be_empty
|
422
451
|
enum.should have(2).elements
|
423
|
-
|
424
|
-
|
452
|
+
class_name(enum.first).should == TEST_STATUSBAR_CLASS
|
453
|
+
class_name(enum.last).should == TEST_TEXTAREA_CLASS
|
425
454
|
end
|
426
455
|
end
|
427
456
|
|
428
|
-
it 'loops through all children of given window, passing each found window handle and a message to a given block'
|
429
|
-
|
457
|
+
it 'loops through all children of given window, passing each found window handle and a message to a given block' do
|
458
|
+
test_app do |app|
|
459
|
+
enum = []
|
460
|
+
enum_child_windows(app.handle, 'Message') do |handle, message|
|
461
|
+
enum << handle
|
462
|
+
message.should == 'Message'
|
463
|
+
end
|
464
|
+
enum.should have(2).elements
|
465
|
+
class_name(enum.first).should == TEST_STATUSBAR_CLASS
|
466
|
+
class_name(enum.last).should == TEST_TEXTAREA_CLASS
|
467
|
+
end
|
468
|
+
end
|
430
469
|
|
431
|
-
|
432
|
-
|
470
|
+
it 'breaks loop if given block returns false' do
|
471
|
+
pending
|
472
|
+
test_app do |app|
|
473
|
+
enum = []
|
474
|
+
enum_child_windows(app.handle, 'Message') do |handle, message|
|
475
|
+
enum << handle
|
476
|
+
1
|
477
|
+
end
|
478
|
+
enum.should have(1).element
|
479
|
+
class_name(enum.first).should == TEST_STATUSBAR_CLASS
|
480
|
+
# class_name(enum.last).should == TEST_TEXTAREA_CLASS
|
481
|
+
end
|
482
|
+
end
|
483
|
+
end
|
433
484
|
end
|
434
485
|
|
435
486
|
describe WinGui, ' convenience wrapper methods' do
|
436
487
|
describe '#keystroke' do
|
437
488
|
spec{ use{ keystroke( vkey = 30, vkey = 30) }}
|
438
489
|
# this service method emulates combinations of (any amount of) keys pressed one after another (Ctrl+Alt+P) and then released
|
439
|
-
# vkey (int) - Specifies a virtual-key code. The code must be a value in the range 1 to 254. For a complete list, see msdn:Virtual Key Codes.
|
490
|
+
# vkey (int) - Specifies a virtual-key code. The code must be a value in the range 1 to 254. For a complete list, see msdn:Virtual Key Codes.
|
440
491
|
|
441
492
|
it 'emulates combinations of keys pressed (Ctrl+Alt+P+M, etc)' do
|
442
493
|
test_app do |app|
|
data/win_gui.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{win_gui}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.4"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["arvicco"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-02-04}
|
13
13
|
s.description = %q{Rubyesque interfaces and wrappers for Win32 API GUI functions}
|
14
14
|
s.email = %q{arvitallian@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: win_gui
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- arvicco
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-
|
12
|
+
date: 2010-02-04 00:00:00 +03:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|