win 0.0.6 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,16 +1,15 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
- require 'win/window'
3
- require 'win/window/extra'
2
+ require 'win/gui/convenience'
4
3
 
5
- module WinWindowTest
6
- include WinTest
7
- include Win::Window
4
+ module WinGuiTest
5
+ include WinTestApp
6
+ include Win::Gui::Window
7
+ include Win::Gui::Input
8
+ include Win::Gui::Convenience
8
9
 
9
- describe Win::Window, ' extra convenience/service methods' do
10
+ describe Win::Gui::Convenience, ' defines convenience/service methods on top of Windows API' do
10
11
  describe '#keystroke' do
11
12
  spec{ use{ keystroke( vkey = 30, vkey = 30) }}
12
- # this service method emulates combinations of (any amount of) keys pressed one after another (Ctrl+Alt+P) and then released
13
- # 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.
14
13
 
15
14
  it 'emulates combinations of keys pressed (Ctrl+Alt+P+M, etc)' do
16
15
  test_app do |app|
@@ -24,21 +23,19 @@ module WinWindowTest
24
23
 
25
24
  describe '#type_in' do
26
25
  spec{ use{ type_in(message = '') }}
27
- # this service method types text message into window holding the focus
28
26
 
29
- it 'types text message into window holding the focus' do
27
+ it 'types text message into the window holding the focus' do
30
28
  test_app do |app|
31
- text = '123 456'
29
+ text = '12 34'
32
30
  type_in(text)
33
31
  app.textarea.text.should =~ Regexp.new(text)
34
- 7.times {keystroke(VK_CONTROL, 'Z'.ord)} # dirty hack!
32
+ 5.times {keystroke(VK_CONTROL, 'Z'.ord)} # dirty hack!
35
33
  end
36
34
  end
37
35
  end
38
36
 
39
37
  describe 'dialog' do
40
38
  spec{ use{ dialog( title ='Dialog Title', timeout_sec = 0.001, &any_block) }}
41
- # me od finds top-level dialog window by title and yields found dialog window to block if given
42
39
 
43
40
  it 'finds top-level dialog window by title' do
44
41
  pending 'Some problems (?with timeouts?) leave window open ~half of the runs'
@@ -58,18 +55,18 @@ module WinWindowTest
58
55
 
59
56
  end
60
57
 
61
- describe Win::Window::Window, ' wrapper class for window handle' do
58
+ describe Win::Gui::Convenience::WrapWindow, ' thin wrapper class around window handle' do
62
59
  before(:each) { @app = launch_test_app }
63
60
  after(:each){ close_test_app }
64
61
 
65
62
  context 'creating' do
66
63
  it 'can be wrapped around any existing window' do
67
64
  any_handle = find_window(nil, nil)
68
- use{ Window.new any_handle }
65
+ use{ WrapWindow.new any_handle }
69
66
  end
70
67
 
71
68
  it 'can be wrapped around specific window' do
72
- use{ Window.new @app.handle }
69
+ use{ WrapWindow.new @app.handle }
73
70
  end
74
71
  end
75
72
 
@@ -77,7 +74,7 @@ module WinWindowTest
77
74
 
78
75
  it 'has handle property equal to underlying window handle' do
79
76
  any_handle = find_window(nil, nil)
80
- any = Window.new any_handle
77
+ any = WrapWindow.new any_handle
81
78
  any.handle.should == any_handle
82
79
  end
83
80
 
@@ -88,26 +85,26 @@ module WinWindowTest
88
85
  it 'closes when asked nicely' do
89
86
  @app.close
90
87
  sleep TEST_SLEEP_DELAY # needed to ensure window had enough time to close down
91
- find_window(nil, TEST_WIN_TITLE).should == nil #!!!!
88
+ find_window(nil, TEST_WIN_TITLE).should == nil #!!!!!
92
89
  end
93
90
 
94
91
  it 'waits f0r window to disappear (NB: this happens before handle is released!)' do
95
92
  start = Time.now
96
93
  @app.close
97
94
  @app.wait_for_close
98
- (Time.now - start).should be <= Win::Window::CLOSE_TIMEOUT
95
+ (Time.now - start).should be <= Win::Gui::Convenience::CLOSE_TIMEOUT
99
96
  window_visible?(@app.handle).should be false
100
97
  end
101
98
  end
102
99
 
