win-user32-ruby 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +456 -0
- data/README +3 -0
- data/Rakefile +51 -0
- data/lib/helpers.rb +12 -0
- data/lib/system_const.rb +968 -0
- data/lib/win-user32-ruby.rb +194 -0
- data/lib/winapisys.rb +117 -0
- metadata +69 -0
@@ -0,0 +1,194 @@
|
|
1
|
+
# Author:: Jerry Fernholz
|
2
|
+
# Date:: 21 May 2009
|
3
|
+
#
|
4
|
+
# Functions for simulating window interactions.
|
5
|
+
|
6
|
+
require 'winapisys'
|
7
|
+
require 'timeout'
|
8
|
+
|
9
|
+
module WinUser32Ruby
|
10
|
+
include WinAPISys
|
11
|
+
|
12
|
+
class Window
|
13
|
+
TIMEOUT = 10
|
14
|
+
@handle = nil
|
15
|
+
attr_reader :handle
|
16
|
+
|
17
|
+
def initialize(hwnd)
|
18
|
+
@handle = hwnd
|
19
|
+
end
|
20
|
+
|
21
|
+
def text
|
22
|
+
|
23
|
+
end
|
24
|
+
# Wrapper for +FindWindow+.
|
25
|
+
# +title+:: is the title of the window we are trying to find
|
26
|
+
# +class_name+: is the predefined registered control-class name, generally not used
|
27
|
+
# *Return*:: window handle
|
28
|
+
def self.find_window(title, class_name = nil)
|
29
|
+
fw= user32 'FindWindow', 'PP', 'L'
|
30
|
+
|
31
|
+
begin
|
32
|
+
wnd = timeout(TIMEOUT) {sleep 0.2 while (h = fw.call class_name, title) <= 0; h}
|
33
|
+
rescue TimeoutError
|
34
|
+
return nil
|
35
|
+
end
|
36
|
+
|
37
|
+
Window.new wnd
|
38
|
+
end
|
39
|
+
|
40
|
+
# Wrapper for +FindWindowEx+.
|
41
|
+
# +title+:: is the title of the window we are trying to find
|
42
|
+
# +class_name+: is the predefined registered control-class name, generally not used
|
43
|
+
# *Return*:: window handle
|
44
|
+
def find_window_ex(title, child = 0, class_name = nil)
|
45
|
+
parent = @handle
|
46
|
+
|
47
|
+
fw= user32 'FindWindowEx', 'LLPP', 'L'
|
48
|
+
|
49
|
+
begin
|
50
|
+
wnd = timeout(TIMEOUT) {sleep 0.2 while (h = fw.call parent, child, class_name, title) <= 0; h}
|
51
|
+
rescue TimeoutError
|
52
|
+
return nil
|
53
|
+
end
|
54
|
+
|
55
|
+
Window.new wnd
|
56
|
+
end
|
57
|
+
|
58
|
+
# Wrapper for +GetTopWindow+.
|
59
|
+
# +title+:: is the title of the window we are trying to find
|
60
|
+
# +class_name+: is the predefined registered control-class name, generally not used
|
61
|
+
# *Return*:: window handle
|
62
|
+
def get_top_window
|
63
|
+
parent = @handle
|
64
|
+
fw= user32 'GetTopWindow', 'L', 'L'
|
65
|
+
|
66
|
+
wnd = timeout(TIMEOUT) {sleep 0.2 while (h = fw.call parent) <= 0; h}
|
67
|
+
|
68
|
+
Window.new wnd
|
69
|
+
end
|
70
|
+
|
71
|
+
# Wrapper for +GetTopWindow+.
|
72
|
+
# +title+:: is the title of the window we are trying to find
|
73
|
+
# +class_name+: is the predefined registered control-class name, generally not used
|
74
|
+
# *Return*:: window handle
|
75
|
+
def self.get_top_window
|
76
|
+
parent = 0
|
77
|
+
fw= user32 'GetTopWindow', 'L', 'L'
|
78
|
+
|
79
|
+
wnd = timeout(TIMEOUT) {sleep 0.2 while (h = fw.call parent) <= 0; h}
|
80
|
+
|
81
|
+
Window.new wnd
|
82
|
+
end
|
83
|
+
|
84
|
+
# Wrapper for +GetWindow+.
|
85
|
+
# +hwnd+:: handle to window on which +cmd+ will be called
|
86
|
+
# +cmd+: command to issue to +hwnd+
|
87
|
+
# *Return*:: handle to window according to +cmd+
|
88
|
+
def get_next_child
|
89
|
+
hwnd, cmd = @handle, GW_CHILD
|
90
|
+
fw = user32 'GetWindow', 'LI', 'L'
|
91
|
+
|
92
|
+
Window.new fw.call(hwnd, cmd)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Wrapper for +WM_GETTEXT+.
|
96
|
+
# +hwnd+:: handle to the window whose text we want
|
97
|
+
# *Return*:: window text
|
98
|
+
def get_window_text
|
99
|
+
hwnd = @handle
|
100
|
+
buffer = ' ' * 2048
|
101
|
+
|
102
|
+
length = send_message hwnd, WM_GETTEXT, buffer.length, buffer
|
103
|
+
|
104
|
+
length == 0 ? '' : buffer[0..length - 1]
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
# Wrapper for +GetWindowRect+.
|
109
|
+
# +hwnd+:: handle the window whose rectangle we are trying to get
|
110
|
+
# *Return*:: [left, top, right, bottom]
|
111
|
+
def get_window_rect
|
112
|
+
hwnd = @handle
|
113
|
+
rect = [0, 0, 0, 0].pack("L*")
|
114
|
+
|
115
|
+
gr = user32 'GetWindowRect', 'LP', 'I'
|
116
|
+
|
117
|
+
gr.call hwnd, rect
|
118
|
+
|
119
|
+
left, top, right, bottom = rect.unpack("L*")
|
120
|
+
|
121
|
+
[left, top, right, bottom]
|
122
|
+
end
|
123
|
+
|
124
|
+
def get_center
|
125
|
+
r = get_window_rect
|
126
|
+
[(r[0] + r[2]) / 2, (r[1] + r[3]) / 2]
|
127
|
+
end
|
128
|
+
|
129
|
+
def cursor_center
|
130
|
+
set_cursor_pos(*get_center)
|
131
|
+
end
|
132
|
+
|
133
|
+
def click
|
134
|
+
cursor_center
|
135
|
+
mouse_click
|
136
|
+
end
|
137
|
+
|
138
|
+
# Wrapper for +BringWindowToTop+.
|
139
|
+
# +hwnd+:: handle to window
|
140
|
+
def bring_window_to_top
|
141
|
+
hwnd = @handle
|
142
|
+
b = user32 'BringWindowToTop', 'L', 'I'
|
143
|
+
b.call hwnd
|
144
|
+
end
|
145
|
+
|
146
|
+
# Wrapper for +SetFocus+.
|
147
|
+
# +hwnd+:: handle to window
|
148
|
+
# *Return*:: window handle
|
149
|
+
def set_focus
|
150
|
+
hwnd = @handle
|
151
|
+
b = user32 'SetFocus', 'L', 'L'
|
152
|
+
b.call hwnd
|
153
|
+
end
|
154
|
+
|
155
|
+
# Wrapper for +SetForegroundWindow+.
|
156
|
+
# +hwnd+:: handle to window
|
157
|
+
# *Return*:: true if successful
|
158
|
+
def set_foreground_window
|
159
|
+
hwnd = @handle
|
160
|
+
b = user32 'SetForegroundWindow', 'L', 'I'
|
161
|
+
|
162
|
+
r = b.call hwnd
|
163
|
+
|
164
|
+
sleep 0.5
|
165
|
+
r
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.get_foreground_window
|
169
|
+
b = user32 'GetForegroundWindow', 'V', 'L'
|
170
|
+
|
171
|
+
r = b.call
|
172
|
+
|
173
|
+
sleep 0.5
|
174
|
+
r
|
175
|
+
end
|
176
|
+
|
177
|
+
# Wrapper for +ShowWindow+.
|
178
|
+
# +hwnd+:: handle to window
|
179
|
+
# *Return*:: true if successful
|
180
|
+
def show_window
|
181
|
+
hwnd = @handle
|
182
|
+
b = user32 'ShowWindow', 'LI', 'I'
|
183
|
+
b.call hwnd, SW_RESTORE
|
184
|
+
end
|
185
|
+
|
186
|
+
# Helper to Post Message to close window
|
187
|
+
# +hwnd+:: handle to the window to close
|
188
|
+
def exit!
|
189
|
+
hwnd = @handle
|
190
|
+
send_message hwnd, WM_CLOSE, 0, 0
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
end
|
data/lib/winapisys.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
# Author:: Jerry Fernholz
|
2
|
+
# Date:: 21 May 2009
|
3
|
+
#
|
4
|
+
# System level function for wrapping the Win32API
|
5
|
+
|
6
|
+
module WinAPISys
|
7
|
+
require 'win32/api'
|
8
|
+
include Win32
|
9
|
+
# IMPORTANT: Using Win32 requires some special considerations. Native C
|
10
|
+
# is strongly typed whereas Ruby is not. Therefore we need to give Ruby hints
|
11
|
+
# as to the correct types for any parameters or return_values.
|
12
|
+
#
|
13
|
+
# Win32 type hints:
|
14
|
+
# 'L':: = long
|
15
|
+
# 'I':: = int
|
16
|
+
# 'P':: = Pointer
|
17
|
+
# 'V':: = void
|
18
|
+
# 'K':: = callback
|
19
|
+
# 'S':: = string
|
20
|
+
#
|
21
|
+
# See rdoc for win32-api
|
22
|
+
|
23
|
+
require 'system_const'
|
24
|
+
# Defines a bunch of constants from windows.h and winuser.h
|
25
|
+
|
26
|
+
# Wrap the API call to functions in 'user32.dll' so we don't have to call
|
27
|
+
# <tt>API.new 'user32' ...</tt> repeatedly
|
28
|
+
# +name+:: Name of the Win32 function to be called
|
29
|
+
# +param_type+:: Array of parameter type hints
|
30
|
+
# +return_value+:: Type hint for the return value
|
31
|
+
# Example: <tt>user32 'FindWindow', ['P', 'P'], 'L'</tt>
|
32
|
+
# => calls the <i>FindWindow</i> function
|
33
|
+
def user32(name, param_type, return_value)
|
34
|
+
API.new name, param_type, return_value, 'user32'
|
35
|
+
end
|
36
|
+
|
37
|
+
# Wrapper for +PostMessage+.
|
38
|
+
# +hwnd+:: Handle to the window we're sending the message to
|
39
|
+
# +message+:: message to send
|
40
|
+
# +w_param+:: message specific information
|
41
|
+
# +l_param+:: more message specific information
|
42
|
+
def post_message(hwnd, message, w_param, l_param)
|
43
|
+
pm = user32 'PostMessage', 'LLLL', 'L'
|
44
|
+
pm.call hwnd, message, w_param, l_param
|
45
|
+
end
|
46
|
+
|
47
|
+
# Wrapper for +SendMessage+.
|
48
|
+
# +hwnd+:: Handle to the window we're sending the message to
|
49
|
+
# +message+:: message to send
|
50
|
+
# +w_param+:: message specific information
|
51
|
+
# +l_param+:: more message specific information
|
52
|
+
def send_message(hwnd, message, w_param, l_param)
|
53
|
+
pm = user32 'SendMessage', 'LLLP', 'L'
|
54
|
+
pm.call hwnd, message, w_param, l_param
|
55
|
+
end
|
56
|
+
|
57
|
+
# Wrapper for +SetCursorPos+.
|
58
|
+
# +x+:: x position
|
59
|
+
# +y+:: y position
|
60
|
+
# *Return*:: nonzero if successful or zero otherwise
|
61
|
+
def set_cursor_pos(x, y)
|
62
|
+
s = user32 'SetCursorPos', 'LL', 'I'
|
63
|
+
|
64
|
+
s.call x, y
|
65
|
+
end
|
66
|
+
|
67
|
+
# Simulates a mouse click by pressing and releasing the _left_ mouse button
|
68
|
+
def mouse_click
|
69
|
+
me = user32 'mouse_event', 'LLLLL', 'V'
|
70
|
+
|
71
|
+
me.call MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0
|
72
|
+
me.call MOUSEEVENTF_LEFTUP, 0, 0, 0, 0
|
73
|
+
end
|
74
|
+
|
75
|
+
# Keyboard Event constants
|
76
|
+
KEYEVENTF_KEYDOWN = 0
|
77
|
+
|
78
|
+
# Wrapper for +keydb_event+.
|
79
|
+
# +v_key+:: virtual key code from \http://msdn.microsoft.com/en-us/library/ms645540(VS.85).aspx
|
80
|
+
# +event+:: type of event: KEYEVENTF_KEYDOWN or KEYEVENTF_KEYUP
|
81
|
+
# +hw_scan_code+:: not used
|
82
|
+
# +extra_info+:: not used
|
83
|
+
# *Return*:: none
|
84
|
+
def kb_event(v_key, event, hw_scan_code = 0x0, extra_info = 0)
|
85
|
+
kbe = user32 'keybd_event', %w{I I L L}, 'V'
|
86
|
+
kbe.call v_key, hw_scan_code, event, extra_info
|
87
|
+
sleep 0.05
|
88
|
+
end
|
89
|
+
|
90
|
+
# Simulates key down event
|
91
|
+
def key_up(v_key, scan_code = 0x0)
|
92
|
+
kb_event v_key, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, scan_code
|
93
|
+
end
|
94
|
+
|
95
|
+
# Simulates key down event
|
96
|
+
def key_down(v_key, scan_code = 0x0)
|
97
|
+
kb_event v_key, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYDOWN, scan_code
|
98
|
+
end
|
99
|
+
|
100
|
+
# Simulates key press and release
|
101
|
+
def key_press(v_key, scan_code = 0x0)
|
102
|
+
kb_event v_key, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYDOWN, scan_code
|
103
|
+
kb_event v_key, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, scan_code
|
104
|
+
end
|
105
|
+
|
106
|
+
# Simulates a sequence of keys being pressed, but not released
|
107
|
+
def keys_down(v_keys)
|
108
|
+
raise if !v_keys.is_a?(Array)
|
109
|
+
v_keys.each{|k| key_down k}
|
110
|
+
end
|
111
|
+
|
112
|
+
# Simulates a sequence of keys being released
|
113
|
+
def keys_up(v_keys)
|
114
|
+
raise if !v_keys.is_a?(Array)
|
115
|
+
v_keys.each{|k| key_up k}
|
116
|
+
end
|
117
|
+
end
|
metadata
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: win-user32-ruby
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jerry Fernholz
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-06-04 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: win32-api
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.4.2
|
24
|
+
version:
|
25
|
+
description: Ruby wrapper for the user32.dll on Windows.
|
26
|
+
email: jerry.fernholz@gmail.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- README
|
33
|
+
- LICENSE
|
34
|
+
files:
|
35
|
+
- LICENSE
|
36
|
+
- README
|
37
|
+
- Rakefile
|
38
|
+
- lib/helpers.rb
|
39
|
+
- lib/system_const.rb
|
40
|
+
- lib/win-user32-ruby.rb
|
41
|
+
- lib/winapisys.rb
|
42
|
+
has_rdoc: true
|
43
|
+
homepage:
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options: []
|
46
|
+
|
47
|
+
require_paths:
|
48
|
+
- lib
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "0"
|
60
|
+
version:
|
61
|
+
requirements: []
|
62
|
+
|
63
|
+
rubyforge_project:
|
64
|
+
rubygems_version: 1.3.1
|
65
|
+
signing_key:
|
66
|
+
specification_version: 2
|
67
|
+
summary: Ruby wrapper for the user32.dll on Windows.
|
68
|
+
test_files: []
|
69
|
+
|