rexx-things/modules/windows/oodialog/winsystem/usewmgr.rex
2025-03-12 20:50:48 +00:00

432 lines
16 KiB
Rexx
Executable File

/*----------------------------------------------------------------------------*/
/* */
/* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved. */
/* Copyright (c) 2005-2014 Rexx Language Association. All rights reserved. */
/* */
/* This program and the accompanying materials are made available under */
/* the terms of the Common Public License v1.0 which accompanies this */
/* distribution. A copy is also available at the following address: */
/* https://www.oorexx.org/license.html */
/* */
/* Redistribution and use in source and binary forms, with or */
/* without modification, are permitted provided that the following */
/* conditions are met: */
/* */
/* Redistributions of source code must retain the above copyright */
/* notice, this list of conditions and the following disclaimer. */
/* Redistributions in binary form must reproduce the above copyright */
/* notice, this list of conditions and the following disclaimer in */
/* the documentation and/or other materials provided with the distribution. */
/* */
/* Neither the name of Rexx Language Association nor the names */
/* of its contributors may be used to endorse or promote products */
/* derived from this software without specific prior written permission. */
/* */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
/* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
/* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
/* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */
/* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY */
/* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */
/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
/* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/* */
/*----------------------------------------------------------------------------*/
/**
* Name: usewmgr.rex
* Type: Example ooRexx program
*
* Description: Demonstrates the use of the WindowsManager, the WindowObject,
* and the WindowsClipboard classes. Has some examples of
* ooDialog usage.
*
* This example uses some of the public functions provided by
* the windowsSystem.frm package. That framework contains
* functions shared with other example programs shipped with
* ooRexx that use winsystm.cls.
*
* Note: Because of language dependencies this example will not run
* correctly on all language versions of Windows. It assumes
* the window titles are in English. To run on a different
* language version, change the window titles for the Calculator
* and Notepad applications to the correct title for
* the specific language version of Windows.
*/
-- First, give the user a clue as to what is happening.
msg = "This ooRexx example program demonstrates controlling a" || .endOfLine || -
"Windows application using the winsystm.cls classes." || .endOfLine~copies(2) || -
"Information will be displayed using message boxes like" || .endOfLine || -
"this one. Push the ok button in them to continue the" || .endOfLine || -
"demonstration." || .endOfLine~copies(2) || -
"You will see the Calculator and Notepad programs appear" || .endOfLine || -
"on your screen, one at a time. There are some short" || .endOfLine || -
"pauses between actions. Be patient during them." || .endOfLine~copies(2) || -
"On the other hand, if the pauses are too short for you," || .endOfLine || -
"you can increase the pauses by editing the code. This" || .endOfLine || -
"will provide a good excuse to explore the code, which" || .endOfLine || -
"is an excellent way to learn. Simply search for 'call" || .endOfLine || -
"SysSleep' in the code and increase the sleep amount for" || .endOfLine || -
"any pause that is is too short." || .endOfLine~copies(2) || -
"In particular watch the Calculator program to see the" || .endOfLine || -
"changes as it is remotely controlled. The applications" || .endOfLine || -
"will be closed automatically"
j = infoDialog(msg)
-- A simple demonstration of the Windows Manager. Get an instance of the
-- WindowsManager class. Then, display the title and coordinates of the current
-- foreground window.
winMgr = .WindowsManager~new
fg = winMgr~ForegroundWindow
if fg \= .nil then do
msg = "Current foreground window" || '0d0a0d0a'x || -
" Window title: " fg~Title || '0d0a'x || -
" Window location:" fg~Coordinates
j = infoDialog(msg)
end
else do
msg = "The WindowsManager object failed to find the foreground window."
j = errorDialog(msg)
end
-- A more involved demonstration using the Windows Calculator application. The
-- real work is done in the workWithCalc() routine.
calcPrg = getPathToSystemExe("calc.exe")
if calcPrg \== .nil then do
ret = workWithCalc(calcPrg)
end
else do
msg = "Faild to locate a definitive path to the Windows" || '0d0a'x || -
"Calculator application. Going to skip this part" || '0d0a'x || -
"of the demonstration."
j = errorDialog(msg)
end
-- An example similar to the Windows Calculator, but using Windows Notepad.
notepad = getPathToSystemExe("notepad.exe")
if notepad \== .nil then do
ret = workWithNotepad(notepad)
end
else do
msg = "Faild to locate a definitive path to the Windows" || '0d0a'x || -
"Notepad application. Going to skip this part of" || '0d0a'x || -
"the demonstration."
j = errorDialog(msg)
end
return 0
/* windowsSystem.frm contains public helper routines and also requires
* winsystm.cls and oodplain.cls. Requiring windowsSystem.frm gives us access
* to the class definitions for WindowsManager, WindowsClipboard, and
* WindowObject. oodplain.cls has the class definitions for the message dialogs.
*/
::requires "windowsSystem.frm"
::routine workWithCalc
use strict arg calcPrg
-- Start the Calculator program.
"start" calcPrg
-- Find the Calculator Window, if we don't find it, then end this portion of
-- the demonstration.
calc = findTheWindow("Calculator")
if calc == .nil then return windowFailure("Calculator")
-- Make the calculator the top-most window.
calc~ToForeground
call SysSleep 2
-- Switch to the scientific view.
calc~ProcessMenuCommand("&View","&Scientific")
call SysSleep 2
/* When the view of the Calculator is changed, it gets a new window handle.
* Because of this, after each view change, the calculator must be found
* again. This is an oddity of the Calculator application. Most applications
* maintain the same window handle through out their execution.
*/
calc = findTheWindow("Calculator")
if calc == .nil then return windowFailure("Calculator")
calc~ToForeground
/* Each button in a dialog has a resource ID. When the button is pushed or
* clicked, the button sends a command (WM_COMMAND) notification to its
* parent window. The command notification contains the resource ID of the
* button that was pushed. This is how the dialog knows what button(s) the
* user pushes or clicks.
*
* We can simulate a user pushing buttons by sending commands to the dialog
* using the resource ID of the button we want pushed. Here we define
* variables with the IDs of some of the buttons in the calculator
* application. This makes the code easier to read. You can verify that
* these are the correct ID numbers by using the displayWindowTree.rex program
* included with this distribution of ooRexx.
*/
divide = 90
multi = 91
plus = 92
minus = 93
point = 85
equals = 112
one = 125
three = 127
five = 129
seven = 131
/* Create a clipboard object */
cb = .WindowsClipboard~new
/* Switch between Scientific and Standard view using the calculator's menu */
calc = findTheWindow("Calculator")
if calc == .nil then return windowFailure("Calculator")
calc~ProcessMenuCommand("&View","S&tandard")
call SysSleep 2
calc = findTheWindow("Calculator")
if calc == .nil then return windowFailure("Calculator")
calc~ProcessMenuCommand("&View","&Scientific")
call SysSleep 2
calc = findTheWindow("Calculator")
if calc == .nil then return windowFailure("Calculator")
calc~Title = "Calculator - Open Object Rexx is in charge!"
-- Do a few calculations and retrieve the results via the clipboard
calc~sendCommand(seven)
calc~sendCommand(plus)
calc~sendCommand(five)
calc~sendCommand(equals)
-- Empty clipboard so that we can wait until data is available
cb~empty
/* Copy result to clipboard, wait until the data is available from the
* clipboard and then use paste to display the result.
*/
calc~processMenuCommand("&Edit", "&Copy")
do while cb~IsDataAvailable = 0; nop; end
msg = "Calculator says: 7+5="cb~Paste
j = infoDialog(msg)
call SysSleep 2
calc~sendCommand(divide)
calc~sendCommand(one)
calc~sendCommand(Point)
calc~sendCommand(five)
calc~sendCommand(equals)
cb~Empty
calc~processMenuCommand("&Edit", "&Copy")
do while cb~IsDataAvailable = 0; nop; end
msg = "Calculator says: 7+5/1.5="cb~Paste
j = infoDialog(msg)
calc~sendCommand(multi)
calc~sendCommand(three)
calc~sendCommand(equals)
cb~Empty
calc~processMenuCommand("&Edit","&Copy")
do while cb~IsDataAvailable = 0; nop; end
msg = "Calculator says: 7+5/1.5*3="cb~Paste
j = infoDialog(msg)
call SysSleep 2
-- Switch to hexadecimal mode.
calc~pushButton("Hex")
cb~empty
calc~processMenuCommand("&Edit","&Copy")
do while cb~isDataAvailable = 0; nop; end
msg = "Calculator says: 7+5/1.5="cb~Paste " (HEX)"
j = infoDialog(msg)
call SysSleep 2
-- Switch back to decimal mode.
calc~pushButton("Dec")
-- Copy a number to the clipboard and from there to the calculator to
-- demonstrate another way to enter numbers.
cb~copy("123456789")
calc~processMenuCommand("&Edit", "&Paste")
call SysSleep 2
-- Simulate a left mouse button click on the "Grads" radio button.
gradsRB = findDescendent(calc, "Grads")
if gradsRB \== .nil then do
gradsRB~sendMouseClick("LEFT", "DOWN", 2, 2)
gradsRB~sendMouseClick("LEFT", "UP", 2, 2)
end
call SysSleep 2
-- Close the Calculator application by pressing Close in the system menu.
calc~sendSysCommand("Close")
return 0
::routine workWithNotepad
use strict arg notePrg
-- Start the Notepad program.
"start" notePrg
np = findTheWindow("Untitled - Notepad")
if np == .nil then return windowFailure("Notepad")
-- Move Notepad to foreground.
np~toForeground
-- The edit window is the first (and perhaps only) child window of Notepad.
npe = np~firstChild
-- The sendText() method sets the text of a window.
npe~sendText("Hello,")
-- The sendKey() method sends a key press to a window. This can be used to
-- send virtual key pressess to the window.
npe~sendKey("RETURN")
-- Because we are sending messages to an application running in a separate
-- process, on today's fast, multi-threaded, multi-cored, systems, it is
-- possible for the messages to arrive in the Notepad application in a
-- different order than they are being sent here. This was probably not
-- possible on Windows 3.0 when this example was first developed.
--
-- To avoid this out of order messaging, we use a helper function from the
-- windowsSystem.frm framework.
j = sendTextWithPause(npe, "This is a sample that mainly demonstrates the use")
j = sendKeyWithPause(npe, "RETURN")
j = sendTextWithPause(npe, "of the WindowsManager class.")
j = sendKeyWithPause(npe, "RETURN")
j = sendKeyWithPause(npe, "RETURN")
j = sendTextWithPause(npe, "It also introduces the WindowObject, the MenuObject,")
j = sendKeyWithPause(npe, "RETURN")
j = sendTextWithPause(npe, "and the WindowsClipboard classes.")
j = sendKeyWithPause(npe, "RETURN")
j = sendKeyWithPause(npe, "RETURN")
npe~sendText("In 1 second intervals I'm going to minimize, maximize, restore,")
j = sendKeyWithPause(npe, "RETURN")
npe~sendText("disable, and reenable Notepad.")
j = sendKeyWithPause(npe, "RETURN")
call SysSleep 3
np~minimize
call SysSleep 1
np~maximize
call SysSleep 1
np~restore
call SysSleep 1
-- Change the size of the Notepad window.
np~resize(650, 280)
-- Make the main window (including the menu) inaccessible.
np~disable
j = sendKeyWithPause(npe, "RETURN")
j = sendKeyWithPause(npe, "RETURN")
j = sendTextWithPause(npe, "Select a menu item. It won't be possible.")
call SysSleep 5
-- Re-enable the main window.
np~enable
j = sendKeyWithPause(npe, "RETURN")
j = sendTextWithPause(npe, "Now the menu is enabled again.")
call SysSleep 1
j = sendKeyWithPause(npe, "RETURN")
j = sendTextWithPause(npe, "You can do the same with the editor window.")
-- We disable the edit window so it gets grayed.
npe~disable
call SysSleep 4
npe~enable
j = sendKeyWithPause(npe, "RETURN")
npe~sendText("Now let's hide the editor window.")
call SysSleep 2
-- Let's hide the edit window (not the main window) for a moment.e */
npe~hide
np~restore
call SysSleep 2
npe~restore
npe~sendKey("RETURN")
npe~sendKey("RETURN")
call SysSleep 3
npe~sendKey("RETURN")
npe~sendKey("RETURN")
npe~sendText("The show is over. Good bye in 3 seconds!")
-- Get a WindowsManager object, we'll use it below to cancel the Save dialog.
winMgr = .WindowsManager~new
-- On Vista, the interface to Notepad is slightly changed.
if isVistaOrLater() then buttonName = "Do&n't Save"
else buttonName = "&No"
call SysSleep 2
-- Close Notepad by pressing the Close menu item in the system menu.
np~sendSysCommand("Close")
-- Wait a second for the dialog that asks whether to save the changes.
call SysSleep 1
fg = winMgr~foregroundWindow
if fg \== .nil, fg~title = "Notepad" then do
call SysSleep .1
-- Get the No or Don't Save button. Then set the focus to the button and
-- send the space key to it. This simulates a user pushing the button and
-- has the effect of closing Notepad automatically.
button = findDescendent(fg, buttonName)
if button \== .nil then do
fg~focusItem(button)
button~SendKey("SPACE")
end
else do
msg = 'Could not locate the' buttonName~changestr('&', "") 'button used to ' || '0d0a'x || -
'discard the text changes. findDescendent() failed' || '0d0a0d0a'x || -
'You will have to close the Notepad windows manually.'
j = errorDialog(msg)
end
end
else do
msg = 'Failed to connect with the Save Dialog for Notepad' || '0d0a0d0a'x || -
'You may have to close the Notepad windows manually.'
j = errorDialog(msg)
end
return 0
/** windowFailure()
* A simple helper function to put up an error message box.
*/
::routine windowFailure
use strict arg name
msg = "Failed to locate the" name "application window." || '0d0a0d0a'x || -
"Ending the" name "demonstration prematurely."
j = errorDialog(msg)
return .false