103
100
  context '.top_level class method' do
104
101
  it 'finds any top-level window (title = nil) and wraps it in a Window object' do
105
- use { @win = Window.top_level(title = nil, timeout_sec = 3) }
106
- Window.should === @win
102
+ use { @win = WrapWindow.top_level(title = nil, timeout_sec = 3) }
103
+ @win.should be_a_kind_of WrapWindow
107
104
  end
108
105
 
109
106
  it 'finds top-level window by title and wraps it in a Window object' do
110
- win = Window.top_level( TEST_WIN_TITLE, 1)
107
+ win = WrapWindow.top_level( TEST_WIN_TITLE, 1)
111
108
  win.handle.should == @app.handle
112
109
  end
113
110
  end
@@ -177,5 +174,4 @@ module WinWindowTest
177
174
  it 'emulates clicking of the control identified by id'
178
175
  end
179
176
  end
180
-
181
177
  end
@@ -0,0 +1,42 @@
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::Dialog
9
+
10
+ describe Win::Gui::Dialog do
11
+
12
+ describe '#get_dlg_item' do
13
+ spec{ use{ control_handle = get_dlg_item(handle = 0, item_id = 1) }}
14
+ # handle (L) - Handle of the dialog box that contains the control.
15
+ # item_id (I) - Specifies the identifier of the control to be retrieved.
16
+ # Returns (L) - handle of the specified control if success or nil for invalid dialog box handle or a nonexistent control.
17
+ # To get extended error information, call GetLastError.
18
+ # You can use the GetDlgItem function with any parent-child window pair, not just with dialog boxes. As long as the handle
19
+ # parameter specifies a parent window and the child window has a unique id (as specified by the hMenu parameter in the
20
+ # CreateWindow or CreateWindowEx function that created the child window), GetDlgItem returns a valid handle to the child window.
21
+
22
+ it 'returns handle to correctly specified control'
23
+
24
+ it 'does something else' do
25
+ pending
26
+ test_app do |app|
27
+ text = '123 456'
28
+ text.upcase.each_byte do |b| # upcase needed since user32 keybd_event expects upper case chars
29
+ keybd_event(b.ord, 0, KEYEVENTF_KEYDOWN, 0)
30
+ sleep TEST_KEY_DELAY
31
+ keybd_event(b.ord, 0, KEYEVENTF_KEYUP, 0)
32
+ sleep TEST_KEY_DELAY
33
+ end
34
+ app.textarea.text.should =~ Regexp.new(text)
35
+ 7.times {keystroke(VK_CONTROL, 'Z'.ord)} # dirty hack!
36
+ end
37
+ end
38
+ end
39
+
40
+ end
41
+ end
42
+
@@ -0,0 +1,39 @@
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 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 = '123 456'
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
+ app.textarea.text.should =~ Regexp.new(text)
25
+ 7.times {keystroke(VK_CONTROL, 'Z'.ord)} # dirty hack!
26
+ end
27
+ end
28
+ end
29
+
30
+ describe '#mouse_event' do
31
+ it 'Emulates Mouse clicks'
32
+ end
33
+
34
+ describe '#set_cursor_pos' do
35
+ it 'how to test set_cursor_pos?'
36
+ end
37
+ end
38
+ end
39
+
@@ -0,0 +1,43 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+ require 'win/gui/input'
3
+ #require 'win/gui/window'
4
+
5
+ module WinGuiMessageTest
6
+
7
+ include WinTestApp
8
+ include Win::Gui::Message
9
+
10
+ describe Win::Gui::Message do
11
+
12
+ describe '#post_message' do
13
+ spec{ use{ success = post_message(handle = 0, msg = 0, w_param = 0, l_param = 0) }}
14
+ # handle (L) - Handle to the window whose window procedure will receive the message.
15
+ # If this parameter is HWND_BROADCAST, the message is sent to all top-level windows in the system, including disabled or
16
+ # invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows.
17
+ # msg (L) - Specifies the message to be posted.
18
+ # w_param (L) - Specifies additional message-specific information.
19
+ # l_param (L) - Specifies additional message-specific information.
20
+ # returns (L) - Nonzero if success, zero if function failed. To get extended error information, call GetLastError.
21
+
22
+ it 'places (posts) a message in the message queue associated with the thread that created the specified window'
23
+ it 'returns without waiting for the thread to process the message'
24
+ end
25
+
26
+ describe '#send_message' do
27
+ spec{ use{ success = send_message(handle = 0, msg = 0, w_param = 1024, l_param = "\x0"*1024) }}
28
+ # handle (L) - Handle to the window whose window procedure is to receive the message. The following values have special meanings.
29
+ # HWND_BROADCAST - The message is posted to all top-level windows in the system, including disabled or invisible unowned windows,
30
+ # overlapped windows, and pop-up windows. The message is not posted to child windows.
31
+ # NULL - The function behaves like a call to PostThreadMessage with the dwThreadId parameter set to the identifier of the current thread.
32
+ # msg (L) - Specifies the message to be posted.
33
+ # w_param (L) - Specifies additional message-specific information.
34
+ # l_param (L) - Specifies additional message-specific information.
35
+ # return (L) - Nonzero if success, zero if function failed. To get extended error information, call GetLastError.
36
+
37
+ it 'sends the specified message to a window or windows'
38
+ it 'calls the window procedure and does not return until the window procedure has processed the message'
39
+ end
40
+ end
41
+ end
42
+
43
+
@@ -1,40 +1,10 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
- require 'win/window'
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+ require 'win/gui/window'
3
3
 
