win 0.0.6 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +45 -20
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/lib/win/dde.rb +13 -15
- data/lib/win/extensions.rb +1 -1
- data/lib/win/gui/convenience.rb +142 -0
- data/lib/win/gui/dialog.rb +15 -0
- data/lib/win/gui/input.rb +255 -0
- data/lib/win/gui/message.rb +22 -0
- data/lib/win/gui/window.rb +497 -0
- data/lib/win/gui.rb +17 -0
- data/lib/win/library.rb +10 -9
- data/spec/spec_helper.rb +53 -15
- data/spec/win/dde_spec.rb +1 -0
- data/spec/win/extensions_spec.rb +1 -1
- data/spec/win/{window/extra_spec.rb → gui/convenience_spec.rb} +19 -23
- data/spec/win/gui/dialog_spec.rb +42 -0
- data/spec/win/gui/input_spec.rb +39 -0
- data/spec/win/gui/message_spec.rb +43 -0
- data/spec/win/{window_spec.rb → gui/window_spec.rb} +7 -97
- data/spec/win/library_spec.rb +3 -6
- data/win.gemspec +21 -11
- metadata +20 -10
- data/lib/win/window/extra.rb +0 -113
- data/lib/win/window.rb +0 -608
data/README.rdoc
CHANGED
@@ -15,19 +15,19 @@ This is still work in progress, only a small portion of Windows API wrapped so f
|
|
15
15
|
== SUMMARY
|
16
16
|
|
17
17
|
So you want to write a simple program that makes some Windows API function calls.
|
18
|
-
You searched MSDN high and low and you
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
18
|
+
You searched MSDN high and low and you know exactly what functions you need.
|
19
|
+
You just want to put these function calls into your Ruby code without too much pain.
|
20
|
+
You'd love this to be more or less natural extension of your Ruby code, preferably
|
21
|
+
not turning your code base into an ugly spaghetty of CamelCase calls, String/Array
|
22
|
+
pack/unpack gymnastics, buffer/pointer allocations, extracting return values
|
23
|
+
from [in/out] parameters and checking return codes for 0.
|
24
24
|
|
25
25
|
You have several options at this point. You can use 'win32-api' or 'ffi' libraries
|
26
26
|
to connect your ruby code to Windows API and manually define wrapper methods for
|
27
27
|
needed function calls. This is definitely a valid approach, even if it is a bit
|
28
|
-
low-level one: you'll have to handle (somewhat) gory details of callback
|
29
|
-
argument preparation, mimicking pointers with Strings
|
30
|
-
with FFI and other stuff (like manually
|
28
|
+
low-level one: you'll have to handle (somewhat) gory details of callback announcements,
|
29
|
+
argument preparation, mimicking pointers with Strings, declaring pointers explicitly
|
30
|
+
with FFI and other stuff (like manually assigning about a gazillion obscure Windows
|
31
31
|
constants). As an example, consider the amount of code needed to complete a task as
|
32
32
|
simple as getting unicode title text for the window that you already have handle for
|
33
33
|
(using win32-api):
|
@@ -68,7 +68,7 @@ It helps you to cut some of the declaration slack though:
|
|
68
68
|
buffer.force_encoding('utf-16LE').encode('utf-8').rstrip
|
69
69
|
end
|
70
70
|
|
71
|
-
But still it seems like TOO MUCH code for something that should (ideally) look like this:
|
71
|
+
But still, it seems like TOO MUCH code for something that should (ideally) look like this:
|
72
72
|
|
73
73
|
title = window_text_w(window_handle)
|
74
74
|
|
@@ -78,8 +78,8 @@ natural inside Ruby code. Following the principle of least surprise, we define w
|
|
78
78
|
* Require minimum arguments with sensible defaults
|
79
79
|
* Return appropriate values explicitly (several return values if necessary)
|
80
80
|
* Have sensible returns (false/true instead of 0/nonzero for test functions, nil if find function fails, etc)
|
81
|
-
* Accept blocks where callback is
|
82
|
-
* Are partitioned into
|
81
|
+
* Accept blocks where callback is needed, provide default callback if no block given
|
82
|
+
* Are partitioned into appropriate namespaces, so that you can load only the modules you really need
|
83
83
|
|
84
84
|
Well, we even keep a backup solution for those diehard Win32 API longtimers who would rather
|
85
85
|
allocate their buffer strings by hand and mess with obscure return codes. If you use original
|
@@ -94,10 +94,10 @@ such as DMLERR_NO_ERROR, APPCLASS_STANDARD, etc. So if you need only DDE-related
|
|
94
94
|
there is no need to load all the other modules, clogging your namespaces - just require 'win/dde'
|
95
95
|
and be done with it.
|
96
96
|
|
97
|
-
And if you do not see your favorite Windows API functions
|
98
|
-
quite easy to 'include Win::Library' into your module and define new ones with 'function'
|
99
|
-
|
100
|
-
|
97
|
+
And if you do not see your favorite Windows API functions among those already defined, it is
|
98
|
+
quite easy to 'include Win::Library' into your module and define new ones with 'function' macro -
|
99
|
+
it does a lot of heavy lifting for you and can be customized with options and code blocks to give
|
100
|
+
you reusable API wrapper methods with the exact behavior you need.
|
101
101
|
|
102
102
|
== REQUIREMENTS:
|
103
103
|
|
@@ -114,20 +114,45 @@ Contributors always welcome!
|
|
114
114
|
$ gem install win
|
115
115
|
|
116
116
|
== SYNOPSIS
|
117
|
+
=== Using pre-defined Windows API functions:
|
117
118
|
|
118
|
-
require 'win/
|
119
|
+
require 'win/gui'
|
119
120
|
|
120
121
|
class MyClass
|
121
|
-
include Win::Window
|
122
|
+
include Win::Gui::Window
|
122
123
|
|
123
124
|
fg_window = foreground_window
|
124
125
|
puts window_text(fg_window)
|
125
126
|
show_window(fg_window) unless minimized?(fg_window)
|
126
|
-
hide_window(fg_window) if maximized?(fg_window)
|
127
127
|
...
|
128
128
|
end
|
129
129
|
|
130
|
-
|
130
|
+
=== Defining your own Windows API functions:
|
131
|
+
|
132
|
+
require 'win/library'
|
133
|
+
|
134
|
+
module YourLibModule
|
135
|
+
include Win::Library
|
136
|
+
|
137
|
+
# Customizing method behavior: zeronil forces function to return nil instead of 0, rename renames method
|
138
|
+
function :FindWindow, [:pointer, :pointer], :ulong, zeronil: true, rename: my_find
|
139
|
+
|
140
|
+
# Customizing even further: your own method extension in attached block
|
141
|
+
function :GetWindowText, [ :pointer, :pointer, :int ], :int do |api, handle|
|
142
|
+
buffer = FFI::MemoryPointer.new :char, 512
|
143
|
+
buffer.put_string(0, "\x00" * 511)
|
144
|
+
num_chars = api.call(handle, buffer, 512)
|
145
|
+
return nil if num_chars == 0
|
146
|
+
string = buffer.get_bytes(0, num_chars)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
extend YourLibModule
|
151
|
+
|
152
|
+
handle = my_find(nil, nil) # find ANY window
|
153
|
+
puts window_text(handle) # print window title
|
154
|
+
|
155
|
+
== PRIOR ART:
|
131
156
|
|
132
157
|
This library started as an extension of ideas and code described in excellent book
|
133
158
|
"Scripted GUI Testing with Ruby" by Ian Dees. 'win32-api' and 'windows-pr' gems by
|
data/Rakefile
CHANGED
@@ -5,8 +5,8 @@ begin
|
|
5
5
|
require 'jeweler'
|
6
6
|
Jeweler::Tasks.new do |gem|
|
7
7
|
gem.name = "win"
|
8
|
-
gem.summary = %Q{
|
9
|
-
gem.description = %Q{
|
8
|
+
gem.summary = %Q{Rubyesque interfaces and wrappers for Windows API functions pre-defined using FFI }
|
9
|
+
gem.description = %Q{Rubyesque interfaces and wrappers for Windows API functions pre-defined using FFI }
|
10
10
|
gem.email = "arvitallian@gmail.com"
|
11
11
|
gem.homepage = "http://github.com/arvicco/win"
|
12
12
|
gem.authors = ["arvicco"]
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/lib/win/dde.rb
CHANGED
@@ -122,17 +122,7 @@ module Win
|
|
122
122
|
#
|
123
123
|
function 'RegisterClipboardFormat', 'P', 'I', zeronil: true
|
124
124
|
|
125
|
-
#
|
126
|
-
# into Dde callback and registered with DdeInitialize. Returns DDE init status and DDE instance id.
|
127
|
-
#
|
128
|
-
return_id_status = ->(api, id=0, cmd, &block){
|
129
|
-
raise ArgumentError, 'No callback block' unless block
|
130
|
-
|
131
|
-
status = api.call(id = [id].pack('L'), block, cmd, 0)
|
132
|
-
id = status == 0 ? id.unpack('L').first : nil
|
133
|
-
[id, status] }
|
134
|
-
|
135
|
-
# DdeCallabck declaration
|
125
|
+
# DdeCallaback declaration
|
136
126
|
# MSDN syntax: HDDEDATA CALLBACK DdeCallback( UINT uType, UINT uFmt, HCONV hconv, HDDEDATA hsz1, HDDEDATA hsz2,
|
137
127
|
# HDDEDATA hdata, HDDEDATA dwData1, HDDEDATA dwData2);
|
138
128
|
callback :dde_callback, [:uint, :uint, :HCONV, :HDDEDATA, :HDDEDATA, :HDDEDATA, :HDDEDATA, :HDDEDATA], :HDDEDATA
|
@@ -187,7 +177,15 @@ module Win
|
|
187
177
|
# :call-seq:
|
188
178
|
# id_inst, status = dde_initialize( id_inst = 0, cmd ) {|callback args| callback block}
|
189
179
|
#
|
190
|
-
function 'DdeInitialize', [:pointer, :dde_callback, :DWORD, :DWORD], :uint,
|
180
|
+
function 'DdeInitialize', [:pointer, :dde_callback, :DWORD, :DWORD], :uint,
|
181
|
+
&->(api, old_id=0, cmd, &block){
|
182
|
+
raise ArgumentError, 'No callback block' unless block
|
183
|
+
id = FFI::MemoryPointer.new(:long)
|
184
|
+
id.write_long(old_id)
|
185
|
+
status = api.call(id, block, cmd, 0)
|
186
|
+
id = status == 0 ? id.read_long() : nil
|
187
|
+
[id, status] }
|
188
|
+
# weird lambda literal instead of block is needed because RDoc goes crazy if block is attached to meta-definition
|
191
189
|
|
192
190
|
##
|
193
191
|
# The DdeCreateStringHandle function creates a handle that identifies the specified string.
|
@@ -209,7 +207,7 @@ module Win
|
|
209
207
|
# Return Value (L) or nil: If the function succeeds, the return value is a string handle.
|
210
208
|
# If the function fails, the return value is 0(changed to nil in enhanced version).
|
211
209
|
# The DdeGetLastError function can be used to get the error code, which can be one of the following values:
|
212
|
-
#DMLERR_NO_ERROR, DMLERR_INVALIDPARAMETER, DMLERR_SYS_ERROR
|
210
|
+
# DMLERR_NO_ERROR, DMLERR_INVALIDPARAMETER, DMLERR_SYS_ERROR
|
213
211
|
#
|
214
212
|
# Remarks: The value of a string handle is not related to the case of the string it identifies.
|
215
213
|
# When an application either creates a string handle or receives one in the callback function
|
@@ -217,7 +215,7 @@ module Win
|
|
217
215
|
# handle when it is no longer needed. An instance-specific string handle cannot be mapped from string
|
218
216
|
# handle to string and back to string handle.
|
219
217
|
#
|
220
|
-
function 'DdeCreateStringHandle', [:DWORD, :pointer, :int], :HSZ
|
218
|
+
function 'DdeCreateStringHandle', [:DWORD, :pointer, :int], :HSZ, zeronil: true
|
221
219
|
|
222
220
|
end
|
223
|
-
end
|
221
|
+
end
|
data/lib/win/extensions.rb
CHANGED
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'win/library'
|
2
|
+
require 'win/gui/window'
|
3
|
+
require 'win/gui/message'
|
4
|
+
require 'win/gui/input'
|
5
|
+
|
6
|
+
module Win
|
7
|
+
module Gui
|
8
|
+
# Contains convenience methods and extra wrappers for Windows Gui related functions
|
9
|
+
#
|
10
|
+
module Convenience
|
11
|
+
include Win::Gui::Window
|
12
|
+
include Win::Gui::Message
|
13
|
+
include Win::Gui::Input
|
14
|
+
|
15
|
+
# Internal constants:
|
16
|
+
|
17
|
+
# Key event delay
|
18
|
+
KEY_DELAY = 0.00001
|
19
|
+
# Wait delay
|
20
|
+
SLEEP_DELAY = 0.001
|
21
|
+
# Timeout waiting for Window to be closed
|
22
|
+
CLOSE_TIMEOUT = 1
|
23
|
+
|
24
|
+
# Convenience wrapper methods:
|
25
|
+
|
26
|
+
# Hides the window and activates another window
|
27
|
+
def hide_window(win_handle)
|
28
|
+
show_window(win_handle, SW_HIDE)
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# Tests if given window handle points to foreground (topmost) window
|
33
|
+
#
|
34
|
+
def foreground?(win_handle)
|
35
|
+
win_handle == foreground_window
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# Emulates combinations of (any amount of) keys pressed one after another (Ctrl+Alt+P) and then released
|
40
|
+
# *keys should be a sequence of a virtual-key codes. The codes must be a value in the range 1 to 254.
|
41
|
+
# For a complete list, see msdn:Virtual Key Codes.
|
42
|
+
def keystroke(*keys)
|
43
|
+
return if keys.empty?
|
44
|
+
keybd_event keys.first, 0, KEYEVENTF_KEYDOWN, 0
|
45
|
+
sleep KEY_DELAY
|
46
|
+
keystroke *keys[1..-1]
|
47
|
+
sleep KEY_DELAY
|
48
|
+
keybd_event keys.first, 0, KEYEVENTF_KEYUP, 0
|
49
|
+
end
|
50
|
+
|
51
|
+
# types text message into window holding the focus
|
52
|
+
def type_in(message)
|
53
|
+
message.scan(/./m) do |char|
|
54
|
+
keystroke(*char.to_vkeys)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# finds top-level dialog window by title and yields found dialog window to block if given
|
59
|
+
def dialog(title, seconds=3)
|
60
|
+
d = begin
|
61
|
+
win = WrapWindow.top_level(title, seconds)
|
62
|
+
yield(win) ? win : nil
|
63
|
+
rescue TimeoutError
|
64
|
+
end
|
65
|
+
d.wait_for_close if d
|
66
|
+
return d
|
67
|
+
end
|
68
|
+
|
69
|
+
# This class is a thin wrapper around window handle
|
70
|
+
class WrapWindow
|
71
|
+
include Win::Gui::Window
|
72
|
+
extend Win::Gui::Window
|
73
|
+
include Win::Gui::Message
|
74
|
+
|
75
|
+
attr_reader :handle
|
76
|
+
|
77
|
+
# find top level window by title, return wrapped Window object
|
78
|
+
def self.top_level(title, seconds=3)
|
79
|
+
@handle = timeout(seconds) do
|
80
|
+
sleep SLEEP_DELAY while (h = find_window nil, title) == nil; h
|
81
|
+
end
|
82
|
+
WrapWindow.new @handle
|
83
|
+
end
|
84
|
+
|
85
|
+
def initialize(handle)
|
86
|
+
@handle = handle
|
87
|
+
end
|
88
|
+
|
89
|
+
# find child window (control) by title, window class, or control ID:
|
90
|
+
def child(id)
|
91
|
+
result = case id
|
92
|
+
when String
|
93
|
+
by_title = find_window_ex @handle, 0, nil, id.gsub('_', '&' )
|
94
|
+
by_class = find_window_ex @handle, 0, id, nil
|
95
|
+
by_title ? by_title : by_class
|
96
|
+
when Fixnum
|
97
|
+
get_dlg_item @handle, id
|
98
|
+
when nil
|
99
|
+
find_window_ex @handle, 0, nil, nil
|
100
|
+
else
|
101
|
+
nil
|
102
|
+
end
|
103
|
+
raise "Control '#{id}' not found" unless result
|
104
|
+
WrapWindow.new result
|
105
|
+
end
|
106
|
+
|
107
|
+
def children
|
108
|
+
enum_child_windows(@handle).map{|child_handle| WrapWindow.new child_handle}
|
109
|
+
end
|
110
|
+
|
111
|
+
# emulate click of the control identified by id
|
112
|
+
def click(id)
|
113
|
+
h = child(id).handle
|
114
|
+
rectangle = [0, 0, 0, 0].pack 'LLLL'
|
115
|
+
get_window_rect h, rectangle
|
116
|
+
left, top, right, bottom = rectangle.unpack 'LLLL'
|
117
|
+
center = [(left + right) / 2, (top + bottom) / 2]
|
118
|
+
set_cursor_pos *center
|
119
|
+
mouse_event MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0
|
120
|
+
mouse_event MOUSEEVENTF_LEFTUP, 0, 0, 0, 0
|
121
|
+
end
|
122
|
+
|
123
|
+
def close
|
124
|
+
post_message @handle, WM_SYSCOMMAND, SC_CLOSE, 0
|
125
|
+
end
|
126
|
+
|
127
|
+
def wait_for_close
|
128
|
+
timeout(CLOSE_TIMEOUT) do
|
129
|
+
sleep SLEEP_DELAY while window_visible?(@handle)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def text
|
134
|
+
buffer = "\x0" * 2048
|
135
|
+
length = send_message @handle, WM_GETTEXT, buffer.length, buffer
|
136
|
+
length == 0 ? '' : buffer[0..length - 1]
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
@@ -0,0 +1,255 @@
|
|
1
|
+
require 'win/library'
|
2
|
+
|
3
|
+
module Win
|
4
|
+
module Gui
|
5
|
+
# Contains constants and Win32API functions related to end user input
|
6
|
+
#
|
7
|
+
module Input
|
8
|
+
include Win::Library
|
9
|
+
|
10
|
+
# Windows keyboard-related Constants:
|
11
|
+
|
12
|
+
# Key down keyboard event (the key is being depressed)
|
13
|
+
KEYEVENTF_KEYDOWN = 0
|
14
|
+
# Key up keyboard event (the key is being released)
|
15
|
+
KEYEVENTF_KEYUP = 2
|
16
|
+
# Extended kb event. If specified, the scan code was preceded by a prefix byte having the value 0xE0 (224).
|
17
|
+
KEYEVENTF_EXTENDEDKEY = 1
|
18
|
+
|
19
|
+
# Virtual key codes:
|
20
|
+
|
21
|
+
# Control-break processing
|
22
|
+
VK_CANCEL = 0x03
|
23
|
+
# Backspace? key
|
24
|
+
VK_BACK = 0x08
|
25
|
+
# Tab key
|
26
|
+
VK_TAB = 0x09
|
27
|
+
# Shift key
|
28
|
+
VK_SHIFT = 0x10
|
29
|
+
# Ctrl key
|
30
|
+
VK_CONTROL = 0x11
|
31
|
+
# ENTER key
|
32
|
+
VK_RETURN = 0x0D
|
33
|
+
# ALT key
|
34
|
+
VK_ALT = 0x12
|
35
|
+
# ALT key alias
|
36
|
+
VK_MENU = 0x12
|
37
|
+
# PAUSE key
|
38
|
+
VK_PAUSE = 0x13
|
39
|
+
# CAPS LOCK key
|
40
|
+
VK_CAPITAL = 0x14
|
41
|
+
# ESC key
|
42
|
+
VK_ESCAPE = 0x1B
|
43
|
+
# SPACEBAR
|
44
|
+
VK_SPACE = 0x20
|
45
|
+
# PAGE UP key
|
46
|
+
VK_PRIOR = 0x21
|
47
|
+
# PAGE DOWN key
|
48
|
+
VK_NEXT = 0x22
|
49
|
+
# END key
|
50
|
+
VK_END = 0x23
|
51
|
+
# HOME key
|
52
|
+
VK_HOME = 0x24
|
53
|
+
# LEFT ARROW key
|
54
|
+
VK_LEFT = 0x25
|
55
|
+
# UP ARROW key
|
56
|
+
VK_UP = 0x26
|
57
|
+
# RIGHT ARROW key
|
58
|
+
VK_RIGHT = 0x27
|
59
|
+
# DOWN ARROW key
|
60
|
+
VK_DOWN = 0x28
|
61
|
+
# SELECT key
|
62
|
+
VK_SELECT = 0x29
|
63
|
+
# PRINT key
|
64
|
+
VK_PRINT = 0x2A
|
65
|
+
# EXECUTE key
|
66
|
+
VK_EXECUTE = 0x2B
|
67
|
+
# PRINT SCREEN key
|
68
|
+
VK_SNAPSHOT = 0x2C
|
69
|
+
# INS key
|
70
|
+
VK_INSERT = 0x2D
|
71
|
+
# DEL key
|
72
|
+
VK_DELETE = 0x2E
|
73
|
+
# HELP key
|
74
|
+
VK_HELP = 0x2F
|
75
|
+
|
76
|
+
# Public Type MOUSEINPUT
|
77
|
+
# dx As Long
|
78
|
+
# dy As Long
|
79
|
+
# mouseData As Long
|
80
|
+
# dwFlags As Long
|
81
|
+
# time As Long
|
82
|
+
# dwExtraInfo As Long
|
83
|
+
# End Type
|
84
|
+
#
|
85
|
+
# Public Type INPUT_TYPE
|
86
|
+
# dwType As Long
|
87
|
+
# xi(0 To 23) As Byte
|
88
|
+
# End Type
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
# dwFlags:
|
93
|
+
# Specifies that the dx and dy parameters contain normalized absolute coordinates. If not set, those parameters
|
94
|
+
# contain relative data: the change in position since the last reported position. This flag can be set, or not
|
95
|
+
# set, regardless of what kind of mouse or mouse-like device, if any, is connected to the system. For further
|
96
|
+
# information about relative mouse motion, see mouse_event Remarks section.
|
97
|
+
MOUSEEVENTF_ABSOLUTE = 0x8000
|
98
|
+
#Specifies that movement occurred.
|
99
|
+
MOUSEEVENTF_MOVE = 0x01
|
100
|
+
#Specifies that the left button is down.
|
101
|
+
MOUSEEVENTF_LEFTDOWN = 0x02
|
102
|
+
#Specifies that the left button is up.
|
103
|
+
MOUSEEVENTF_LEFTUP = 0x04
|
104
|
+
#Specifies that the right button is down.
|
105
|
+
MOUSEEVENTF_RIGHTDOWN = 0x08
|
106
|
+
#Specifies that the right button is up.
|
107
|
+
MOUSEEVENTF_RIGHTUP = 0x010
|
108
|
+
#Specifies that the middle button is down.
|
109
|
+
MOUSEEVENTF_MIDDLEDOWN = 0x20
|
110
|
+
#Specifies that the middle button is up.
|
111
|
+
MOUSEEVENTF_MIDDLEUP = 0x040
|
112
|
+
#Windows NT/2000/XP: Specifies that the wheel has been moved, if the mouse has a wheel. The amount of movement
|
113
|
+
#is specified in dwData
|
114
|
+
MOUSEEVENTF_WHEEL = 0x80
|
115
|
+
#Windows 2000/XP: Specifies that an X button was pressed.
|
116
|
+
MOUSEEVENTF_XDOWN = 0x100
|
117
|
+
#Windows 2000/XP: Specifies that an X button was released.
|
118
|
+
MOUSEEVENTF_XUP = 0x200
|
119
|
+
|
120
|
+
# dwData:
|
121
|
+
# One wheel click is defined as WHEEL_DELTA, which is 120.
|
122
|
+
WHEEL_DELTA = 120
|
123
|
+
# Set if the first X button was pressed or released.
|
124
|
+
XBUTTON1 = 1
|
125
|
+
# Set if the second X button was pressed or released.
|
126
|
+
XBUTTON2 = 2
|
127
|
+
# Indicates NO data if dwFlags are NOT any of MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, or MOUSEEVENTF_XUP
|
128
|
+
INPUT_MOUSE = 0
|
129
|
+
|
130
|
+
|
131
|
+
##
|
132
|
+
# The keybd_event function synthesizes a keystroke. The system can use such a synthesized keystroke to generate
|
133
|
+
# a WM_KEYUP or WM_KEYDOWN message. The keyboard driver's interrupt handler calls the keybd_event function.
|
134
|
+
#
|
135
|
+
# !!!! Windows NT/2000/XP/Vista:This function has been superseded. Use SendInput instead.
|
136
|
+
#
|
137
|
+
# Syntax: VOID keybd_event( BYTE bVk, BYTE bScan, DWORD dwFlags, PTR dwExtraInfo);
|
138
|
+
#
|
139
|
+
# Parameters:
|
140
|
+
# bVk [C] - [in] Specifies a virtual-key code. The code must be a value in the range 1 to 254.
|
141
|
+
# For a complete list, see Virtual-Key Codes.
|
142
|
+
# bScan [C] - [in] Specifies a hardware scan code for the key.
|
143
|
+
# dwFlags [L] - [in] Specifies various aspects of function operation. This parameter can be
|
144
|
+
# one or more of the following values:
|
145
|
+
# KEYEVENTF_EXTENDEDKEY, KEYEVENTF_KEYUP, KEYEVENTF_KEYDOWN
|
146
|
+
# dwExtraInfo [L] -[in] Specifies an additional value associated with the key stroke.
|
147
|
+
#
|
148
|
+
# Return Value: none
|
149
|
+
#
|
150
|
+
# Remarks: An application can simulate a press of the PRINTSCRN key in order to obtain a screen snapshot and save
|
151
|
+
# it to the clipboard. To do this, call keybd_event with the bVk parameter set to VK_SNAPSHOT.
|
152
|
+
#
|
153
|
+
# Windows NT/2000/XP: The keybd_event function can toggle the NUM LOCK, CAPS LOCK, and SCROLL LOCK keys.
|
154
|
+
# Windows 95/98/Me: The keybd_event function can toggle only the CAPS LOCK and SCROLL LOCK keys.
|
155
|
+
#
|
156
|
+
function 'keybd_event', 'IILL', 'V'
|
157
|
+
|
158
|
+
##
|
159
|
+
# The mouse_event function synthesizes mouse motion and button clicks.
|
160
|
+
# !!!! Windows NT/2000/XP: This function has been superseded. Use SendInput instead.
|
161
|
+
#
|
162
|
+
# Syntax: VOID mouse_event( DWORD dwFlags, DWORD dx, DWORD dy, DWORD dwData, ULONG_PTR dwExtraInfo );
|
163
|
+
#
|
164
|
+
# Parameters:
|
165
|
+
# flags (I) - [in] Specifies various aspects of mouse motion and button clicking. This parameter can be
|
166
|
+
# certain combinations of the following values. The values that specify mouse button status are set to
|
167
|
+
# indicate changes in status, not ongoing conditions. For example, if the left mouse button is pressed
|
168
|
+
# and held down, MOUSEEVENTF_LEFTDOWN is set when the left button is first pressed, but not for subsequent
|
169
|
+
# motions. Similarly, MOUSEEVENTF_LEFTUP is set only when the button is first released. You cannot specify
|
170
|
+
# both MOUSEEVENTF_WHEEL and either MOUSEEVENTF_XDOWN or MOUSEEVENTF_XUP simultaneously, because they
|
171
|
+
# both require use of the dwData field:
|
172
|
+
# MOUSEEVENTF_ABSOLUTE, MOUSEEVENTF_MOVE, MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP, MOUSEEVENTF_RIGHTDOWN,
|
173
|
+
# MOUSEEVENTF_RIGHTUP, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN,
|
174
|
+
# MOUSEEVENTF_XUP
|
175
|
+
# dx (I) - [in] Specifies the mouse's absolute position along the x-axis or its amount of motion since the
|
176
|
+
# last mouse event was generated, depending on the setting of MOUSEEVENTF_ABSOLUTE. Absolute data is
|
177
|
+
# specified as the mouse's actual x-coordinate; relative data is specified as the number of mickeys moved.
|
178
|
+
# A mickey is the amount that a mouse has to move for it to report that it has moved.
|
179
|
+
# dy (I) - [in] Specifies the mouse's absolute position along the y-axis or its amount of motion since the
|
180
|
+
# last mouse event was generated, depending on the setting of MOUSEEVENTF_ABSOLUTE. Absolute data is
|
181
|
+
# specified as the mouse's actual y-coordinate; relative data is specified as the number of mickeys moved.
|
182
|
+
# data (I) - [in] If flags contains MOUSEEVENTF_WHEEL, then data specifies the amount of wheel movement.
|
183
|
+
# A positive value indicates that the wheel was rotated forward, away from the user; a negative value
|
184
|
+
# indicates that the wheel was rotated backward, toward the user. One wheel click is defined as
|
185
|
+
# WHEEL_DELTA, which is 120. If flags contains MOUSEEVENTF_WHHEEL, then data specifies the amount of
|
186
|
+
# wheel movement. A positive value indicates that the wheel was rotated to the right; a negative value
|
187
|
+
# indicates that the wheel was rotated to the left. One wheel click is defined as WHEEL_DELTA, which is 120.
|
188
|
+
# Windows 2000/XP: If flags contains MOUSEEVENTF_XDOWN or MOUSEEVENTF_XUP, then data specifies which X
|
189
|
+
# buttons were pressed or released. This value may be any combination of the following flags.
|
190
|
+
# If flags is not MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, or MOUSEEVENTF_XUP, then data should be zero.
|
191
|
+
# XBUTTON1 - Set if the first X button was pressed or released.
|
192
|
+
# XBUTTON2 - Set if the second X button was pressed or released.
|
193
|
+
# extra_info (P) - [in] Specifies an additional value associated with the mouse event. An application
|
194
|
+
# calls GetMessageExtraInfo to obtain this extra information.
|
195
|
+
#
|
196
|
+
# NO Return Value
|
197
|
+
#
|
198
|
+
# Remarks: If the mouse has moved, indicated by MOUSEEVENTF_MOVE being set, dx and dy hold information about
|
199
|
+
# that motion. The information is specified as absolute or relative integer values. If MOUSEEVENTF_ABSOLUTE
|
200
|
+
# value is specified, dx and dy contain normalized absolute coordinates between 0 and 65,535. The event
|
201
|
+
# procedure maps these coordinates onto the display surface. Coordinate (0,0) maps onto the upper-left corner
|
202
|
+
# of the display surface, (65535,65535) maps onto the lower-right corner. If the MOUSEEVENTF_ABSOLUTE value
|
203
|
+
# is not specified, dx and dy specify relative motions from when the last mouse event was generated (the last
|
204
|
+
# reported position). Positive values mean the mouse moved right (or down); negative values mean the mouse
|
205
|
+
# moved left (or up). Relative mouse motion is subject to the settings for mouse speed and acceleration level.
|
206
|
+
# An end user sets these values using the Mouse application in Control Panel. An application obtains and sets
|
207
|
+
# these values with the SystemParametersInfo function. The system applies two tests to the specified relative
|
208
|
+
# mouse motion when applying acceleration. If the specified distance along either the x or y axis is greater
|
209
|
+
# than the first mouse threshold value, and the mouse acceleration level is not zero, the operating system
|
210
|
+
# doubles the distance. If the specified distance along either the x- or y-axis is greater than the second
|
211
|
+
# mouse threshold value, and the mouse acceleration level is equal to two, the operating system doubles the
|
212
|
+
# distance that resulted from applying the first threshold test. It is thus possible for the operating system
|
213
|
+
# to multiply relatively-specified mouse motion along the x- or y-axis by up to four times. Once acceleration
|
214
|
+
# has been applied, the system scales the resultant value by the desired mouse speed. Mouse speed can range
|
215
|
+
# from 1 (slowest) to 20 (fastest) and represents how much the pointer moves based on the distance the mouse
|
216
|
+
# moves. The default value is 10, which results in no additional modification to the mouse motion. The
|
217
|
+
# mouse_event function is used to synthesize mouse events by applications that need to do so. It is also used
|
218
|
+
# by applications that need to obtain more information from the mouse than its position and button state.
|
219
|
+
# For example, if a tablet manufacturer wants to pass pen-based information to its own applications, it can
|
220
|
+
# write a DLL that communicates directly to the tablet hardware, obtains the extra information, and saves it
|
221
|
+
# in a queue. The DLL then calls mouse_event with the standard button and x/y position data, along with,
|
222
|
+
# in the dwExtraInfo parameter, some pointer or index to the queued extra information. When the application
|
223
|
+
# needs the extra information, it calls the DLL with the pointer or index stored in dwExtraInfo, and the DLL
|
224
|
+
# returns the extra information.
|
225
|
+
#
|
226
|
+
#
|
227
|
+
function 'mouse_event', 'IIIIP', 'V'
|
228
|
+
|
229
|
+
##
|
230
|
+
# SetCursorPos Function moves the cursor to the specified screen coordinates. If the new coordinates are not
|
231
|
+
# within the screen rectangle set by the most recent ClipCursor function call, the system automatically adjusts
|
232
|
+
# the coordinates so that the cursor stays within the rectangle.
|
233
|
+
#
|
234
|
+
# Syntax: BOOL SetCursorPos( int X, int Y );
|
235
|
+
#
|
236
|
+
# Parameters:
|
237
|
+
# X (i) - [in] Specifies the new x-coordinate of the cursor, in screen coordinates.
|
238
|
+
# Y (i) - [in] Specifies the new y-coordinate of the cursor, in screen coordinates.
|
239
|
+
#
|
240
|
+
# Return Value: Nonzero if successful or zero otherwise. To get extended error information, call GetLastError.
|
241
|
+
# Enhanced to return true/false instead of nonzero/zero
|
242
|
+
#
|
243
|
+
# Remarks: The cursor is a shared resource. A window should move the cursor only when the cursor is in the
|
244
|
+
# window's client area. The calling process must have WINSTA_WRITEATTRIBUTES access to the window station.
|
245
|
+
# The input desktop must be the current desktop when you call SetCursorPos. Call OpenInputDesktop to determine
|
246
|
+
# whether the current desktop is the input desktop. If it is not, call SetThreadDesktop with the HDESK returned
|
247
|
+
# by OpenInputDesktop to switch to that desktop.
|
248
|
+
#
|
249
|
+
# :call-seq:
|
250
|
+
# success = set_cursor_pos(x,y)
|
251
|
+
#
|
252
|
+
function :SetCursorPos, [:int, :int], :bool
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'win/library'
|
2
|
+
|
3
|
+
module Win
|
4
|
+
module Gui
|
5
|
+
# Contains constants and Win32API functions related to inter-Window messaging
|
6
|
+
#
|
7
|
+
module Message
|
8
|
+
include Win::Library
|
9
|
+
|
10
|
+
# Windows Message Get Text
|
11
|
+
WM_GETTEXT = 0x000D
|
12
|
+
# Windows Message Sys Command
|
13
|
+
WM_SYSCOMMAND = 0x0112
|
14
|
+
# Sys Command Close
|
15
|
+
SC_CLOSE = 0xF060
|
16
|
+
|
17
|
+
function 'PostMessage', 'LLLL', 'L'
|
18
|
+
function 'SendMessage', 'LLLP', 'L'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|