win 0.0.6 → 0.1.0

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.
@@ -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