4
4
  module WinWindowTest
5
5
 
6
- include WinTest
7
- include Win::Window
8
-
9
- def launch_test_app
10
- system TEST_APP_START
11
- sleep TEST_SLEEP_DELAY until (handle = find_window(nil, TEST_WIN_TITLE))
12
-
13
- @launched_test_app = Window.new handle
14
- # app = "Test app" #need to get rid of Window for JRuby
15
- # class << app; self; end.send( :define_method, :handle, &lambda {handle})
16
- # @launched_test_app = app
17
- end
18
-
19
- def close_test_app(app = @launched_test_app)
20
- while app and app.respond_to? :handle and find_window(nil, TEST_WIN_TITLE)
21
- post_message(app.handle, WM_SYSCOMMAND, SC_CLOSE, 0)
22
- sleep TEST_SLEEP_DELAY
23
- end
24
- @launched_test_app = nil
25
- end
26
-
27
- # Creates test app object and yields it back to the block
28
- def test_app
29
- app = launch_test_app
30
-
31
- def app.textarea #define singleton method retrieving app's text area
32
- Window.new find_window_ex(self.handle, 0, TEST_TEXTAREA_CLASS, nil)
33
- end
34
-
35
- yield app
36
- close_test_app
37
- end
6
+ include WinTestApp
7
+ include Win::Gui::Window
38
8
 
39
9
  def commands_should_show_window *cmds, tests
40
10
  cmds.each do |cmd|
@@ -57,8 +27,7 @@ module WinWindowTest
57
27
  end
58
28
  end
59
29
 
60
-
61
- describe Win::Window, ' defines a set user32 API functions related to Window manipulation' do
30
+ describe Win::Gui::Window, ' defines a set user32 API functions related to Window manipulation' do
62
31
  describe '#window?' do
63
32
  spec{ use{ IsWindow(any_handle) }}
64
33
  spec{ use{ is_window(any_handle) }}
@@ -480,65 +449,6 @@ module WinWindowTest
480
449
  end
481
450
  end
482
451
  end
