Skip to content

Commit

Permalink
Merge branch 'get_window_text'
Browse files Browse the repository at this point in the history
* get_window_text:
  version bump to 0.5.2
  add default window timeouts to specs to minimize spec failures due to timing issues
  whitespace cleanup
  changed to use GetWindowText which is less likely to hang
  • Loading branch information
robertwahler committed Jun 5, 2012
2 parents 8728ee1 + 6527e09 commit 571c0dd
Show file tree
Hide file tree
Showing 12 changed files with 79 additions and 30 deletions.
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
win32-autogui (0.5.1)
win32-autogui (0.5.2)
log4r (>= 1.1.9)
win32-clipboard (~> 0.5.2)
win32-process (~> 0.6.5)
Expand Down
4 changes: 4 additions & 0 deletions HISTORY.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ Most recent changes are at the top
Changes
-------

### 0.5.2 - 06/01/2012 ###

* Retrieving the text of windows and controls is now more robust. Issue #5. (ebertech)

### 0.5.1 - 08/20/2011 ###

* Rebuild gem without psych to work-around the 'invalid gemspec date' issue
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.5.1
0.5.2
28 changes: 20 additions & 8 deletions examples/quicknote/lib/quicknote.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ def initialize(options = {})
super defaults.merge(options)
end

# timeout in seconds to wait for desktop windows to appear
def default_window_timeout
1
end

def edit_window
main_window.children.find {|w| w.window_class == 'TMemo'}
end
Expand All @@ -24,18 +29,21 @@ def status_bar
end

def dialog_about(options={})
options[:timeout] = default_window_timeout unless options[:timeout]
Autogui::EnumerateDesktopWindows.new(options).find do |w|
w.title.match(/^About QuickNote/) && (w.pid == pid)
end
end

def splash(options={})
options[:timeout] = default_window_timeout unless options[:timeout]
Autogui::EnumerateDesktopWindows.new(options).find do |w|
w.title.match(/^FormSplash/) && (w.pid == pid)
end
end

def message_dialog_confirm(options={})
options[:timeout] = default_window_timeout unless options[:timeout]
Autogui::EnumerateDesktopWindows.new(options).find do |w|
w.title.match(/^Confirm/) && (w.pid == pid)
end
Expand All @@ -44,6 +52,7 @@ def message_dialog_confirm(options={})
# Title and class are the same as dialog_overwrite_confirm
# Use child windows to differentiate
def dialog_overwrite_confirm(options={})
options[:timeout] = default_window_timeout unless options[:timeout]
Autogui::EnumerateDesktopWindows.new(options).find do |w|
w.title.match(/^Text File Save$/) &&
(w.pid == pid) &&
Expand All @@ -54,6 +63,7 @@ def dialog_overwrite_confirm(options={})

# Title and class are the same as dialog_overwrite_confirm
def file_save_as_dialog(options={})
options[:timeout] = default_window_timeout unless options[:timeout]
Autogui::EnumerateDesktopWindows.new(options).find do |w|
w.title.match(/^Text File Save/) &&
(w.pid == pid) &&
Expand All @@ -63,12 +73,14 @@ def file_save_as_dialog(options={})
end

def file_open_dialog(options={})
options[:timeout] = default_window_timeout unless options[:timeout]
Autogui::EnumerateDesktopWindows.new(options).find do |w|
w.title.match(/^Text File Open/) && (w.pid == pid)
end
end

def error_dialog(options={})
options[:timeout] = default_window_timeout unless options[:timeout]
Autogui::EnumerateDesktopWindows.new(options).find do |w|
w.title.match(/^QuickNote$/) && (w.pid == pid) && (w.window_class == "#32770")
end
Expand All @@ -78,22 +90,22 @@ def error_dialog(options={})
def file_new(options={})
set_focus
keystroke(VK_MENU, VK_F, VK_N)
if message_dialog_confirm
if message_dialog_confirm(:timeout => 0)
options[:save] == true ? keystroke(VK_Y) : keystroke(VK_N)
end
# sanity check
raise "confirm dialog is still here" if message_dialog_confirm
raise "confirm dialog is still here" if message_dialog_confirm(:timeout => 0)
end

# menu action File, New
def file_open(filename, options={})
set_focus
keystroke(VK_MENU, VK_F, VK_O)
if message_dialog_confirm
if message_dialog_confirm(:timeout => 0)
options[:save] == true ? keystroke(VK_Y) : keystroke(VK_N)
end

raise "sanity check, confirm dialog is still here" if message_dialog_confirm
raise "sanity check, confirm dialog is still here" if message_dialog_confirm(:timeout => 0)
raise "sanity check, file_open_dialog not found" unless file_open_dialog

