require 'win/library'
module Win
module Gui
# Contains constants and Win32API functions related to end user input
#
module Input
include Win::Library
# Internal constants:
# Key event delay
KEY_DELAY = 0.00001
# Windows keyboard-related Constants:
# Key down keyboard event (the key is being depressed)
KEYEVENTF_KEYDOWN = 0
# Key up keyboard event (the key is being released)
KEYEVENTF_KEYUP = 2
# Extended kb event. If specified, the scan code was preceded by a prefix byte having the value 0xE0 (224).
KEYEVENTF_EXTENDEDKEY = 1
# Virtual key codes:
# Control-break processing
VK_CANCEL = 0x03
# Backspace? key
VK_BACK = 0x08
# Tab key
VK_TAB = 0x09
# Shift key
VK_SHIFT = 0x10
# Ctrl key
VK_CONTROL = 0x11
# ENTER key
VK_RETURN = 0x0D
# ALT key
VK_ALT = 0x12
# ALT key alias
VK_MENU = 0x12
# PAUSE key
VK_PAUSE = 0x13
# CAPS LOCK key
VK_CAPITAL = 0x14
# ESC key
VK_ESCAPE = 0x1B
# SPACEBAR
VK_SPACE = 0x20
# PAGE UP key
VK_PRIOR = 0x21
# PAGE DOWN key
VK_NEXT = 0x22
# END key
VK_END = 0x23
# HOME key
VK_HOME = 0x24
# LEFT ARROW key
VK_LEFT = 0x25
# UP ARROW key
VK_UP = 0x26
# RIGHT ARROW key
VK_RIGHT = 0x27
# DOWN ARROW key
VK_DOWN = 0x28
# SELECT key
VK_SELECT = 0x29
# PRINT key
VK_PRINT = 0x2A
# EXECUTE key
VK_EXECUTE = 0x2B
# PRINT SCREEN key
VK_SNAPSHOT = 0x2C
# INS key
VK_INSERT = 0x2D
# DEL key
VK_DELETE = 0x2E
# HELP key
VK_HELP = 0x2F
# Public Type MOUSEINPUT
# dx As Long
# dy As Long
# mouseData As Long
# dwFlags As Long
# time As Long
# dwExtraInfo As Long
# End Type
#
# Public Type INPUT_TYPE
# dwType As Long
# xi(0 To 23) As Byte
# End Type
# dwFlags:
# Specifies that the dx and dy parameters contain normalized absolute coordinates. If not set, those parameters
# contain relative data: the change in position since the last reported position. This flag can be set, or not
# set, regardless of what kind of mouse or mouse-like device, if any, is connected to the system. For further
# information about relative mouse motion, see mouse_event Remarks section.
MOUSEEVENTF_ABSOLUTE = 0x8000
#Specifies that movement occurred.
MOUSEEVENTF_MOVE = 0x01
#Specifies that the left button is down.
MOUSEEVENTF_LEFTDOWN = 0x02
#Specifies that the left button is up.
MOUSEEVENTF_LEFTUP = 0x04
#Specifies that the right button is down.
MOUSEEVENTF_RIGHTDOWN = 0x08
#Specifies that the right button is up.
MOUSEEVENTF_RIGHTUP = 0x010
#Specifies that the middle button is down.
MOUSEEVENTF_MIDDLEDOWN = 0x20
#Specifies that the middle button is up.
MOUSEEVENTF_MIDDLEUP = 0x040
#Windows NT/2000/XP: Specifies that the wheel has been moved, if the mouse has a wheel. The amount of movement
#is specified in dwData
MOUSEEVENTF_WHEEL = 0x80
#Windows 2000/XP: Specifies that an X button was pressed.
MOUSEEVENTF_XDOWN = 0x100
#Windows 2000/XP: Specifies that an X button was released.
MOUSEEVENTF_XUP = 0x200
# dwData:
# One wheel click is defined as WHEEL_DELTA, which is 120.
WHEEL_DELTA = 120
# Set if the first X button was pressed or released.
XBUTTON1 = 1
# Set if the second X button was pressed or released.
XBUTTON2 = 2
# Indicates NO data if dwFlags are NOT any of MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, or MOUSEEVENTF_XUP
INPUT_MOUSE = 0
##
# The keybd_event function synthesizes a keystroke. The system can use such a synthesized keystroke to generate
# a WM_KEYUP or WM_KEYDOWN message. The keyboard driver's interrupt handler calls the keybd_event function.
#
# !! Windows NT/2000/XP/Vista:This function has been superseded. Use SendInput instead.
#
# [*Syntax*] VOID keybd_event( BYTE bVk, BYTE bScan, DWORD dwFlags, PTR dwExtraInfo);
#
# bVk:: Specifies a virtual-key code. The code must be a value in the range 1 to 254.
# For a complete list, see Virtual-Key Codes.
# bScan:: Specifies a hardware scan code for the key.
# dwFlags:: Specifies various aspects of function operation. This parameter can be
# one or more of the following values:
# KEYEVENTF_EXTENDEDKEY, KEYEVENTF_KEYUP, KEYEVENTF_KEYDOWN
# dwExtraInfo:: Specifies an additional value associated with the key stroke.
#
# NO Return Value
# ---
# *Remarks*:
# - An application can simulate a press of the PRINTSCRN key in order to obtain a screen snapshot
# and save it to the clipboard. To do this, call keybd_event with the bVk parameter set to VK_SNAPSHOT.
#
# - Windows NT/2000/XP: The keybd_event function can toggle the NUM LOCK, CAPS LOCK, and SCROLL LOCK keys.
# - Windows 95/98/Me: The keybd_event function can toggle only the CAPS LOCK and SCROLL LOCK keys.
#
# :call-seq:
# keybd_event( virtual_key, scan_code, flags, extra_info )
#
function :keybd_event, [:char, :char, :ulong, :ulong], :void
##
# The mouse_event function synthesizes mouse motion and button clicks.
#
# !! Windows NT/2000/XP/Vista:This function has been superseded. Use SendInput instead.
#
# [*Syntax*] VOID mouse_event( DWORD dwFlags, DWORD dx, DWORD dy, DWORD dwData, ULONG_PTR dwExtraInfo );
#
# dwFlags:: Specifies various aspects of mouse motion and button clicking. This parameter can be certain
# combinations of the following values. The values that specify mouse button status are set to indicate
# changes in status, not ongoing conditions. For example, if the left mouse button is pressed and
# held down, MOUSEEVENTF_LEFTDOWN is set when the left button is first pressed, but not for subsequent
# motions. Similarly, MOUSEEVENTF_LEFTUP is set only when the button is first released. You cannot
# specify both MOUSEEVENTF_WHEEL and either MOUSEEVENTF_XDOWN or MOUSEEVENTF_XUP simultaneously,
# because they both require use of the dwData field:
# MOUSEEVENTF_ABSOLUTE, MOUSEEVENTF_MOVE, MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP,
# MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP,
# MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, MOUSEEVENTF_XUP
# dx:: Specifies the mouse's absolute position along the x-axis or its amount of motion since the
# last mouse event was generated, depending on the setting of MOUSEEVENTF_ABSOLUTE. Absolute data is
# specified as the mouse's actual x-coordinate; relative data is specified as the number of mickeys moved.
# A mickey is the amount that a mouse has to move for it to report that it has moved.
# dy:: Specifies the mouse's absolute position along the y-axis or its amount of motion since the
# last mouse event was generated, depending on the setting of MOUSEEVENTF_ABSOLUTE. Absolute data is
# specified as the mouse's actual y-coordinate; relative data is specified as the number of mickeys moved.
# dwData::
# - If dwFlags contains MOUSEEVENTF_WHEEL, then data specifies the amount of wheel movement.
# A positive value indicates that the wheel was rotated forward, away from the user; a negative value
# indicates that the wheel was rotated backward, toward the user. One wheel click is defined as
# WHEEL_DELTA, which is 120.
# - If dwFlags contains MOUSEEVENTF_WHHEEL, then data specifies the amount of
# wheel movement. A positive value indicates that the wheel was rotated to the right; a negative value
# indicates that the wheel was rotated to the left. One wheel click is defined as WHEEL_DELTA (= 120).
# - Windows 2000/XP: If flags contains MOUSEEVENTF_XDOWN or MOUSEEVENTF_XUP, then data specifies which
# X buttons were pressed or released. This value may be any combination of the following flags.
# - If flags is not MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, or MOUSEEVENTF_XUP, then data should be zero.
# XBUTTON1 - Set if the first X button was pressed or released.
# XBUTTON2 - Set if the second X button was pressed or released.
# dwExtraInfo:: Specifies an additional value associated with the mouse event. An application
# calls GetMessageExtraInfo to obtain this extra information.
# NO Return Value
# ---
# *Remarks*:
# - If the mouse has moved, indicated by MOUSEEVENTF_MOVE being set, dx and dy hold information about
# that motion. The information is specified as absolute or relative integer values.
# - If MOUSEEVENTF_ABSOLUTE value is specified, dx and dy contain normalized absolute coordinates between
# 0 and 65,535. The event procedure maps these coordinates onto the display surface. Coordinate (0,0) maps
# onto the upper-left corner of the display surface, (65535,65535) maps onto the lower-right corner.
# - If the MOUSEEVENTF_ABSOLUTE value is not specified, dx and dy specify relative motions from when the
# last mouse event was generated (the last reported position). Positive values mean the mouse moved right
# (or down); negative values mean the mouse moved left (or up). Relative mouse motion is subject to the
# settings for mouse speed and acceleration level. An end user sets these values using the Mouse application
# in Control Panel. An application obtains and sets these values with the SystemParametersInfo function.
# - The system applies two tests to the specified relative mouse motion when applying acceleration. If the
# specified distance along either the x or y axis is greater than the first mouse threshold value, and the
# mouse acceleration level is not zero, the operating system doubles the distance. If the specified distance
# along either the x- or y-axis is greater than the second mouse threshold value, and the mouse acceleration
# level is equal to two, the operating system doubles the distance that resulted from applying the first
# threshold test. It is thus possible for the operating system to multiply relatively-specified mouse motion
# along the x- or y-axis by up to four times.
# - Once acceleration has been applied, the system scales the resultant value by the desired mouse speed.
# Mouse speed can range from 1 (slowest) to 20 (fastest) and represents how much the pointer moves based
# on the distance the mouse moves. The default value is 10, which results in no additional modification
# to the mouse motion.
# - The mouse_event function is used to synthesize mouse events by applications that need to do so. It is also
# used by applications that need to obtain more information from the mouse than its position and button state.
# For example, if a tablet manufacturer wants to pass pen-based information to its own applications, it can
# write a DLL that communicates directly to the tablet hardware, obtains the extra information, and saves it
# in a queue. The DLL then calls mouse_event with the standard button and x/y position data, along with,
# in the dwExtraInfo parameter, some pointer or index to the queued extra information. When the application
# needs the extra information, it calls the DLL with the pointer or index stored in dwExtraInfo, and the DLL
# returns the extra information.
#
# :call-seq:
# mouse_event( flags, dx, dy, data, extra_info )
#
function :mouse_event, [:ulong, :ulong, :ulong, :ulong, :ulong, ], :void
##
# SetCursorPos Function moves the cursor to the specified screen coordinates. If the new coordinates are not
# within the screen rectangle set by the most recent ClipCursor function call, the system automatically adjusts
# the coordinates so that the cursor stays within the rectangle.
#
# [*Syntax*] BOOL SetCursorPos( int X, int Y );
#
# X:: Specifies the new x-coordinate of the cursor, in screen coordinates.
# Y:: Specifies the new y-coordinate of the cursor, in screen coordinates.
#
# *Returns*:: Nonzero(*true*) if successful or zero(*false*) otherwise. To get extended error information,
# call GetLastError. Enhanced to return true/false instead of nonzero/zero
# ---
# *Remarks*: The cursor is a shared resource. A window should move the cursor only when the cursor is in the
# window's client area. The calling process must have WINSTA_WRITEATTRIBUTES access to the window station.
# The input desktop must be the current desktop when you call SetCursorPos. Call OpenInputDesktop to determine
# whether the current desktop is the input desktop. If it is not, call SetThreadDesktop with the HDESK returned
# by OpenInputDesktop to switch to that desktop.
#
# :call-seq:
# success = set_cursor_pos(x,y)
#
function :SetCursorPos, [:int, :int], :int, boolean: true
##
# GetCursorPos Function retrieves the cursor's position, in screen coordinates.
#
# [*Syntax*] BOOL GetCursorPos( LPPOINT lpPoint );
#
# lpPoint:: Pointer to a POINT structure that receives the screen coordinates of the cursor.
#
# *Returns*:: Returns nonzero if successful or zero otherwise. To get extended error information, call
# GetLastError.
# ---
# *Remarks*:
# The cursor position is always specified in screen coordinates and is not affected by the mapping mode
# of the window that contains the cursor.
# The calling process must have WINSTA_READATTRIBUTES access to the window station.
# The input desktop must be the current desktop when you call GetCursorPos. Call OpenInputDesktop to
# determine whether the current desktop is the input desktop. If it is not, call SetThreadDesktop with
# the HDESK returned by OpenInputDesktop to switch to that desktop.
# ---
# Enhanced (snake_case) API: accepts no args, returns a pair (x, y) of cursor coordinates
#
# :call-seq:
# x, y = get_cursor_pos()
#
function :GetCursorPos, [:pointer], :int8,
&->(api) {
point = FFI::MemoryPointer.new(:long, 2)
res = api.call point
res == 0 ? [nil, nil] : point.read_array_of_long(2) }
# weird lambda literal instead of normal block is needed because current version of RDoc
# goes crazy if block is attached to meta-definition
# Convenience methods
##
# Emulates combinations of (any amount of) keys pressed one after another (Ctrl+Alt+P) and then released
# *keys should be a sequence of a virtual-key codes. The codes must be a value in the range 1 to 254.
# For a complete list, see msdn:Virtual Key Codes.
def keystroke(*keys)
return if keys.empty?
keybd_event keys.first, 0, KEYEVENTF_KEYDOWN, 0
sleep KEY_DELAY
keystroke *keys[1..-1]
sleep KEY_DELAY
keybd_event keys.first, 0, KEYEVENTF_KEYUP, 0
end
# types text message into window holding the focus
def type_in(message)
message.scan(/./m) do |char|
keystroke(*char.to_vkeys)
end
end
end
end
end