483
-
484
- describe '#keydb_event' do
485
- spec{ use{ keybd_event(vkey = 0, bscan = 0, flags = 0, extra_info = 0) }}
486
-
487
- it 'synthesizes a numeric keystrokes, emulating keyboard driver' do
488
- test_app do |app|
489
- text = '123 456'
490
- text.upcase.each_byte do |b| # upcase needed since user32 keybd_event expects upper case chars
491
- keybd_event(b.ord, 0, KEYEVENTF_KEYDOWN, 0)
492
- sleep TEST_KEY_DELAY
493
- keybd_event(b.ord, 0, KEYEVENTF_KEYUP, 0)
494
- sleep TEST_KEY_DELAY
495
- end
496
- app.textarea.text.should =~ Regexp.new(text)
497
- 7.times {keystroke(VK_CONTROL, 'Z'.ord)} # dirty hack!
498
- end
499
- end
500
- end
501
-
502
- describe '#post_message' do
503
- spec{ use{ success = post_message(handle = 0, msg = 0, w_param = 0, l_param = 0) }}
504
- # handle (L) - Handle to the window whose window procedure will receive the message.
505
- # If this parameter is HWND_BROADCAST, the message is sent to all top-level windows in the system, including disabled or
506
- # invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows.
507
- # msg (L) - Specifies the message to be posted.
508
- # w_param (L) - Specifies additional message-specific information.
509
- # l_param (L) - Specifies additional message-specific information.
510
- # returns (L) - Nonzero if success, zero if function failed. To get extended error information, call GetLastError.
511
-
512
- it 'places (posts) a message in the message queue associated with the thread that created the specified window'
513
- it 'returns without waiting for the thread to process the message'
514
- end
515
-
516
- describe '#send_message' do
517
- spec{ use{ success = send_message(handle = 0, msg = 0, w_param = 1024, l_param = "\x0"*1024) }}
518
- # handle (L) - Handle to the window whose window procedure is to receive the message. The following values have special meanings.
519
- # HWND_BROADCAST - The message is posted to all top-level windows in the system, including disabled or invisible unowned windows,
520
- # overlapped windows, and pop-up windows. The message is not posted to child windows.
521
- # NULL - The function behaves like a call to PostThreadMessage with the dwThreadId parameter set to the identifier of the current thread.
522
- # msg (L) - Specifies the message to be posted.
523
- # w_param (L) - Specifies additional message-specific information.
524
- # l_param (L) - Specifies additional message-specific information.
525
- # return (L) - Nonzero if success, zero if function failed. To get extended error information, call GetLastError.
526
-
527
- it 'sends the specified message to a window or windows'
528
- it 'calls the window procedure and does not return until the window procedure has processed the message'
529
- end
530
-
531
- describe '#get_dlg_item' do
532
- spec{ use{ control_handle = get_dlg_item(handle = 0, item_id = 1) }}
533
- # handle (L) - Handle of the dialog box that contains the control.
534
- # item_id (I) - Specifies the identifier of the control to be retrieved.
535
- # Returns (L) - handle of the specified control if success or nil for invalid dialog box handle or a nonexistent control.
536
- # To get extended error information, call GetLastError.
537
- # You can use the GetDlgItem function with any parent-child window pair, not just with dialog boxes. As long as the handle
538
- # parameter specifies a parent window and the child window has a unique id (as specified by the hMenu parameter in the
539
- # CreateWindow or CreateWindowEx function that created the child window), GetDlgItem returns a valid handle to the child window.
540
-
541
- it 'returns handle to correctly specified control'
542
- end
543
452
  end
544
- end
453
+ end
454
+
@@ -1,7 +1,9 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
2
  require 'win/library'
3
3
 
4
- module WinTest
4
+ module WinLibraryTest
5
+
6
+ include WinTest
5
7
 
6
8
  module MyLib # namespace for defined functions
7
9
  include Win::Library
@@ -40,10 +42,6 @@ module WinTest
40
42
  find_window(nil, nil)
41
43
  end
42
44
 
43
- def not_a_handle
44
- 123
45
- end
46
-
47
45
  def redefined_methods
48
46
  [:FindWindow, :IsWindow, :EnumWindows, :GetComputerName, :GetForegroundWindow]
49
47
  end
@@ -366,6 +364,5 @@ module WinTest
366
364
  expect { enum_windows('Message'){|handle, message| true } }.to_not raise_error
367
365
  end
368
366
  end
369
-
370
367
  end
371
368
  end
data/win.gemspec CHANGED
@@ -5,12 +5,12 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{win}
8
- s.version = "0.0.6"
8
+ s.version = "0.1.0"
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-02-14}
13
- s.description = %q{A collection of pre-defined Windows API functions with Rubyesque interfaces}
12
+ s.date = %q{2010-02-15}
13
+ s.description = %q{Rubyesque interfaces and wrappers for Windows API functions pre-defined using FFI }
14
14
  s.email = %q{arvitallian@gmail.com}
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE",
@@ -28,31 +28,41 @@ Gem::Specification.new do |s|
28
28
  "features/win.feature",
29
29
  "lib/win/dde.rb",
30
30
  "lib/win/extensions.rb",
31
+ "lib/win/gui.rb",
32
+ "lib/win/gui/convenience.rb",
33
+ "lib/win/gui/dialog.rb",
34
+ "lib/win/gui/input.rb",
35
+ "lib/win/gui/message.rb",
36
+ "lib/win/gui/window.rb",
31
37
  "lib/win/library.rb",