# Paste in filename for speed, much faster than 'type_in(filename)'
Expand All @@ -106,10 +118,10 @@ def file_open(filename, options={})
# menu action File, Exit
def file_exit
set_focus
keystroke(VK_N) if message_dialog_confirm
keystroke(VK_ESCAPE) if file_open_dialog
keystroke(VK_N) if message_dialog_confirm(:timeout => 0)
keystroke(VK_ESCAPE) if file_open_dialog(:timeout => 0)
keystroke(VK_MENU, VK_F, VK_X)
keystroke(VK_N) if message_dialog_confirm
keystroke(VK_N) if message_dialog_confirm(:timeout => 0)
end

# menu action File, Save
Expand All @@ -132,7 +144,7 @@ def file_save_as(filename, options={})
if dialog_overwrite_confirm
options[:overwrite] == true ? keystroke(VK_Y) : keystroke(VK_N)
end
raise "sanity check, overwrite confirm dialog is still here" if dialog_overwrite_confirm
raise "sanity check, overwrite confirm dialog is still here" if dialog_overwrite_confirm(:timeout => 0)

end

Expand Down
4 changes: 2 additions & 2 deletions examples/quicknote/spec/quicknote/form_about_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
end

before(:each) do
@application.dialog_about.should be_nil
@application.dialog_about(:timeout => 0).should be_nil
@application.set_focus
keystroke(VK_MENU, VK_H, VK_A)
@dialog_about = @application.dialog_about
Expand All @@ -34,7 +34,7 @@
it "should close by hitting return" do
@dialog_about.set_focus
keystroke(VK_RETURN)
@application.dialog_about.should be_nil
@application.dialog_about(:timeout => 0).should be_nil
end

it "should have the title 'About QuickNote'" do
Expand Down
24 changes: 15 additions & 9 deletions examples/quicknote/spec/quicknote/form_main_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
end
after(:each) do
if @application.running?
keystroke(VK_N) if @application.message_dialog_confirm || @application.dialog_overwrite_confirm
keystroke(VK_ESCAPE) if @application.error_dialog
keystroke(VK_N) if @application.message_dialog_confirm(:timeout => 0) || @application.dialog_overwrite_confirm(:timeout => 0)
keystroke(VK_ESCAPE) if @application.error_dialog(:timeout => 0)
end
puts "FormMain after(:each)" if @debug
end
Expand Down Expand Up @@ -67,8 +67,14 @@
@application.file_new(:save => false)
end
after(:each) do
keystroke(VK_N) if @application.message_dialog_confirm
keystroke(VK_ESCAPE) if @application.file_open_dialog
if @application.message_dialog_confirm(:timeout => 0)
@application.message_dialog_confirm.set_focus
keystroke(VK_N)
end
if @application.file_open_dialog(:timeout => 0)
@application.file_open_dialog.set_focus
keystroke(VK_ESCAPE)
end
end

it "should prompt to save with modified text" do
Expand All @@ -80,7 +86,7 @@
it "should not prompt to save with unmodified text" do
@application.main_window.title.should_not match(/\+/)
keystroke(VK_MENU, VK_F, VK_O)
@application.message_dialog_confirm.should be_nil
@application.message_dialog_confirm(:timeout => 0).should be_nil
end

describe "succeeding" do
Expand Down Expand Up @@ -122,7 +128,7 @@
@application.file_new(:save => false)
@application.main_window.title.should_not match(/\+/)
keystroke(VK_MENU, VK_F, VK_N)
@application.message_dialog_confirm.should be_nil
@application.message_dialog_confirm(:timeout => 0).should be_nil
end
it "should add the filename 'untitled.txt' to the title" do
filename = "input_file.txt"
Expand Down Expand Up @@ -222,8 +228,8 @@
@application.file_open(fullpath(@filename), :save => false)
end
after(:each) do
keystroke(VK_N) if @application.dialog_overwrite_confirm
keystroke(VK_ESCAPE) if @application.file_save_as_dialog
keystroke(VK_N) if @application.dialog_overwrite_confirm(:timeout => 0)
keystroke(VK_ESCAPE) if @application.file_save_as_dialog(:timeout => 0)
end

it "should prompt for filename" do
Expand Down Expand Up @@ -266,7 +272,7 @@
end
it "should not prompt to save with unmodified text" do
keystroke(VK_MENU, VK_F, VK_X)
@application.message_dialog_confirm.should be_nil
@application.message_dialog_confirm(:timeout => 0).should be_nil
@application.main_window.is_window?.should == false
@application.should_not be_running
end
Expand Down
6 changes: 3 additions & 3 deletions examples/quicknote/spec/quicknote/form_splash_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
describe "FormSplash" do
after(:each) do
if @application && @application.running?
@application.splash.wait_for_close if @application.splash
@application.splash.wait_for_close if @application.splash(:timeout => 0)
@application.file_exit
# still running? force it to close
@application.close(:wait_for_close => true)
Expand All @@ -30,15 +30,15 @@
timeout(seconds) do
@application.splash.wait_for_close
end
@application.splash.should be_nil
@application.splash(:timeout => 0).should be_nil
end
end

