432 lines
16 KiB
Rexx
Executable File
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
|
|
|