32
- "lib/win/window.rb",
33
- "lib/win/window/extra.rb",
34
38
  "spec/spec.opts",
35
39
  "spec/spec_helper.rb",
36
40
  "spec/test_apps/locknote/LockNote.exe",
37
41
  "spec/win/dde_spec.rb",
38
42
  "spec/win/extensions_spec.rb",
43
+ "spec/win/gui/convenience_spec.rb",
44
+ "spec/win/gui/dialog_spec.rb",
45
+ "spec/win/gui/input_spec.rb",
46
+ "spec/win/gui/message_spec.rb",
47
+ "spec/win/gui/window_spec.rb",
39
48
  "spec/win/library_spec.rb",
40
- "spec/win/window/extra_spec.rb",
41
- "spec/win/window_spec.rb",
42
49
  "win.gemspec"
43
50
  ]
44
51
  s.homepage = %q{http://github.com/arvicco/win}
45
52
  s.rdoc_options = ["--charset=UTF-8"]
46
53
  s.require_paths = ["lib"]
47
54
  s.rubygems_version = %q{1.3.5}
48
- s.summary = %q{A collection of pre-defined Windows API functions with Rubyesque interfaces}
55
+ s.summary = %q{Rubyesque interfaces and wrappers for Windows API functions pre-defined using FFI}
49
56
  s.test_files = [
50
57
  "spec/spec_helper.rb",
51
58
  "spec/win/dde_spec.rb",
52
59
  "spec/win/extensions_spec.rb",
53
- "spec/win/library_spec.rb",
54
- "spec/win/window/extra_spec.rb",
55
- "spec/win/window_spec.rb"
60
+ "spec/win/gui/convenience_spec.rb",
61
+ "spec/win/gui/dialog_spec.rb",
62
+ "spec/win/gui/input_spec.rb",
63
+ "spec/win/gui/message_spec.rb",
64
+ "spec/win/gui/window_spec.rb",
65
+ "spec/win/library_spec.rb"
56
66
  ]
57
67
 
58
68
  if s.respond_to? :specification_version then
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: win
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.1.0
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-02-14 00:00:00 +03:00
12
+ date: 2010-02-15 00:00:00 +03:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -42,7 +42,7 @@ dependencies:
42
42
  - !ruby/object:Gem::Version
43
43
  version: "0"
44
44
  version:
45
- description: A collection of pre-defined Windows API functions with Rubyesque interfaces
45
+ description: "Rubyesque interfaces and wrappers for Windows API functions pre-defined using FFI "
46
46
  email: arvitallian@gmail.com
47
47
  executables: []
48
48
 
@@ -63,17 +63,24 @@ files:
63
63
  - features/win.feature
64
64
  - lib/win/dde.rb
65
65
  - lib/win/extensions.rb
66
+ - lib/win/gui.rb
67
+ - lib/win/gui/convenience.rb
68
+ - lib/win/gui/dialog.rb
69
+ - lib/win/gui/input.rb
70
+ - lib/win/gui/message.rb
71
+ - lib/win/gui/window.rb
66
72
  - lib/win/library.rb
67
- - lib/win/window.rb
68
- - lib/win/window/extra.rb
69
73
  - spec/spec.opts
70
74
  - spec/spec_helper.rb
71
75
  - spec/test_apps/locknote/LockNote.exe
72
76
  - spec/win/dde_spec.rb
73
77
  - spec/win/extensions_spec.rb
78
+ - spec/win/gui/convenience_spec.rb
79
+ - spec/win/gui/dialog_spec.rb
80
+ - spec/win/gui/input_spec.rb
81
+ - spec/win/gui/message_spec.rb
82
+ - spec/win/gui/window_spec.rb
74
83
  - spec/win/library_spec.rb
75
- - spec/win/window/extra_spec.rb
76
- - spec/win/window_spec.rb
77
84
  - win.gemspec
78
85
  has_rdoc: true
79
86
  homepage: http://github.com/arvicco/win
@@ -102,11 +109,14 @@ rubyforge_project:
102
109
  rubygems_version: 1.3.5
103
110
  signing_key:
104
111
  specification_version: 3
105
- summary: A collection of pre-defined Windows API functions with Rubyesque interfaces
112
+ summary: Rubyesque interfaces and wrappers for Windows API functions pre-defined using FFI
106
113
  test_files:
107
114
  - spec/spec_helper.rb
108
115
  - spec/win/dde_spec.rb
109
116
  - spec/win/extensions_spec.rb
117
+ - spec/win/gui/convenience_spec.rb
118
+ - spec/win/gui/dialog_spec.rb
119
+ - spec/win/gui/input_spec.rb
120
+ - spec/win/gui/message_spec.rb
121
+ - spec/win/gui/window_spec.rb
110
122
  - spec/win/library_spec.rb
111
- - spec/win/window/extra_spec.rb
112
- - spec/win/window_spec.rb
@@ -1,113 +0,0 @@
1
- require 'win/library'
2
- require 'win/window'
3
-
4
- module Win
5
- module Window
6
- # Wait delay quant
7
- SLEEP_DELAY = 0.001
8
- # Timeout waiting for Window to be closed
9
- CLOSE_TIMEOUT = 1
10
-
11
- # Convenience wrapper methods:
12
-
13
- # emulates combinations of keys pressed (Ctrl+Alt+P+M, etc)
14
- def keystroke(*keys)
15
- return if keys.empty?
16
- keybd_event keys.first, 0, KEYEVENTF_KEYDOWN, 0
17
- sleep KEY_DELAY
18
- keystroke *keys[1..-1]
19
- sleep KEY_DELAY
20
- keybd_event keys.first, 0, KEYEVENTF_KEYUP, 0
21
- end
22
-
23
- # types text message into window holding the focus
24
- def type_in(message)
25
- message.scan(/./m) do |char|
26
- keystroke(*char.to_vkeys)
27
- end
28
- end
29
-
30
- # finds top-level dialog window by title and yields it to given block
31
- def dialog(title, seconds=3)
32
- d = begin
33
- win = Window.top_level(title, seconds)
34
- yield(win) ? win : nil
35
- rescue TimeoutError
36
- end
37
- d.wait_for_close if d
38
- return d
39
- end
40
-
41
-
42
- # Thin class is a thin wrapper around window handle
43
- class Window
44
- include Win::Window
45
- extend Win::Window
46
-
47
- attr_reader :handle
48
-
49
- # find top level window by title, return wrapped Window object
50
- def self.top_level(title, seconds=3)
51
- @handle = timeout(seconds) do
52
- sleep SLEEP_DELAY while (h = find_window nil, title) == nil; h
53
- end
54
- Window.new @handle
55
- end
56
-
57
- def initialize(handle)
58
- @handle = handle
59
- end
60
-
61
- # find child window (control) by title, window class, or control ID:
62
- def child(id)
63
- result = case id
64
- when String
65
- by_title = find_window_ex @handle, 0, nil, id.gsub('_', '&' )
66
- by_class = find_window_ex @handle, 0, id, nil
67
- by_title ? by_title : by_class
68
- when Fixnum
69
- get_dlg_item @handle, id
70
- when nil
71
- find_window_ex @handle, 0, nil, nil
72
- else
73
- nil
74
- end
75
- raise "Control '#{id}' not found" unless result
76
- Window.new result
77
- end
78
-
79
- def children
80
- enum_child_windows(@handle).map{|child_handle| Window.new child_handle}
81
- end
82
-
83
- # emulate click of the control identified by id
84
- def click(id)
85
- h = child(id).handle
86
- rectangle = [0, 0, 0, 0].pack 'LLLL'
87
- get_window_rect h, rectangle
88
- left, top, right, bottom = rectangle.unpack 'LLLL'
89
- center = [(left + right) / 2, (top + bottom) / 2]
90
- set_cursor_pos *center
91
- mouse_event MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0
92
- mouse_event MOUSEEVENTF_LEFTUP, 0, 0, 0, 0
93
- end
94
-
95
- def close
96
- post_message @handle, WM_SYSCOMMAND, SC_CLOSE, 0
97
- end
98
-
99
- def wait_for_close
100
- timeout(CLOSE_TIMEOUT) do
101
- sleep SLEEP_DELAY while window_visible?(@handle)
102
- end
103
- end
104
-
105
- def text
106
- buffer = "\x0" * 2048
107
- length = send_message @handle, WM_GETTEXT, buffer.length, buffer
108
- length == 0 ? '' : buffer[0..length - 1]
109
- end
110
- end
111
-
112
- end
113
- end