win_gui 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.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +43 -0
- data/Rakefile +58 -0
- data/VERSION +1 -0
- data/book_code/early_success/bundle.rb +34 -0
- data/book_code/early_success/english.txt +1 -0
- data/book_code/early_success/jruby_basics.rb +47 -0
- data/book_code/early_success/windows_basics.rb +97 -0
- data/book_code/guessing/locknote.rb +379 -0
- data/book_code/guessing/monkeyshines.rb +14 -0
- data/book_code/guessing/note.rb +120 -0
- data/book_code/guessing/note_spec.rb +175 -0
- data/book_code/guessing/replay.rb +21 -0
- data/book_code/guessing/seed.rb +9 -0
- data/book_code/guessing/spec_helper.rb +69 -0
- data/book_code/guessing/windows_gui.rb +247 -0
- data/book_code/home_stretch/junquenote.rb +151 -0
- data/book_code/home_stretch/locknote.rb +180 -0
- data/book_code/home_stretch/note.rb +144 -0
- data/book_code/home_stretch/note_spec.rb +191 -0
- data/book_code/home_stretch/spec_helper.rb +55 -0
- data/book_code/home_stretch/swing_gui.rb +50 -0
- data/book_code/home_stretch/windows_gui.rb +232 -0
- data/book_code/junquenote/exports.sh +10 -0
- data/book_code/junquenote/jruby_mac.sh +10 -0
- data/book_code/junquenote/junquenote_app.rb +262 -0
- data/book_code/novite/Rakefile +10 -0
- data/book_code/novite/app/controllers/application.rb +18 -0
- data/book_code/novite/app/controllers/guests_controller.rb +28 -0
- data/book_code/novite/app/controllers/parties_controller.rb +77 -0
- data/book_code/novite/app/helpers/application_helper.rb +11 -0
- data/book_code/novite/app/helpers/guests_helper.rb +10 -0
- data/book_code/novite/app/helpers/parties_helper.rb +10 -0
- data/book_code/novite/app/models/guest.rb +11 -0
- data/book_code/novite/app/models/party.rb +32 -0
- data/book_code/novite/app/models/party_mailer.rb +19 -0
- data/book_code/novite/app/views/layouts/application.rhtml +44 -0
- data/book_code/novite/app/views/parties/new.html.erb +42 -0
- data/book_code/novite/app/views/parties/show.html.erb +43 -0
- data/book_code/novite/app/views/party_mailer/invite.erb +17 -0
- data/book_code/novite/config/boot.rb +117 -0
- data/book_code/novite/config/database.yml +19 -0
- data/book_code/novite/config/environment.rb +67 -0
- data/book_code/novite/config/environments/development.rb +29 -0
- data/book_code/novite/config/environments/production.rb +27 -0
- data/book_code/novite/config/environments/test.rb +30 -0
- data/book_code/novite/config/initializers/inflections.rb +18 -0
- data/book_code/novite/config/initializers/mime_types.rb +13 -0
- data/book_code/novite/config/routes.rb +47 -0
- data/book_code/novite/db/migrate/001_create_parties.rb +26 -0
- data/book_code/novite/db/migrate/002_create_guests.rb +23 -0
- data/book_code/novite/db/schema.rb +41 -0
- data/book_code/novite/log/empty.txt +0 -0
- data/book_code/novite/public/.htaccess +40 -0
- data/book_code/novite/public/404.html +38 -0
- data/book_code/novite/public/422.html +38 -0
- data/book_code/novite/public/500.html +38 -0
- data/book_code/novite/public/dispatch.cgi +10 -0
- data/book_code/novite/public/dispatch.fcgi +24 -0
- data/book_code/novite/public/dispatch.rb +18 -0
- data/book_code/novite/public/favicon.ico +0 -0
- data/book_code/novite/public/images/rails.png +0 -0
- data/book_code/novite/public/index.html +285 -0
- data/book_code/novite/public/javascripts/application.js +10 -0
- data/book_code/novite/public/javascripts/controls.js +971 -0
- data/book_code/novite/public/javascripts/dragdrop.js +980 -0
- data/book_code/novite/public/javascripts/effects.js +1128 -0
- data/book_code/novite/public/javascripts/prototype.js +4233 -0
- data/book_code/novite/public/robots.txt +5 -0
- data/book_code/novite/script/about +3 -0
- data/book_code/novite/script/console +3 -0
- data/book_code/novite/script/destroy +3 -0
- data/book_code/novite/script/generate +3 -0
- data/book_code/novite/script/performance/benchmarker +3 -0
- data/book_code/novite/script/performance/profiler +3 -0
- data/book_code/novite/script/performance/request +3 -0
- data/book_code/novite/script/plugin +3 -0
- data/book_code/novite/script/process/inspector +3 -0
- data/book_code/novite/script/process/reaper +3 -0
- data/book_code/novite/script/process/spawner +3 -0
- data/book_code/novite/script/runner +3 -0
- data/book_code/novite/script/server +3 -0
- data/book_code/novite/test/test_helper.rb +46 -0
- data/book_code/one_more_thing/applescript.rb +68 -0
- data/book_code/one_more_thing/note_spec.rb +50 -0
- data/book_code/one_more_thing/spec_helper.rb +17 -0
- data/book_code/one_more_thing/textedit-pure.rb +28 -0
- data/book_code/one_more_thing/textedit.applescript +26 -0
- data/book_code/one_more_thing/textedit.rb +32 -0
- data/book_code/one_more_thing/textnote.rb +87 -0
- data/book_code/simplify/junquenote.rb +48 -0
- data/book_code/simplify/locknote.rb +46 -0
- data/book_code/simplify/note.rb +35 -0
- data/book_code/simplify/note_spec.rb +28 -0
- data/book_code/simplify/swing_gui.rb +45 -0
- data/book_code/simplify/windows_gui.rb +232 -0
- data/book_code/simplify/windows_gui_spec.rb +35 -0
- data/book_code/story/invite.story +19 -0
- data/book_code/story/journal.txt +29 -0
- data/book_code/story/novite_stories.rb +156 -0
- data/book_code/story/party.rb +149 -0
- data/book_code/story/password.rb +61 -0
- data/book_code/story/password.story +26 -0
- data/book_code/story/rsvp.story +29 -0
- data/book_code/tables/TestTime.html +93 -0
- data/book_code/tables/TestTimeSample.html +63 -0
- data/book_code/tables/calculate_time.rb +39 -0
- data/book_code/tables/calculator.rb +108 -0
- data/book_code/tables/calculator_actions.rb +27 -0
- data/book_code/tables/calculator_spec.rb +47 -0
- data/book_code/tables/fit.rb +32 -0
- data/book_code/tables/matrix.rb +109 -0
- data/book_code/tables/pseudocode.rb +17 -0
- data/book_code/tubes/book_selenium.rb +67 -0
- data/book_code/tubes/book_watir.rb +60 -0
- data/book_code/tubes/dragdrop.html +81 -0
- data/book_code/tubes/html_capture.rb +33 -0
- data/book_code/tubes/joke_list.rb +67 -0
- data/book_code/tubes/list_spec.rb +41 -0
- data/book_code/tubes/search_spec.rb +32 -0
- data/book_code/tubes/selenium_example.rb +66 -0
- data/book_code/tubes/selenium_link.rb +23 -0
- data/book_code/tubes/web_server.rb +14 -0
- data/book_code/windows/wgui.rb +29 -0
- data/book_code/windows/wobj.rb +25 -0
- data/book_code/windows/wsh.rb +25 -0
- data/book_code/with_rspec/empty_spec.rb +13 -0
- data/book_code/with_rspec/junquenote.rb +60 -0
- data/book_code/with_rspec/locknote.rb +129 -0
- data/book_code/with_rspec/note_spec.rb +32 -0
- data/book_code/with_rspec/should_examples.rb +18 -0
- data/exp/exp.rb +6 -0
- data/exp/exp_encodings.rb +40 -0
- data/exp/exp_enum_windows.rb +60 -0
- data/exp/exp_quik.rb +38 -0
- data/exp/exp_wsh.rb +115 -0
- data/exp/old/windows_basics.rb +80 -0
- data/exp/old/wnote.rb +80 -0
- data/exp/old/wnote_spec.rb +20 -0
- data/features/step_definitions/win_gui_steps.rb +0 -0
- data/features/support/env.rb +4 -0
- data/features/win_gui.feature +9 -0
- data/lib/note/java/jemmy.jar +0 -0
- data/lib/note/java/jnote.rb +48 -0
- data/lib/note/java/jruby_basics.rb +37 -0
- data/lib/note/java/junquenote_app.rb +262 -0
- data/lib/note/java/note_spec.rb +20 -0
- data/lib/note/win/locknote.rb +19 -0
- data/lib/note.rb +15 -0
- data/lib/win_gui/constants.rb +66 -0
- data/lib/win_gui/string_extensions.rb +24 -0
- data/lib/win_gui/win_gui.rb +274 -0
- data/lib/win_gui/window.rb +70 -0
- data/lib/win_gui.rb +3 -0
- data/spec/note/win/locknote_spec.rb +7 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +100 -0
- data/spec/test_apps/locknote/LockNote.exe +0 -0
- data/spec/win_gui/string_extensions_spec.rb +61 -0
- data/spec/win_gui/win_gui_spec.rb +733 -0
- data/spec/win_gui/window_spec.rb +124 -0
- metadata +251 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module WinGui
|
|
2
|
+
class Window
|
|
3
|
+
include WinGui
|
|
4
|
+
extend WinGui
|
|
5
|
+
|
|
6
|
+
attr_reader :handle
|
|
7
|
+
|
|
8
|
+
# find top level window by title, return wrapped Window object
|
|
9
|
+
def self.top_level(title, seconds=3)
|
|
10
|
+
@handle = timeout(seconds) do
|
|
11
|
+
sleep WG_SLEEP_DELAY while (h = find_window nil, title) == nil; h
|
|
12
|
+
end
|
|
13
|
+
Window.new @handle
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def initialize(handle)
|
|
17
|
+
@handle = handle
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# find child window (control) by title, window class, or control ID:
|
|
21
|
+
def child(id)
|
|
22
|
+
result = case id
|
|
23
|
+
when String
|
|
24
|
+
by_title = find_window_ex @handle, 0, nil, id.gsub('_' , '&' )
|
|
25
|
+
by_class = find_window_ex @handle, 0, id, nil
|
|
26
|
+
by_title ? by_title : by_class
|
|
27
|
+
when Fixnum
|
|
28
|
+
get_dlg_item @handle, id
|
|
29
|
+
when nil
|
|
30
|
+
find_window_ex @handle, 0, nil, nil
|
|
31
|
+
else
|
|
32
|
+
nil
|
|
33
|
+
end
|
|
34
|
+
raise "Control '#{id}' not found" unless result
|
|
35
|
+
Window.new result
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def children
|
|
39
|
+
enum_child_windows(@handle,'Msg').map{|child_handle| Window.new child_handle}
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# emulate click of the control identified by id
|
|
43
|
+
def click(id)
|
|
44
|
+
h = child(id).handle
|
|
45
|
+
rectangle = [0, 0, 0, 0].pack 'LLLL'
|
|
46
|
+
get_window_rect h, rectangle
|
|
47
|
+
left, top, right, bottom = rectangle.unpack 'LLLL'
|
|
48
|
+
center = [(left + right) / 2, (top + bottom) / 2]
|
|
49
|
+
set_cursor_pos *center
|
|
50
|
+
mouse_event MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0
|
|
51
|
+
mouse_event MOUSEEVENTF_LEFTUP, 0, 0, 0, 0
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def close
|
|
55
|
+
post_message @handle, WM_SYSCOMMAND, SC_CLOSE, 0
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def wait_for_close
|
|
59
|
+
timeout(WG_CLOSE_TIMEOUT) do
|
|
60
|
+
sleep WG_SLEEP_DELAY while window_visible?(@handle)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def text
|
|
65
|
+
buffer = "\x0" * 2048
|
|
66
|
+
length = send_message @handle, WM_GETTEXT, buffer.length, buffer
|
|
67
|
+
length == 0 ? '' : buffer[0..length - 1]
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
data/lib/win_gui.rb
ADDED
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
lib_dir = File.join(File.dirname(__FILE__),".." ,"lib" )
|
|
2
|
+
$LOAD_PATH.unshift lib_dir unless $LOAD_PATH.include?(lib_dir)
|
|
3
|
+
require 'spec'
|
|
4
|
+
require 'win_gui'
|
|
5
|
+
require 'note'
|
|
6
|
+
|
|
7
|
+
# Customize RSpec with my own extensions
|
|
8
|
+
module SpecMacros
|
|
9
|
+
|
|
10
|
+
# wrapper for it method that extracts description from example source code, such as:
|
|
11
|
+
# spec { use{ function(arg1 = 4, arg2 = 'string') }}
|
|
12
|
+
def spec &block
|
|
13
|
+
it description_from(*block.source_location), &block
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# reads description line from source file and drops external brackets (like its{}, use{}
|
|
17
|
+
def description_from(file, line)
|
|
18
|
+
File.open(file) do |f|
|
|
19
|
+
f.lines.to_a[line-1].gsub( /(spec.*?{)|(use.*?{)|}/, '' ).strip
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
Spec::Runner.configure { |config| config.extend(SpecMacros) }
|
|
25
|
+
|
|
26
|
+
module GuiTest
|
|
27
|
+
include WinGui
|
|
28
|
+
|
|
29
|
+
# Test related Constants:
|
|
30
|
+
TEST_TIMEOUT = 0.001
|
|
31
|
+
TEST_KEY_DELAY = 0.001
|
|
32
|
+
TEST_SLEEP_DELAY = 0.01
|
|
33
|
+
TEST_APP_PATH = File.join(File.dirname(__FILE__), "test_apps/locknote/LockNote.exe" )
|
|
34
|
+
TEST_APP_START = 'start "" "' + TEST_APP_PATH + '"'
|
|
35
|
+
TEST_WIN_TITLE = 'LockNote - Steganos LockNote'
|
|
36
|
+
TEST_WIN_CLASS = 'ATL:00434098'
|
|
37
|
+
TEST_WIN_RECT = [710, 400, 1210, 800]
|
|
38
|
+
TEST_MAX_RECT = [-4, -4, 1924, 1204] # on my 1920x1200 display
|
|
39
|
+
TEST_MIN_RECT = [-32000, -32000, -31840, -31976]
|
|
40
|
+
TEST_TEXTAREA_CLASS = 'ATL:00434310'
|
|
41
|
+
TEST_IMPOSSIBLE = 'Impossible'
|
|
42
|
+
TEST_ERROR_CONVERSION = /Can.t convert/
|
|
43
|
+
|
|
44
|
+
# Helper methods:
|
|
45
|
+
def use
|
|
46
|
+
lambda {yield}.should_not raise_error
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def any_handle
|
|
50
|
+
find_window(nil, nil)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def any_block
|
|
54
|
+
lambda {|*args| args}
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def hide_method(name) # hide original method if it is defined
|
|
58
|
+
WinGui.module_eval do
|
|
59
|
+
if method_defined? name.to_sym
|
|
60
|
+
alias_method "orig_#{name.to_s}".to_sym, name.to_sym
|
|
61
|
+
remove_method name.to_sym
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def restore_method(name) # restore original method if it was hidden
|
|
67
|
+
WinGui.module_eval do
|
|
68
|
+
temp = "orig_#{name.to_s}".to_sym
|
|
69
|
+
if method_defined? temp
|
|
70
|
+
alias_method name.to_sym, temp
|
|
71
|
+
remove_method temp
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def launch_test_app
|
|
77
|
+
system TEST_APP_START
|
|
78
|
+
sleep TEST_SLEEP_DELAY until (handle = find_window(nil, TEST_WIN_TITLE))
|
|
79
|
+
@launched_test_app = Window.new handle
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def close_test_app(app = @launched_test_app)
|
|
83
|
+
while app and app.respond_to? :handle and find_window(nil, TEST_WIN_TITLE)
|
|
84
|
+
post_message(app.handle, WM_SYSCOMMAND, SC_CLOSE, 0)
|
|
85
|
+
sleep TEST_SLEEP_DELAY
|
|
86
|
+
end
|
|
87
|
+
@launched_test_app = nil
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Creates test app object and yields it back to the block
|
|
91
|
+
def test_app
|
|
92
|
+
app = launch_test_app
|
|
93
|
+
def app.textarea #define singleton method retrieving app's text area
|
|
94
|
+
Window.new find_window_ex(self.handle, 0, TEST_TEXTAREA_CLASS, nil)
|
|
95
|
+
end
|
|
96
|
+
yield app
|
|
97
|
+
close_test_app
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
end
|
|
Binary file
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), ".." , "spec_helper" )
|
|
2
|
+
|
|
3
|
+
module GuiTest
|
|
4
|
+
|
|
5
|
+
describe String do
|
|
6
|
+
context '#snake_case' do
|
|
7
|
+
it 'transforms CamelCase strings' do
|
|
8
|
+
'GetCharWidth32'.snake_case.should == 'get_char_width_32'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it 'leaves snake_case strings intact' do
|
|
12
|
+
'keybd_event'.snake_case.should == 'keybd_event'
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
context '#to_w' do
|
|
17
|
+
it 'transcodes string to utf-16LE' do
|
|
18
|
+
'GetCharWidth32'.to_w.encoding.name.should == 'UTF-16LE'
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'ensures that encoded string is null-terminated' do
|
|
22
|
+
'GetCharWidth32'.to_w.bytes.to_a[-2..-1].should == [0, 0]
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
context '#to_vkeys' do
|
|
27
|
+
it 'transforms number char into [equivalent key code]' do
|
|
28
|
+
('0'..'9').each {|char| char.to_vkeys.should == char.unpack('C')}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'transforms uppercase letters into [shift, equivalent key code]' do
|
|
32
|
+
('A'..'Z').each {|char| char.to_vkeys.should == [VK_SHIFT, *char.unpack('C')]}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'transforms lowercase letters into [(upcase) key code]' do
|
|
36
|
+
('a'..'z').each {|char| char.to_vkeys.should == char.upcase.unpack('C')}
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'transforms space into [equivalent key code]' do
|
|
40
|
+
" ".to_vkeys.should == " ".unpack('C')
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'raises error if char is not implemented punctuation' do
|
|
44
|
+
('!'..'/').each {|char| lambda {char.to_vkeys}.should raise_error TEST_ERROR_CONVERSION }
|
|
45
|
+
(':'..'@').each {|char| lambda {char.to_vkeys}.should raise_error TEST_ERROR_CONVERSION }
|
|
46
|
+
('['..'`').each {|char| lambda {char.to_vkeys}.should raise_error TEST_ERROR_CONVERSION }
|
|
47
|
+
('{'..'~').each {|char| lambda {char.to_vkeys}.should raise_error TEST_ERROR_CONVERSION }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'raises error if char is non-printable or non-ascii' do
|
|
51
|
+
lambda {1.chr.to_vkeys}.should raise_error TEST_ERROR_CONVERSION
|
|
52
|
+
lambda {230.chr.to_vkeys}.should raise_error TEST_ERROR_CONVERSION
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'raises error if string is multi-char' do
|
|
56
|
+
lambda {'hello'.to_vkeys}.should raise_error TEST_ERROR_CONVERSION
|
|
57
|
+
lambda {'23'.to_vkeys}.should raise_error TEST_ERROR_CONVERSION
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|