win-user32-ruby 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/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
|
+
|