lib/win/window.rb in win-0.0.4 vs lib/win/window.rb in win-0.0.6
- old
+ new
@@ -3,10 +3,16 @@
module Win
# Contains constants, functions and wrappers related to Windows manipulation
#
module Window
+ # Internal constants:
+
+ # Windows keyboard-related Constants:
+ # ? move to keyboard.rb?
+ KEY_DELAY = 0.00001
+
include Win::Library
#General constants:
# Windows Message Get Text
@@ -14,10 +20,74 @@
# Windows Message Sys Command
WM_SYSCOMMAND = 0x0112
# Sys Command Close
SC_CLOSE = 0xF060
+ # 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
+
# ShowWindow constants:
# Hides the window and activates another window.
SW_HIDE = 0
# Same as SW_SHOWNORMAL
@@ -49,11 +119,55 @@
SW_SHOWDEFAULT = 10
# Windows 2000/XP: Minimizes a window, even if the thread that owns the window is not responding. Only use this
# flag when minimizing windows from a different thread.
SW_FORCEMINIMIZE = 11
+ class << self
+ # Def_block that calls API function expecting EnumWindowsProc callback (EnumWindows, EnumChildWindows, ...).
+ # Default callback just pushes all passed handles into Array that is returned if Enum function call was successful.
+ # If runtime block is given it is added to the end of default callback (handles Array is still collected/returned).
+ # If Enum function call failed, method returns nil, otherwise an Array of window handles.
+ #
+ def return_enum #:nodoc:
+ lambda do |api, *args, &block|
+ args.push 0 if args.size == api.prototype.size - 2 # If value is missing, it defaults to 0
+ handles = []
+ # Insert callback proc into appropriate place of args Array
+ args[api.prototype.find_index(:enum_callback), 0] =
+ proc do |handle, message|
+ handles << handle
+ block ? block[handle, message] : true
+ end
+ handles if api.call *args
+ end
+ end
+
+ # Helper method that creates def_block returning (possibly encoded) string as a result of
+ # api function call or nil if zero characters was returned by api call
+ #
+ def return_string( encode = nil ) #:nodoc:
+ lambda do |api, *args|
+ namespace.enforce_count( args, api.prototype, -2)
+ buffer = FFI::MemoryPointer.new :char, 1024
+ buffer.put_string(0, "\x00" * 1023)
+ args += [buffer, 1024]
+ num_chars = api.call(*args)
+ return nil if num_chars == 0
+ if encode
+ string = buffer.get_bytes(0, num_chars*2)
+ string = string.force_encoding('utf-16LE').encode(encode)
+ else
+ string = buffer.get_bytes(0, num_chars)
+ end
+ string.rstrip
+ end
+ end
+
+ private :return_enum, :return_string
+ end
+
# Windows GUI API definitions:
##
# Tests whether the specified window handle identifies an existing window.
# A thread should not use IsWindow for a window that it did not create because the window
@@ -69,11 +183,11 @@
# Tests if the specified window, its parent window, its parent's parent window, and so forth,
# have the WS_VISIBLE style. Because the return value specifies whether the window has the
# WS_VISIBLE style, it may be true even if the window is totally obscured by other windows.
#
# :call-seq:
- # visible?( win_handle ), window_visible?( win_handle )
+ # [window_]visible?( win_handle )
#
function 'IsWindowVisible', 'L', 'L', aliases: :visible?
##
# Tests whether the specified window is maximized.
@@ -146,24 +260,10 @@
# :call-seq:
# win_handle = find_window_ex( win_handle, after_child, class_name, win_name )
#
function 'FindWindowEx', 'LLPP', 'L', zeronil: true
- # Helper method that creates def_block returning (possibly encoded) string as a result of
- # api function call or nil if zero characters was returned by api call
- # TODO: should be private
- def self.return_string( encode = nil ) #:nodoc:
- lambda do |api, *args|
- namespace.enforce_count( args, api.prototype, -2)
- args += [string = buffer, string.length]
- num_chars = api.call(*args)
- return nil if num_chars == 0
- string = string.force_encoding('utf-16LE').encode(encode) if encode
- string.rstrip
- end
- end
-
##
# Returns the text of the specified window's title bar (if it has one).
# If the specified window is a control, the text of the control is copied. However, GetWindowText
# cannot retrieve the text of a control in another application.
#
@@ -193,20 +293,20 @@
# belongs to the calling app, GetWindowText will cause the calling app to become unresponsive.
# To retrieve the text of a control in another process, send a WM_GETTEXT message directly instead
# of calling GetWindowText.
#
#:call-seq:
- # text = get_window_text( win_handle )
+ # text = [get_]window_text( win_handle )
#
function 'GetWindowText', 'LPI', 'L', &return_string
##
# Unicode version of get_window_text (returns rstripped utf-8 string)
# API improved to require only win_handle and return rstripped string
#
#:call-seq:
- # text = get_window_text_w( win_handle )
+ # text = [get_]window_text_w( win_handle )
#
function 'GetWindowTextW', 'LPI', 'L', &return_string('utf-8')
##
# Retrieves the name of the class to which the specified window belongs.
@@ -225,20 +325,20 @@
# Enhanced Parameters:
# win_handle (L) - Handle to the window and, indirectly, the class to which the window belongs.
# Returns: Name of the class or NIL if function fails. For extended error information, call GetLastError.
#
#:call-seq:
- # text = get_class_name( win_handle )
+ # text = [get_]class_name( win_handle )
#
function 'GetClassName', 'LPI', 'I', &return_string
##
# Unicode version of get_class_name (returns rstripped utf-8 string)
# API improved to require only win_handle and return rstripped string
#
#:call-seq:
- # text = get_class_name_w( win_handle )
+ # text = [get_]class_name_w( win_handle )
#
function 'GetClassNameW', 'LPI', 'I', &return_string('utf-8')
##
# Shows and hides windows.
@@ -263,16 +363,10 @@
# Hides the window and activates another window
def hide_window(win_handle)
show_window(win_handle, SW_HIDE)
end
- return_thread_process = lambda do |api, *args|
- namespace.enforce_count( args, api.prototype, -1)
- thread = api.call(args.first, process = [1].pack('L'))
- nonzero_array(thread, *process.unpack('L'))
- end
-
##
# Retrieves the identifier of the thread that created the specified window
# and, optionally, the identifier of the process that created the window.
#
# Original Parameters:
@@ -285,21 +379,20 @@
# New Parameters:
# handle (L) - Handle to the window.
# Returns: Pair of identifiers of the thread and process_id that created the window.
#
#:call-seq:
- # thread, process_id = get_window_tread_process_id( win_handle )
+ # thread, process_id = [get_]window_tread_process_id( win_handle )
#
- function 'GetWindowThreadProcessId', 'LP', 'L', &return_thread_process
+ function 'GetWindowThreadProcessId', [:long, :pointer], :long, &->(api, *args) {
+ namespace.enforce_count( args, api.prototype, -1)
+ process = FFI::MemoryPointer.new(:long)
+ process.write_long(1)
+ thread = api.call(args.first, process)
+ thread == 0 ? [nil, nil] : [thread, process.read_long()] }
+ # weird lambda literal instead of block is needed because RDoc goes crazy if block is attached to meta-definition
- return_rect = lambda do |api, *args|
- namespace.enforce_count( args, api.prototype, -1)
- rectangle = [0, 0, 0, 0].pack('L*')
- res = api.call args.first, rectangle
- res == 0 ? [nil, nil, nil, nil] : rectangle.unpack('L*')
- end
-
##
# Retrieves the dimensions of the specified window bounding rectangle.
# Dimensions are given relative to the upper-left corner of the screen.
#
# Original Parameters:
@@ -316,111 +409,151 @@
#
# Remarks: As a convention for the RECT structure, the bottom-right coordinates of the returned rectangle
# are exclusive. In other words, the pixel at (right, bottom) lies immediately outside the rectangle.
#
#:call-seq:
- # rect = get_window_rect( win_handle )
+ # rect = [get_]window_rect( win_handle )
#
- function 'GetWindowRect', 'LP', 'I', &return_rect
+ function 'GetWindowRect', 'LP', 'I', &->(api, *args) {
+ namespace.enforce_count( args, api.prototype, -1)
+ rect = FFI::MemoryPointer.new(:long, 4)
+ rect.write_array_of_long([0, 0, 0, 0])
+ res = api.call args.first, rect
+ res == 0 ? [nil, nil, nil, nil] : rect.read_array_of_long(4) }
+ # weird lambda literal instead of block is needed because RDoc goes crazy if block is attached to meta-definition
-# # Procedure that calls api function expecting a callback. If runtime block is given
-# # it is converted into callback, otherwise procedure returns an array of all handles
-# # pushed into callback by api enumeration
-# # TODO: should be private
-# #
-# def self.return_enum #:nodoc:
-# lambda do |api, *args, &block|
-# namespace.enforce_count( args, api.prototype, -1)
-# handles = []
-# cb = if block
-# callback('LP', 'I', &block)
-# else
-# callback('LP', 'I') do |handle, message|
-# handles << handle
-# true
-# end
-# end
-# args[api.prototype.find_index('K'), 0] = cb # Insert callback into appropriate place of args Array
-# api.call *args
-# handles
-# end
-# end
-#
-# ##
-# # The EnumWindows function enumerates all top-level windows on the screen by passing the handle to
-# # each window, in turn, to an application-defined callback function. EnumWindows continues until
-# # the last top-level window is enumerated or the callback function returns FALSE.
-# #
-# # Original Parameters:
-# # callback [K] - Pointer to an application-defined callback function (see EnumWindowsProc).
-# # message [P] - Specifies an application-defined value(message) to be passed to the callback function.
-# # Original Return: Nonzero if the function succeeds, zero if the function fails. GetLastError for error info.
-# # If callback returns zero, the return value is also zero. In this case, the callback function should
-# # call SetLastError to obtain a meaningful error code to be returned to the caller of EnumWindows.
-# #
-# # API improved to accept blocks (instead of callback objects) and message as a single arg
-# #
-# # New Parameters:
-# # message [P] - Specifies an application-defined value(message) to be passed to the callback function.
-# # block given to method invocation serves as an application-defined callback function (see EnumWindowsProc).
-# # Returns: True if the function succeeds, false if the function fails. GetLastError for error info.
-# # If callback returns zero, the return value is also zero. In this case, the callback function should
-# # call SetLastError to obtain a meaningful error code to be returned to the caller of EnumWindows.
-# #
-# # Remarks: The EnumWindows function does not enumerate child windows, with the exception of a few top-level
-# # windows owned by the system that have the WS_CHILD style. This function is more reliable than calling
-# # the GetWindow function in a loop. An application that calls GetWindow to perform this task risks being
-# # caught in an infinite loop or referencing a handle to a window that has been destroyed.
-# #
-# #:call-seq:
-# # status = enum_windows( message ) {|win_handle, message| callback procedure }
-# #
-# function'EnumWindows', 'KP', 'L', boolean: true, &return_enum
-#
-# ##
-# # Enumerates child windows to a given window.
-# #
-# # Original Parameters:
-# # parent (L) - Handle to the parent window whose child windows are to be enumerated.
-# # callback [K] - Pointer to an application-defined callback function (see EnumWindowsProc).
-# # message [P] - Specifies an application-defined value(message) to be passed to the callback function.
-# # Original Return: Not used (?!)
-# # If callback returns zero, the return value is also zero. In this case, the callback function should
-# # call SetLastError to obtain a meaningful error code to be returned to the caller of EnumWindows.
-# # If it is nil, this function is equivalent to EnumWindows. Windows 95/98/Me: parent cannot be NULL.
-# #
-# # API improved to accept blocks (instead of callback objects) and two args: parent handle and message.
-# # New Parameters:
-# # parent (L) - Handle to the parent window whose child windows are to be enumerated.
-# # message (P) - Specifies an application-defined value(message) to be passed to the callback function.
-# # block given to method invocation serves as an application-defined callback function (see EnumChildProc).
-# #
-# # Remarks:
-# # If a child window has created child windows of its own, EnumChildWindows enumerates those windows as well.
-# # A child window that is moved or repositioned in the Z order during the enumeration process will be properly enumerated.
-# # The function does not enumerate a child window that is destroyed before being enumerated or that is created during the enumeration process.
-# #
-# #:call-seq:
-# # enum_windows( parent_handle, message ) {|win_handle, message| callback procedure }
-# #
-# function 'EnumChildWindows', 'LKP', 'L', &return_enum
+ # This is an application-defined callback function that receives top-level window handles as a result of a call
+ # to the EnumWindows, EnumChildWindows or EnumDesktopWindows function.
+ #
+ # Syntax: BOOL CALLBACK EnumWindowsProc( HWND hwnd, LPARAM lParam );
+ #
+ # Parameters:
+ # hwnd (L) - [out] Handle to a top-level window.
+ # lParam (L) - [in] Specifies the application-defined value given in EnumWindows or EnumDesktopWindows.
+ # Return Values:
+ # TRUE continues enumeration. FALSE stops enumeration.
+ #
+ # Remarks: An application must register this callback function by passing its address to EnumWindows or EnumDesktopWindows.
+ callback :enum_callback, 'LL', :bool
##
+ # The EnumWindows function enumerates all top-level windows on the screen by passing the handle to
+ # each window, in turn, to an application-defined callback function. EnumWindows continues until
+ # the last top-level window is enumerated or the callback function returns FALSE.
+ #
+ # Original Parameters:
+ # callback [K] - Pointer to an application-defined callback function (see EnumWindowsProc).
+ # value [P] - Specifies an application-defined value(message) to be passed to the callback function.
+ # Original Return: Nonzero if the function succeeds, zero if the function fails. GetLastError for error info.
+ # If callback returns zero, the return value is also zero. In this case, the callback function should
+ # call SetLastError to obtain a meaningful error code to be returned to the caller of EnumWindows.
+ #
+ # API improved to accept blocks (instead of callback objects) and message as a single arg
+ #
+ # New Parameters:
+ # message [P] - Specifies an application-defined value(message) to be passed to the callback function.
+ # block given to method invocation serves as an application-defined callback function (see EnumWindowsProc).
+ # Returns: True if the function succeeds, false if the function fails. GetLastError for error info.
+ # If callback returns zero, the return value is also zero. In this case, the callback function should
+ # call SetLastError to obtain a meaningful error code to be returned to the caller of EnumWindows.
+ #
+ # Remarks: The EnumWindows function does not enumerate child windows, with the exception of a few top-level
+ # windows owned by the system that have the WS_CHILD style. This function is more reliable than calling
+ # the GetWindow function in a loop. An application that calls GetWindow to perform this task risks being
+ # caught in an infinite loop or referencing a handle to a window that has been destroyed.
+ #
+ #:call-seq:
+ # handles = enum_windows( [value] ) {|handle, message| your callback procedure }
+ #
+ function'EnumWindows', [:enum_callback, :long], :bool, &return_enum
+
+ ##
+ #EnumDesktopWindows Function
+ #
+ #Enumerates all top-level windows associated with the specified desktop. It passes the handle to each window, in turn, to an application-defined callback function.
+ #
+ #
+ #Syntax
+ #BOOL WINAPI EnumDesktopWindows(
+ # __in_opt HDESK hDesktop,
+ # __in WNDENUMPROC lpfn,
+ # __in LPARAM lParam
+ #);
+ #
+ #Parameters
+ #hDesktop
+ #A handle to the desktop whose top-level windows are to be enumerated. This handle is returned by the CreateDesktop, GetThreadDesktop, OpenDesktop, or OpenInputDesktop function, and must have the DESKTOP_ENUMERATE access right. For more information, see Desktop Security and Access Rights.
+ #
+ #If this parameter is NULL, the current desktop is used.
+ #
+ #lpfn
+ #A pointer to an application-defined EnumWindowsProc callback function.
+ #
+ #lParam
+ #An application-defined value to be passed to the callback function.
+ #
+ #Return Value
+ #If the function fails or is unable to perform the enumeration, the return value is zero.
+ #
+ #To get extended error information, call GetLastError.
+ #
+ #You must ensure that the callback function sets SetLastError if it fails.
+ #
+ #Windows Server 2003 and Windows XP/2000: If there are no windows on the desktop, GetLastError returns ERROR_INVALID_HANDLE.
+ #Remarks
+ #The EnumDesktopWindows function repeatedly invokes the lpfn callback function until the last top-level window is enumerated or the callback function returns FALSE.
+ #
+ #Requirements
+ #Client Requires Windows Vista, Windows XP, or Windows 2000 Professional.
+ function'EnumDesktopWindows', [:ulong, :enum_callback, :long], :bool, &return_enum
+
+ ##
+ # Enumerates child windows to a given window.
+ #
+ # Original Parameters:
+ # parent (L) - Handle to the parent window whose child windows are to be enumerated.
+ # callback [K] - Pointer to an application-defined callback function (see EnumWindowsProc).
+ # message [P] - Specifies an application-defined value(message) to be passed to the callback function.
+ # Original Return: Not used (?!)
+ # If callback returns zero, the return value is also zero. In this case, the callback function should
+ # call SetLastError to obtain a meaningful error code to be returned to the caller of EnumWindows.
+ # If it is nil, this function is equivalent to EnumWindows. Windows 95/98/Me: parent cannot be NULL.
+ #
+ # API improved to accept blocks (instead of callback objects) and parent handle (value is optional, default 0)
+ # New Parameters:
+ # parent (L) - Handle to the parent window whose child windows are to be enumerated.
+ # value (P) - Specifies an application-defined value(message) to be passed to the callback function.
+ # block given to method invocation serves as an application-defined callback function (see EnumChildProc).
+ #
+ # Remarks:
+ # If a child window has created child windows of its own, EnumChildWindows enumerates those windows as well.
+ # A child window that is moved or repositioned in the Z order during the enumeration process will be properly enumerated.
+ # The function does not enumerate a child window that is destroyed before being enumerated or that is created during the enumeration process.
+ #
+ #:call-seq:
+ # handles = enum_child_windows( parent_handle, [value = 0] ) {|handle, message| your callback procedure }
+ #
+ function 'EnumChildWindows', [:ulong, :enum_callback, :long], :bool, &return_enum
+
+ ##
# GetForegroundWindow function returns a handle to the foreground window (the window with which the user
# is currently working). The system assigns a slightly higher priority to the thread that creates the
# foreground window than it does to other threads.
#
# Syntax: HWND GetForegroundWindow(VOID);
#
# Return Value: The return value is a handle to the foreground window. The foreground window can be NULL in
# certain circumstances, such as when a window is losing activation.
#
#:call-seq:
- # win_handle = (get_)foreground_window()
+ # win_handle = [get_]foreground_window()
#
function 'GetForegroundWindow', [], 'L'
+ ##
+ # Tests if given window handle points to foreground (topmost) window
+ #
def foreground?(win_handle)
win_handle == foreground_window
end
##
@@ -434,117 +567,42 @@
#
# Remarks: To get the handle to the foreground window, you can use GetForegroundWindow.
# To get the window handle to the active window in the message queue for another thread, use GetGUIThreadInfo.
#
#:call-seq:
- # win_handle = (get_)active_window()
+ # win_handle = [get_]active_window()
#
function 'GetActiveWindow', [], 'L'
+ ##
+ # 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);
+ #
+ # Parameters:
+ # bVk [C] - [in] 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 [C] - [in] Specifies a hardware scan code for the key.
+ # dwFlags [L] - [in] Specifies various aspects of function operation. This parameter can be
+ # one or more of the following values:
+ # KEYEVENTF_EXTENDEDKEY, KEYEVENTF_KEYUP, KEYEVENTF_KEYDOWN
+ # dwExtraInfo [L] -[in] Specifies an additional value associated with the key stroke.
+ #
+ # Return Value: none
+ #
+ # 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.
+ #
function 'keybd_event', 'IILL', 'V'
+
function 'PostMessage', 'LLLL', 'L'
function 'SendMessage', 'LLLP', 'L'
function 'GetDlgItem', 'LL', 'L'
-
- # Convenience wrapper methods:
-
- # emulates combinations of keys pressed (Ctrl+Alt+P+M, etc)
- def keystroke(*keys)
- return if keys.empty?
- keybd_event keys.first, 0, KEYEVENTF_KEYDOWN, 0
- sleep WG_KEY_DELAY
- keystroke *keys[1..-1]
- sleep WG_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
-
- # finds top-level dialog window by title and yields it to given block
- def dialog(title, seconds=3)
- d = begin
- win = Window.top_level(title, seconds)
- yield(win) ? win : nil
- rescue TimeoutError
- end
- d.wait_for_close if d
- return d
- end
-
- # Thin wrapper around window handle
- class Window
- include Win::Window
- extend Win::Window
-
- attr_reader :handle
-
- # find top level window by title, return wrapped Window object
- def self.top_level(title, seconds=3)
- @handle = timeout(seconds) do
- sleep WG_SLEEP_DELAY while (h = find_window nil, title) == nil; h
- end
- Window.new @handle
- end
-
- def initialize(handle)
- @handle = handle
- end
-
- # find child window (control) by title, window class, or control ID:
- def child(id)
- result = case id
- when String
- by_title = find_window_ex @handle, 0, nil, id.gsub('_' , '&' )
- by_class = find_window_ex @handle, 0, id, nil
- by_title ? by_title : by_class
- when Fixnum
- get_dlg_item @handle, id
- when nil
- find_window_ex @handle, 0, nil, nil
- else
- nil
- end
- raise "Control '#{id}' not found" unless result
- Window.new result
- end
-
- def children
- enum_child_windows(@handle,'Msg').map{|child_handle| Window.new child_handle}
- end
-
- # emulate click of the control identified by id
- def click(id)
- h = child(id).handle
- rectangle = [0, 0, 0, 0].pack 'LLLL'
- get_window_rect h, rectangle
- left, top, right, bottom = rectangle.unpack 'LLLL'
- center = [(left + right) / 2, (top + bottom) / 2]
- set_cursor_pos *center
- mouse_event MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0
- mouse_event MOUSEEVENTF_LEFTUP, 0, 0, 0, 0
- end
-
- def close
- post_message @handle, WM_SYSCOMMAND, SC_CLOSE, 0
- end
-
- def wait_for_close
- timeout(WG_CLOSE_TIMEOUT) do
- sleep WG_SLEEP_DELAY while window_visible?(@handle)
- end
- end
-
- def text
- buffer = "\x0" * 2048
- length = send_message @handle, WM_GETTEXT, buffer.length, buffer
- length == 0 ? '' : buffer[0..length - 1]
- end
- end
-
end
end