describe "startup with '--nosplash' command line parameter" do
it "should not show" do
@application = Quicknote.new :parameters => '--nosplash'
@application.should be_running
@application.splash.should be_nil
@application.splash(:timeout => 0).should be_nil
end
end

Expand Down
17 changes: 15 additions & 2 deletions lib/win32/autogui/window.rb
Original file line number Diff line number Diff line change
Expand Up @@ -141,19 +141,32 @@ def window_class
length == 0 ? '' : buffer[0..length - 1]
end

# Window text (WM_GETTEXT)
# Window text (GetWindowText or WM_GETTEXT)
#
# @param [Number] max_length (2048)
#
# @return [String] of max_length (2048)
#
def text(max_length = 2048)
buffer = "\0" * max_length
length = SendMessageA(handle, WM_GETTEXT, buffer.length, buffer)
length = if is_control?
SendMessageA(handle, WM_GETTEXT, buffer.length, buffer)
else
GetWindowText(handle, buffer, buffer.length)
end

length == 0 ? '' : buffer[0..length - 1]
end
alias :title :text

# Determines whether the specified window handle identifies a window or a control
#
# @return [Boolean]
#
def is_control?
(handle != 0) && (GetDlgCtrlID(handle) != 0)
end

# Determines whether the specified window handle identifies an existing window
#
# @return [Boolean]
Expand Down
1 change: 1 addition & 0 deletions lib/win32/autogui/windows/window.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ module Window
API.new('SetForegroundWindow', 'L', 'I', 'user32')
API.new('SendMessageA', 'LIIP', 'I', 'user32')
API.new('IsWindowVisible', 'L', 'I', 'user32')
API.new('GetDlgCtrlID', 'L', 'I', 'user32')

end
end
6 changes: 6 additions & 0 deletions spec/applications/calculator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,14 @@ def edit_window
main_window.children.find {|w| w.window_class == 'Edit'}
end

# timeout in seconds to wait for desktop windows to appear
def default_window_timeout
1
end

# About dialog, hotkey (VK_MENU, VK_H, VK_A)
def dialog_about(options = {})
options[:timeout] = default_window_timeout unless options[:timeout]
Autogui::EnumerateDesktopWindows.new(options).find do |w|
w.title.match(/About Calculator/) && (w.pid == pid)
end
Expand Down
11 changes: 9 additions & 2 deletions spec/applications/notepad.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,26 @@ def initialize(options = {})
super defaults.merge(options)
end

# timeout in seconds to wait for desktop windows to appear
def default_window_timeout
1
end

# the notepad's results window
def edit_window
main_window.children.find {|w| w.window_class == 'Edit'}
end

# About dialog, hotkey (VK_MENU, VK_H, VK_A)
def dialog_about(options = {})
options[:timeout] = default_window_timeout unless options[:timeout]
Autogui::EnumerateDesktopWindows.new(options).find do |w|
w.title.match(/About Notepad/) && (w.pid == pid)
end
end

def message_dialog_confirm(options={})
options[:timeout] = default_window_timeout unless options[:timeout]
Autogui::EnumerateDesktopWindows.new(options).find do |w|
w.title.match(/Notepad/) && (w.pid == pid) && (w.window_class == "#32770")
end
Expand All @@ -36,8 +43,8 @@ def message_dialog_confirm(options={})
def file_exit
set_focus
keystroke(VK_MENU, VK_F, VK_X)
if message_dialog_confirm
keystroke(VK_N) if message_dialog_confirm
if message_dialog_confirm(:timeout => 0)
keystroke(VK_N)
end
end

Expand Down
4 changes: 2 additions & 2 deletions spec/auto_gui/application_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,13 @@

it "should open and close the 'About Calculator' dialog via (VK_MENU, VK_H, VK_A)" do
@calculator.set_focus
dialog_about = @calculator.dialog_about
dialog_about = @calculator.dialog_about(:timeout => 0)
dialog_about.should be_nil
keystroke(VK_MENU, VK_H, VK_A)
dialog_about = @calculator.dialog_about
dialog_about.title.should == "About Calculator"
dialog_about.close
@calculator.dialog_about.should be_nil
@calculator.dialog_about(:timeout => 0).should be_nil
end

describe "calculations" do
Expand Down

0 comments on commit 571c0dd

Please sign in to comment.