win 0.1.27 → 0.3.1
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/.document +5 -5
- data/.gitignore +21 -21
- data/LICENSE +20 -20
- data/README.rdoc +175 -175
- data/Rakefile +58 -58
- data/VERSION +1 -1
- data/features/support/env.rb +4 -4
- data/features/win.feature +9 -9
- data/lib/win/dde.rb +1234 -1234
- data/lib/win/error.rb +1223 -1223
- data/lib/win/extensions.rb +41 -41
- data/lib/win/gui.rb +16 -16
- data/lib/win/gui/dialog.rb +50 -50
- data/lib/win/gui/input.rb +319 -319
- data/lib/win/gui/message.rb +807 -807
- data/lib/win/gui/window.rb +679 -679
- data/lib/win/library.rb +463 -463
- data/spec/spec.opts +2 -2
- data/spec/spec_helper.rb +140 -135
- data/spec/test_apps/locknote/LockNote.exe +0 -0
- data/spec/win/dde_spec.rb +528 -528
- data/spec/win/error_spec.rb +112 -112
- data/spec/win/extensions_spec.rb +73 -73
- data/spec/win/gui/dialog_spec.rb +43 -43
- data/spec/win/gui/input_spec.rb +101 -101
- data/spec/win/gui/message_spec.rb +236 -236
- data/spec/win/gui/window_spec.rb +549 -548
- data/spec/win/library_spec.rb +341 -341
- data/win.gemspec +87 -87
- metadata +34 -17
data/spec/win/gui/input_spec.rb
CHANGED
@@ -1,101 +1,101 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
-
require 'win/gui/input'
|
3
|
-
#require 'win/gui/window'
|
4
|
-
|
5
|
-
module WinWindowTest
|
6
|
-
|
7
|
-
include WinTestApp
|
8
|
-
include Win::
|
9
|
-
|
10
|
-
describe Win::
|
11
|
-
|
12
|
-
describe '#keydb_event' do
|
13
|
-
spec{ use{ keybd_event(vkey = 0, bscan = 0, flags = 0, extra_info = 0) }}
|
14
|
-
|
15
|
-
it 'synthesizes a numeric keystrokes, emulating keyboard driver' do
|
16
|
-
test_app do |app|
|
17
|
-
text = '12 34'
|
18
|
-
text.upcase.each_byte do |b| # upcase needed since user32 keybd_event expects upper case chars
|
19
|
-
keybd_event(b.ord, 0, KEYEVENTF_KEYDOWN, 0)
|
20
|
-
sleep TEST_KEY_DELAY
|
21
|
-
keybd_event(b.ord, 0, KEYEVENTF_KEYUP, 0)
|
22
|
-
sleep TEST_KEY_DELAY
|
23
|
-
end
|
24
|
-
text(app.textarea).should =~ Regexp.new(text)
|
25
|
-
5.times {keystroke(VK_CONTROL, 'Z'.ord)} # rolling back changes to allow window closing without dialog!
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end # describe '#keydb_event'
|
29
|
-
|
30
|
-
describe '#mouse_event' do
|
31
|
-
spec { use {mouse_event( flags = MOUSEEVENTF_ABSOLUTE , dx = 0, dy = 0, data=0, extra_info=0 )}}
|
32
|
-
it 'Emulates Mouse clicks'
|
33
|
-
end # describe '#mouse_event'
|
34
|
-
|
35
|
-
describe "#get_cursor_pos" do
|
36
|
-
spec{ use{ success = GetCursorPos(lp_point=FFI::MemoryPointer.new(:long, 2)) }}
|
37
|
-
spec{ use{ x, y = get_cursor_pos() }}
|
38
|
-
|
39
|
-
it "original api returns success code and puts cursor's screen coordinates into supplied buffer" do
|
40
|
-
success = GetCursorPos(lp_point=FFI::MemoryPointer.new(:long, 2))
|
41
|
-
success.should_not == 0
|
42
|
-
x, y = lp_point.read_array_of_long(2)
|
43
|
-
x.should be_an Integer
|
44
|
-
x.should be >= 0
|
45
|
-
y.should be_an Integer
|
46
|
-
y.should be >= 0
|
47
|
-
end
|
48
|
-
|
49
|
-
it "snake_case api returns the cursor's position, in screen coordinates" do
|
50
|
-
x, y = get_cursor_pos()
|
51
|
-
x.should be_an Integer
|
52
|
-
x.should be >= 0
|
53
|
-
y.should be_an Integer
|
54
|
-
y.should be >= 0
|
55
|
-
end
|
56
|
-
end # describe get_cursor_pos
|
57
|
-
|
58
|
-
describe '#set_cursor_pos' do
|
59
|
-
spec { use {success = SetCursorPos(x=0, y=0)}}
|
60
|
-
spec { use {success = set_cursor_pos(x=0, y=0)}}
|
61
|
-
|
62
|
-
it 'sets cursor`s position, in screen coordinates' do
|
63
|
-
SetCursorPos(x=600, y=600).should be_true
|
64
|
-
get_cursor_pos().should == [600,600]
|
65
|
-
set_cursor_pos(x=0, y=0).should be_true
|
66
|
-
get_cursor_pos().should == [0,0]
|
67
|
-
end
|
68
|
-
end # describe '#set_cursor_pos'
|
69
|
-
|
70
|
-
end # Win::
|
71
|
-
|
72
|
-
describe Win::
|
73
|
-
describe '#keystroke' do
|
74
|
-
spec{ use{ keystroke( vkey = 30, vkey = 30) }}
|
75
|
-
|
76
|
-
it 'emulates combinations of keys pressed (Ctrl+Alt+P+M, etc)' do
|
77
|
-
test_app do |app|
|
78
|
-
keystroke(VK_CONTROL, 'A'.ord)
|
79
|
-
keystroke(VK_SPACE)
|
80
|
-
text(app.textarea).should.should == ' '
|
81
|
-
2.times {keystroke(VK_CONTROL, 'Z'.ord)} # rolling back changes to allow window closing without dialog!
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end # describe '#keystroke'
|
85
|
-
|
86
|
-
describe '#type_in' do
|
87
|
-
spec{ use{ type_in(message = '') }}
|
88
|
-
|
89
|
-
it 'types text message into the window holding the focus' do
|
90
|
-
test_app do |app|
|
91
|
-
text = '12 34'
|
92
|
-
type_in(text)
|
93
|
-
text(app.textarea).should =~ Regexp.new(text)
|
94
|
-
5.times {keystroke(VK_CONTROL, 'Z'.ord)} # rolling back changes to allow window closing without dialog!
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end # describe '#type_in'
|
98
|
-
|
99
|
-
end # Win::
|
100
|
-
end
|
101
|
-
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
require 'win/gui/input'
|
3
|
+
#require 'win/gui/window'
|
4
|
+
|
5
|
+
module WinWindowTest
|
6
|
+
|
7
|
+
include WinTestApp
|
8
|
+
include Win::Gui::Input
|
9
|
+
|
10
|
+
describe Win::Gui::Input, ' defines a set of API functions related to user input' do
|
11
|
+
|
12
|
+
describe '#keydb_event' do
|
13
|
+
spec{ use{ keybd_event(vkey = 0, bscan = 0, flags = 0, extra_info = 0) }}
|
14
|
+
|
15
|
+
it 'synthesizes a numeric keystrokes, emulating keyboard driver' do
|
16
|
+
test_app do |app|
|
17
|
+
text = '12 34'
|
18
|
+
text.upcase.each_byte do |b| # upcase needed since user32 keybd_event expects upper case chars
|
19
|
+
keybd_event(b.ord, 0, KEYEVENTF_KEYDOWN, 0)
|
20
|
+
sleep TEST_KEY_DELAY
|
21
|
+
keybd_event(b.ord, 0, KEYEVENTF_KEYUP, 0)
|
22
|
+
sleep TEST_KEY_DELAY
|
23
|
+
end
|
24
|
+
text(app.textarea).should =~ Regexp.new(text)
|
25
|
+
5.times {keystroke(VK_CONTROL, 'Z'.ord)} # rolling back changes to allow window closing without dialog!
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end # describe '#keydb_event'
|
29
|
+
|
30
|
+
describe '#mouse_event' do
|
31
|
+
spec { use {mouse_event( flags = MOUSEEVENTF_ABSOLUTE , dx = 0, dy = 0, data=0, extra_info=0 )}}
|
32
|
+
it 'Emulates Mouse clicks'
|
33
|
+
end # describe '#mouse_event'
|
34
|
+
|
35
|
+
describe "#get_cursor_pos" do
|
36
|
+
spec{ use{ success = GetCursorPos(lp_point=FFI::MemoryPointer.new(:long, 2)) }}
|
37
|
+
spec{ use{ x, y = get_cursor_pos() }}
|
38
|
+
|
39
|
+
it "original api returns success code and puts cursor's screen coordinates into supplied buffer" do
|
40
|
+
success = GetCursorPos(lp_point=FFI::MemoryPointer.new(:long, 2))
|
41
|
+
success.should_not == 0
|
42
|
+
x, y = lp_point.read_array_of_long(2)
|
43
|
+
x.should be_an Integer
|
44
|
+
x.should be >= 0
|
45
|
+
y.should be_an Integer
|
46
|
+
y.should be >= 0
|
47
|
+
end
|
48
|
+
|
49
|
+
it "snake_case api returns the cursor's position, in screen coordinates" do
|
50
|
+
x, y = get_cursor_pos()
|
51
|
+
x.should be_an Integer
|
52
|
+
x.should be >= 0
|
53
|
+
y.should be_an Integer
|
54
|
+
y.should be >= 0
|
55
|
+
end
|
56
|
+
end # describe get_cursor_pos
|
57
|
+
|
58
|
+
describe '#set_cursor_pos' do
|
59
|
+
spec { use {success = SetCursorPos(x=0, y=0)}}
|
60
|
+
spec { use {success = set_cursor_pos(x=0, y=0)}}
|
61
|
+
|
62
|
+
it 'sets cursor`s position, in screen coordinates' do
|
63
|
+
SetCursorPos(x=600, y=600).should be_true
|
64
|
+
get_cursor_pos().should == [600,600]
|
65
|
+
set_cursor_pos(x=0, y=0).should be_true
|
66
|
+
get_cursor_pos().should == [0,0]
|
67
|
+
end
|
68
|
+
end # describe '#set_cursor_pos'
|
69
|
+
|
70
|
+
end # Win::Gui::Input, ' defines a set of API functions related to user input'
|
71
|
+
|
72
|
+
describe Win::Gui::Input, ' defines convenience/service methods on top of Windows API' do
|
73
|
+
describe '#keystroke' do
|
74
|
+
spec{ use{ keystroke( vkey = 30, vkey = 30) }}
|
75
|
+
|
76
|
+
it 'emulates combinations of keys pressed (Ctrl+Alt+P+M, etc)' do
|
77
|
+
test_app do |app|
|
78
|
+
keystroke(VK_CONTROL, 'A'.ord)
|
79
|
+
keystroke(VK_SPACE)
|
80
|
+
text(app.textarea).should.should == ' '
|
81
|
+
2.times {keystroke(VK_CONTROL, 'Z'.ord)} # rolling back changes to allow window closing without dialog!
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end # describe '#keystroke'
|
85
|
+
|
86
|
+
describe '#type_in' do
|
87
|
+
spec{ use{ type_in(message = '') }}
|
88
|
+
|
89
|
+
it 'types text message into the window holding the focus' do
|
90
|
+
test_app do |app|
|
91
|
+
text = '12 34'
|
92
|
+
type_in(text)
|
93
|
+
text(app.textarea).should =~ Regexp.new(text)
|
94
|
+
5.times {keystroke(VK_CONTROL, 'Z'.ord)} # rolling back changes to allow window closing without dialog!
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end # describe '#type_in'
|
98
|
+
|
99
|
+
end # Win::Gui::Input, ' defines convenience/service methods on top of Windows API'
|
100
|
+
end
|
101
|
+
|
@@ -1,236 +1,236 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
-
require 'win/gui/input'
|
3
|
-
require 'win/error'
|
4
|
-
|
5
|
-
module
|
6
|
-
|
7
|
-
include WinTestApp
|
8
|
-
include Win::
|
9
|
-
include Win::
|
10
|
-
include Win::
|
11
|
-
include Win::Error
|
12
|
-
|
13
|
-
def buffer
|
14
|
-
@buffer ||= FFI::MemoryPointer.new :char, 1024
|
15
|
-
end
|
16
|
-
|
17
|
-
def msg
|
18
|
-
@msg ||=Win::
|
19
|
-
end
|
20
|
-
|
21
|
-
def msg_callback
|
22
|
-
lambda {|handle, message, data, result| @handle = handle; @message = message; @data = data; @result = result }
|
23
|
-
end
|
24
|
-
|
25
|
-
def should_have msg, members
|
26
|
-
members.each do |member, value|
|
27
|
-
case member
|
28
|
-
when :l_param
|
29
|
-
msg[member].address.should == value
|
30
|
-
when :time
|
31
|
-
msg[member].should be > value
|
32
|
-
else
|
33
|
-
msg[member].should == value
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def clear_thread_queue
|
39
|
-
get_message while peek_message
|
40
|
-
end
|
41
|
-
|
42
|
-
describe Win::
|
43
|
-
before(:all){clear_thread_queue}
|
44
|
-
|
45
|
-
describe '#post_message' do
|
46
|
-
before(:each){clear_thread_queue}
|
47
|
-
after(:all){close_test_app if @launched_test_app}
|
48
|
-
|
49
|
-
spec{ use{ success = PostMessage(handle = 0, msg = 0, w_param = 0, l_param = nil) }}
|
50
|
-
spec{ use{ success = post_message(handle = 0, msg = 0, w_param = 0, l_param = nil) }}
|
51
|
-
|
52
|
-
it 'places (posts) a message in the message queue associated with the thread that created the specified window' do
|
53
|
-
app = launch_test_app
|
54
|
-
post_message(app.handle, WM_SYSCOMMAND, SC_CLOSE, nil).should == true
|
55
|
-
sleep TEST_SLEEP_DELAY
|
56
|
-
window?(app.handle).should == false
|
57
|
-
end
|
58
|
-
|
59
|
-
it 'places (posts) a message into current thread`s queue if first arg is 0' do
|
60
|
-
post_message(0, WM_USER, 33, nil).should == true
|
61
|
-
msg = get_message()
|
62
|
-
should_have msg, hwnd: 0, message: WM_USER, w_param: 33, l_param: 0
|
63
|
-
end
|
64
|
-
|
65
|
-
it 'returns without waiting for the thread to process the message'
|
66
|
-
|
67
|
-
end # describe '#post_message'
|
68
|
-
|
69
|
-
describe '#send_message' do
|
70
|
-
spec{ use{ success = SendMessage(handle = 0, msg = 0, w_param = 0, l_param = nil) }}
|
71
|
-
spec{ use{ success = send_message(handle = 0, msg = 0, w_param = 0, l_param = nil) }}
|
72
|
-
|
73
|
-
it 'directly sends the specified message to a window or windows' do
|
74
|
-
app = launch_test_app
|
75
|
-
|
76
|
-
num_chars = send_message app.handle, WM_GETTEXT, buffer.size, buffer
|
77
|
-
buffer.get_bytes(0, num_chars).should == "LockNote - Steganos LockNote"
|
78
|
-
|
79
|
-
num_chars = send_message app.textarea, WM_GETTEXT, buffer.size, buffer
|
80
|
-
buffer.get_bytes(0, num_chars).should =~ /Welcome to Steganos LockNote/
|
81
|
-
|
82
|
-
send_message(app.handle, WM_SYSCOMMAND, SC_CLOSE, nil)
|
83
|
-
sleep TEST_SLEEP_DELAY # delay to allow window close
|
84
|
-
window?(app.handle).should == false
|
85
|
-
end
|
86
|
-
end # describe '#send_message'
|
87
|
-
|
88
|
-
# :call-seq:
|
89
|
-
# success = send_message_callback(handle, msg, w_param, l_param, data)
|
90
|
-
# {|handle, msg, data, l_result| callback code }
|
91
|
-
|
92
|
-
describe "#send_message_callback" do
|
93
|
-
before(:all){@app=launch_test_app}
|
94
|
-
after(:all){close_test_app if @launched_test_app}
|
95
|
-
|
96
|
-
spec{ use{ success = SendMessageCallback(h_wnd=0, msg=0, w_param=0, l_param=nil, msg_callback, data=0) }}
|
97
|
-
spec{ use{ success = send_message_callback(h_wnd=0, msg=0, w_param=0, l_param=nil, data=0, &msg_callback) }}
|
98
|
-
|
99
|
-
it "sends message to window and returns, specifying callback to be called by system after message is processed" do
|
100
|
-
sent = SendMessageCallback(@app.handle, WM_USER, 0, nil, msg_callback, data=13)
|
101
|
-
sent.should == 1
|
102
|
-
@handle.should == nil
|
103
|
-
@message.should == nil
|
104
|
-
@data.should == nil
|
105
|
-
@result.should == nil
|
106
|
-
|
107
|
-
sleep TEST_SLEEP_DELAY # small delay to allow message delivery
|
108
|
-
peek_message # dispatching sent message (even though there is nothing in queue)
|
109
|
-
|
110
|
-
@handle.should == @app.handle
|
111
|
-
@message.should == WM_USER
|
112
|
-
@data.should == 13
|
113
|
-
@result.should == 0
|
114
|
-
end
|
115
|
-
|
116
|
-
it "snake_case api defaults data to 0, converts block into callback and returns true/false" do
|
117
|
-
sent = send_message_callback(@app.handle, WM_USER, 0, nil){|*args|@data=args[2]}
|
118
|
-
sent.should == true
|
119
|
-
@data.should == nil
|
120
|
-
|
121
|
-
sleep TEST_SLEEP_DELAY # small delay to allow message delivery
|
122
|
-
peek_message # dispatching sent message (even though there is nothing in queue)
|
123
|
-
|
124
|
-
@data.should == 0
|
125
|
-
end
|
126
|
-
|
127
|
-
it "fails if unable to send message" do
|
128
|
-
sent = SendMessageCallback(not_a_handle, WM_USER, 0, nil, msg_callback, 0)
|
129
|
-
sent.should == 0
|
130
|
-
send_message_callback(not_a_handle, WM_USER, 0, nil){|*args|@data=args[2]}
|
131
|
-
sent.should == 0
|
132
|
-
get_last_error.should == "Invalid window handle."
|
133
|
-
end
|
134
|
-
end # describe send_message_callback
|
135
|
-
|
136
|
-
describe "#get_message" do
|
137
|
-
before(:all){clear_thread_queue; 2.times {post_message 0,0,0,nil}}
|
138
|
-
|
139
|
-
spec{ use{ res = GetMessage(msg, handle=0, msg_filter_min=0, msg_filter_max=0) }}
|
140
|
-
spec{ use{ message = get_message(msg, handle=0, msg_filter_min=0, msg_filter_max=0) }}
|
141
|
-
|
142
|
-
it "original api retrieves a message from the calling thread's message queue" do
|
143
|
-
set_cursor_pos(x=0, y=0)
|
144
|
-
post_message(0, WM_USER+1, 33, nil)
|
145
|
-
res = GetMessage(msg, handle=0, msg_filter_min=0, msg_filter_max=0)
|
146
|
-
res.should == 1
|
147
|
-
# p msg[:hwnd], msg[:message], msg[:w_param], msg[:l_param], msg[:time], msg[:x], msg[:y]
|
148
|
-
should_have msg, hwnd: 0, message: WM_USER+1, w_param: 33, x: 0, y: 0, l_param: 0, time: 1000000
|
149
|
-
end
|
150
|
-
|
151
|
-
it "original api returns -1 if there is an error (wrong handle, in this case)" do
|
152
|
-
res = GetMessage(msg, not_a_handle, msg_filter_min=0, msg_filter_max=0)
|
153
|
-
res.should == -1
|
154
|
-
end
|
155
|
-
|
156
|
-
it "original api returns 0 if WM_QUIT was posted to thread`s message queue" do
|
157
|
-
post_message(0, WM_QUIT, 13, nil)
|
158
|
-
res = GetMessage(msg, 0, msg_filter_min=0, msg_filter_max=0)
|
159
|
-
res.should == 0
|
160
|
-
end
|
161
|
-
|
162
|
-
it "snake_case api returns a message struct retrieved from the calling thread's message queue " do
|
163
|
-
set_cursor_pos(x=99, y=99)
|
164
|
-
post_message(0, WM_USER+2, 33, nil)
|
165
|
-
msg = get_message()
|
166
|
-
should_have msg, hwnd: 0, message: WM_USER+2, w_param: 33, x: 99, y: 99, l_param: 0, time: 1000000
|
167
|
-
end
|
168
|
-
|
169
|
-
it "snake_case api returns nil if there is an error (wrong handle, in this case)" do
|
170
|
-
get_message(msg, not_a_handle).should == nil
|
171
|
-
end
|
172
|
-
|
173
|
-
it "snake_case api returns false if WM_QUIT was posted to thread`s message queue" do
|
174
|
-
post_message(0, WM_QUIT, 13, nil)
|
175
|
-
get_message.should == false
|
176
|
-
end
|
177
|
-
end # describe get_message
|
178
|
-
|
179
|
-
|
180
|
-
describe "#peek_message" do
|
181
|
-
before(:all){set_cursor_pos(x=0, y=0); post_message(0, WM_USER+2, 13, nil)}
|
182
|
-
spec{ use{ success = PeekMessage(msg, h_wnd=0, filter_min=0, filter_max=0, remove_msg=0) }}
|
183
|
-
spec{ use{ success = peek_message(msg, h_wnd=0, filter_min=0, filter_max=0, remove_msg=0) }}
|
184
|
-
|
185
|
-
it "original api checks the thread message queue for a posted message, retrieves it without removing" do
|
186
|
-
10.times do
|
187
|
-
res = PeekMessage(msg, h_wnd=0, filter_min=0, filter_max=0, remove_msg=0)
|
188
|
-
res.should == 1
|
189
|
-
should_have msg, hwnd: 0, message: WM_USER+2, w_param: 13, x: 0, y: 0, l_param: 0, time: 1000000
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
it "snake_case api checks the thread message queue for a posted message, returns it without removing" do
|
194
|
-
10.times do
|
195
|
-
msg = peek_message()
|
196
|
-
should_have msg, hwnd: 0, message: WM_USER+2, w_param: 13, x: 0, y: 0, l_param: 0, time: 1000000
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
it "original api returns 0 if no message in queue" do
|
201
|
-
get_message
|
202
|
-
PeekMessage(msg, h_wnd=0, filter_min=0, filter_max=0, remove_msg=0).should == 0
|
203
|
-
end
|
204
|
-
|
205
|
-
it "snake_case api returns nil if no message in queue" do
|
206
|
-
peek_message.should == nil
|
207
|
-
end
|
208
|
-
end # describe peek_message
|
209
|
-
|
210
|
-
describe "#translate_message" do
|
211
|
-
spec{ use{ success = TranslateMessage(msg) }}
|
212
|
-
spec{ use{ success = translate_message(msg) }}
|
213
|
-
|
214
|
-
it "translates virtual-key message into character message which is then posted to the thread's message queue"
|
215
|
-
|
216
|
-
it "returns zero/false if no translation took place" do
|
217
|
-
TranslateMessage(msg).should == 0
|
218
|
-
translate_message(msg).should == false
|
219
|
-
end
|
220
|
-
end # describe translate_message
|
221
|
-
|
222
|
-
describe "#dispatch_message" do
|
223
|
-
spec{ use{ res = DispatchMessage(msg) }} #return value is normally ignored
|
224
|
-
spec{ use{ res = dispatch_message(msg) }} #return value is normally ignored
|
225
|
-
|
226
|
-
it "dispatches a message to a window procedure. Typically used to dispatch a message retrieved by GetMessage" do
|
227
|
-
pending
|
228
|
-
res = DispatchMessage(msg)
|
229
|
-
end
|
230
|
-
|
231
|
-
end # describe dispatch_message
|
232
|
-
|
233
|
-
end # Win::
|
234
|
-
end
|
235
|
-
|
236
|
-
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
require 'win/gui/input'
|
3
|
+
require 'win/error'
|
4
|
+
|
5
|
+
module WinGuiMessageTest
|
6
|
+
|
7
|
+
include WinTestApp
|
8
|
+
include Win::Gui::Message
|
9
|
+
include Win::Gui::Window
|
10
|
+
include Win::Gui::Input
|
11
|
+
include Win::Error
|
12
|
+
|
13
|
+
def buffer
|
14
|
+
@buffer ||= FFI::MemoryPointer.new :char, 1024
|
15
|
+
end
|
16
|
+
|
17
|
+
def msg
|
18
|
+
@msg ||=Win::Gui::Message::Msg.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def msg_callback
|
22
|
+
lambda {|handle, message, data, result| @handle = handle; @message = message; @data = data; @result = result }
|
23
|
+
end
|
24
|
+
|
25
|
+
def should_have msg, members
|
26
|
+
members.each do |member, value|
|
27
|
+
case member
|
28
|
+
when :l_param
|
29
|
+
msg[member].address.should == value
|
30
|
+
when :time
|
31
|
+
msg[member].should be > value
|
32
|
+
else
|
33
|
+
msg[member].should == value
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def clear_thread_queue
|
39
|
+
get_message while peek_message
|
40
|
+
end
|
41
|
+
|
42
|
+
describe Win::Gui::Message, ' defines a set of API functions related to Window messaging' do
|
43
|
+
before(:all){clear_thread_queue}
|
44
|
+
|
45
|
+
describe '#post_message' do
|
46
|
+
before(:each){clear_thread_queue}
|
47
|
+
after(:all){close_test_app if @launched_test_app}
|
48
|
+
|
49
|
+
spec{ use{ success = PostMessage(handle = 0, msg = 0, w_param = 0, l_param = nil) }}
|
50
|
+
spec{ use{ success = post_message(handle = 0, msg = 0, w_param = 0, l_param = nil) }}
|
51
|
+
|
52
|
+
it 'places (posts) a message in the message queue associated with the thread that created the specified window' do
|
53
|
+
app = launch_test_app
|
54
|
+
post_message(app.handle, WM_SYSCOMMAND, SC_CLOSE, nil).should == true
|
55
|
+
sleep TEST_SLEEP_DELAY
|
56
|
+
window?(app.handle).should == false
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'places (posts) a message into current thread`s queue if first arg is 0' do
|
60
|
+
post_message(0, WM_USER, 33, nil).should == true
|
61
|
+
msg = get_message()
|
62
|
+
should_have msg, hwnd: 0, message: WM_USER, w_param: 33, l_param: 0
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'returns without waiting for the thread to process the message'
|
66
|
+
|
67
|
+
end # describe '#post_message'
|
68
|
+
|
69
|
+
describe '#send_message' do
|
70
|
+
spec{ use{ success = SendMessage(handle = 0, msg = 0, w_param = 0, l_param = nil) }}
|
71
|
+
spec{ use{ success = send_message(handle = 0, msg = 0, w_param = 0, l_param = nil) }}
|
72
|
+
|
73
|
+
it 'directly sends the specified message to a window or windows' do
|
74
|
+
app = launch_test_app
|
75
|
+
|
76
|
+
num_chars = send_message app.handle, WM_GETTEXT, buffer.size, buffer
|
77
|
+
buffer.get_bytes(0, num_chars).should == "LockNote - Steganos LockNote"
|
78
|
+
|
79
|
+
num_chars = send_message app.textarea, WM_GETTEXT, buffer.size, buffer
|
80
|
+
buffer.get_bytes(0, num_chars).should =~ /Welcome to Steganos LockNote/
|
81
|
+
|
82
|
+
send_message(app.handle, WM_SYSCOMMAND, SC_CLOSE, nil)
|
83
|
+
sleep TEST_SLEEP_DELAY # delay to allow window close
|
84
|
+
window?(app.handle).should == false
|
85
|
+
end
|
86
|
+
end # describe '#send_message'
|
87
|
+
|
88
|
+
# :call-seq:
|
89
|
+
# success = send_message_callback(handle, msg, w_param, l_param, data)
|
90
|
+
# {|handle, msg, data, l_result| callback code }
|
91
|
+
|
92
|
+
describe "#send_message_callback" do
|
93
|
+
before(:all){@app=launch_test_app}
|
94
|
+
after(:all){close_test_app if @launched_test_app}
|
95
|
+
|
96
|
+
spec{ use{ success = SendMessageCallback(h_wnd=0, msg=0, w_param=0, l_param=nil, msg_callback, data=0) }}
|
97
|
+
spec{ use{ success = send_message_callback(h_wnd=0, msg=0, w_param=0, l_param=nil, data=0, &msg_callback) }}
|
98
|
+
|
99
|
+
it "sends message to window and returns, specifying callback to be called by system after message is processed" do
|
100
|
+
sent = SendMessageCallback(@app.handle, WM_USER, 0, nil, msg_callback, data=13)
|
101
|
+
sent.should == 1
|
102
|
+
@handle.should == nil
|
103
|
+
@message.should == nil
|
104
|
+
@data.should == nil
|
105
|
+
@result.should == nil
|
106
|
+
|
107
|
+
sleep TEST_SLEEP_DELAY # small delay to allow message delivery
|
108
|
+
peek_message # dispatching sent message (even though there is nothing in queue)
|
109
|
+
|
110
|
+
@handle.should == @app.handle
|
111
|
+
@message.should == WM_USER
|
112
|
+
@data.should == 13
|
113
|
+
@result.should == 0
|
114
|
+
end
|
115
|
+
|
116
|
+
it "snake_case api defaults data to 0, converts block into callback and returns true/false" do
|
117
|
+
sent = send_message_callback(@app.handle, WM_USER, 0, nil){|*args|@data=args[2]}
|
118
|
+
sent.should == true
|
119
|
+
@data.should == nil
|
120
|
+
|
121
|
+
sleep TEST_SLEEP_DELAY # small delay to allow message delivery
|
122
|
+
peek_message # dispatching sent message (even though there is nothing in queue)
|
123
|
+
|
124
|
+
@data.should == 0
|
125
|
+
end
|
126
|
+
|
127
|
+
it "fails if unable to send message" do
|
128
|
+
sent = SendMessageCallback(not_a_handle, WM_USER, 0, nil, msg_callback, 0)
|
129
|
+
sent.should == 0
|
130
|
+
send_message_callback(not_a_handle, WM_USER, 0, nil){|*args|@data=args[2]}
|
131
|
+
sent.should == 0
|
132
|
+
get_last_error.should == "Invalid window handle."
|
133
|
+
end
|
134
|
+
end # describe send_message_callback
|
135
|
+
|
136
|
+
describe "#get_message" do
|
137
|
+
before(:all){clear_thread_queue; 2.times {post_message 0,0,0,nil}}
|
138
|
+
|
139
|
+
spec{ use{ res = GetMessage(msg, handle=0, msg_filter_min=0, msg_filter_max=0) }}
|
140
|
+
spec{ use{ message = get_message(msg, handle=0, msg_filter_min=0, msg_filter_max=0) }}
|
141
|
+
|
142
|
+
it "original api retrieves a message from the calling thread's message queue" do
|
143
|
+
set_cursor_pos(x=0, y=0)
|
144
|
+
post_message(0, WM_USER+1, 33, nil)
|
145
|
+
res = GetMessage(msg, handle=0, msg_filter_min=0, msg_filter_max=0)
|
146
|
+
res.should == 1
|
147
|
+
# p msg[:hwnd], msg[:message], msg[:w_param], msg[:l_param], msg[:time], msg[:x], msg[:y]
|
148
|
+
should_have msg, hwnd: 0, message: WM_USER+1, w_param: 33, x: 0, y: 0, l_param: 0, time: 1000000
|
149
|
+
end
|
150
|
+
|
151
|
+
it "original api returns -1 if there is an error (wrong handle, in this case)" do
|
152
|
+
res = GetMessage(msg, not_a_handle, msg_filter_min=0, msg_filter_max=0)
|
153
|
+
res.should == -1
|
154
|
+
end
|
155
|
+
|
156
|
+
it "original api returns 0 if WM_QUIT was posted to thread`s message queue" do
|
157
|
+
post_message(0, WM_QUIT, 13, nil)
|
158
|
+
res = GetMessage(msg, 0, msg_filter_min=0, msg_filter_max=0)
|
159
|
+
res.should == 0
|
160
|
+
end
|
161
|
+
|
162
|
+
it "snake_case api returns a message struct retrieved from the calling thread's message queue " do
|
163
|
+
set_cursor_pos(x=99, y=99)
|
164
|
+
post_message(0, WM_USER+2, 33, nil)
|
165
|
+
msg = get_message()
|
166
|
+
should_have msg, hwnd: 0, message: WM_USER+2, w_param: 33, x: 99, y: 99, l_param: 0, time: 1000000
|
167
|
+
end
|
168
|
+
|
169
|
+
it "snake_case api returns nil if there is an error (wrong handle, in this case)" do
|
170
|
+
get_message(msg, not_a_handle).should == nil
|
171
|
+
end
|
172
|
+
|
173
|
+
it "snake_case api returns false if WM_QUIT was posted to thread`s message queue" do
|
174
|
+
post_message(0, WM_QUIT, 13, nil)
|
175
|
+
get_message.should == false
|
176
|
+
end
|
177
|
+
end # describe get_message
|
178
|
+
|
179
|
+
|
180
|
+
describe "#peek_message" do
|
181
|
+
before(:all){set_cursor_pos(x=0, y=0); post_message(0, WM_USER+2, 13, nil)}
|
182
|
+
spec{ use{ success = PeekMessage(msg, h_wnd=0, filter_min=0, filter_max=0, remove_msg=0) }}
|
183
|
+
spec{ use{ success = peek_message(msg, h_wnd=0, filter_min=0, filter_max=0, remove_msg=0) }}
|
184
|
+
|
185
|
+
it "original api checks the thread message queue for a posted message, retrieves it without removing" do
|
186
|
+
10.times do
|
187
|
+
res = PeekMessage(msg, h_wnd=0, filter_min=0, filter_max=0, remove_msg=0)
|
188
|
+
res.should == 1
|
189
|
+
should_have msg, hwnd: 0, message: WM_USER+2, w_param: 13, x: 0, y: 0, l_param: 0, time: 1000000
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
it "snake_case api checks the thread message queue for a posted message, returns it without removing" do
|
194
|
+
10.times do
|
195
|
+
msg = peek_message()
|
196
|
+
should_have msg, hwnd: 0, message: WM_USER+2, w_param: 13, x: 0, y: 0, l_param: 0, time: 1000000
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
it "original api returns 0 if no message in queue" do
|
201
|
+
get_message
|
202
|
+
PeekMessage(msg, h_wnd=0, filter_min=0, filter_max=0, remove_msg=0).should == 0
|
203
|
+
end
|
204
|
+
|
205
|
+
it "snake_case api returns nil if no message in queue" do
|
206
|
+
peek_message.should == nil
|
207
|
+
end
|
208
|
+
end # describe peek_message
|
209
|
+
|
210
|
+
describe "#translate_message" do
|
211
|
+
spec{ use{ success = TranslateMessage(msg) }}
|
212
|
+
spec{ use{ success = translate_message(msg) }}
|
213
|
+
|
214
|
+
it "translates virtual-key message into character message which is then posted to the thread's message queue"
|
215
|
+
|
216
|
+
it "returns zero/false if no translation took place" do
|
217
|
+
TranslateMessage(msg).should == 0
|
218
|
+
translate_message(msg).should == false
|
219
|
+
end
|
220
|
+
end # describe translate_message
|
221
|
+
|
222
|
+
describe "#dispatch_message" do
|
223
|
+
spec{ use{ res = DispatchMessage(msg) }} #return value is normally ignored
|
224
|
+
spec{ use{ res = dispatch_message(msg) }} #return value is normally ignored
|
225
|
+
|
226
|
+
it "dispatches a message to a window procedure. Typically used to dispatch a message retrieved by GetMessage" do
|
227
|
+
pending
|
228
|
+
res = DispatchMessage(msg)
|
229
|
+
end
|
230
|
+
|
231
|
+
end # describe dispatch_message
|
232
|
+
|
233
|
+
end # Win::Gui::Message, ' defines a set of API functions related to Window messaging'
|
234
|
+
end
|
235
|
+
|
236
|
+
|