win_gui 0.1.3 → 0.1.4
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/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
|