APPLICATION FRAMEWORK FOR PSION SERIES 3 By John Hind ---------------------------------------------------------------------- A Dynamic Link Library that supports message-based, event-driven application programming in OPL on the PSION Series 3 pocket computer. The library includes support for time-based applications that cannot otherwise be done without machine code. Full documentation, source code and a test application is included. ---------------------------------------------------------------------- FEATURE LIST * Automatic handling of all Series3 operating system messages. * Automatic vectoring of hotkey and menu options to application code. * Simple file handling procedures automatically work from system level * Non-blocking keyboard handling with all key combinations available. * Support for "lazy" screen updating for better responsiveness. * Non-blocking seconds timer with elapsed seconds count. * Non-blocking minutes counter synchronised to real-time clock and with elapsed minutes count. * Message masking for simple mode handling. * Automatic error handling mechanisms. * Application exit interlock works from all exit methods. * Dynamic Link Library may be shared amongst multiple applications. * Includes fix for bug in the MENU command documented by PSION. ---------------------------------------------------------------------- OVERVIEW The library provides a main routine which runs, after initialisation, until the application terminates. This routine invokes callback routines supplied by the application programmer when system, keyboard or timer messages occur. The library also supplies a number of utility routines that can be called from the callback routines. ---------------------------------------------------------------------- FIRST LOOK The distribution archive contains the following files: FRAMELIB.OPO - Translated framework module. FRAMELIB.OPL - Commented framework source code. FTEST.OPL - Source code for example & test program. FRAMELIB.TXT - This file. To run the example program, first copy FRAMELIB.OPO into an \OPO directory on your S3. Then copy FTEST.OPL into the \OPL directory, open it and translate. On completion, install using PSION-I at the system screen. Note that the sample application uses the OPL files in the OPL directory an a convenient example. It will not actually open or modify any files. The test application simply displays messages and parameters as events occur. Use the [Menu] key to see the available facilities. Try pressing keys, switching the S3 on and off, opening new files at the system level etc. Examine the FTEST.OPL application in conjunction with this file to understand how an application is put together. FRAME.OPL is provided for advanced users only and you would not normally need to understand this code to put an application together. ---------------------------------------------------------------------- MESSAGES When running, the "fRun:" procedure generates MESSAGES in response to events from the SERIES 3 operating system. These are in three categories: KEYBOARD,TIMER and SYSTEM (see below). Each message has a number, which determines which Callback Routine gets invoked when that event occurs. When the callback routine is invoked an integer parameter and a string parameter are set (the parameters are actually the global variables "fParm%" and "fParm$"). The callback routine uses these parameters to decide what to do. Sixteen of the messages are "maskable" - unless these are enabled, the callback routine will not be invoked. The message mask is set when "fRun:" is first started and can be changed subsequently by returning a message from a callback routine. The mask is a bit-map with one bit set for each message to be enabled. This mask can be assembled by adding together the values given in the MESSAGE TABLE below. The message handler callbacks return a message number when complete. This will normally be either an error message (negative) or 0 (null message) or 100 (exit message). However, the routine can return any message, including user-defined ones. Care must be taken to avoid infinite loops such as would happen if a callback routine returned its own message number. ---------------------------------------------------------------------- KEYBOARD MESSAGES There are five keyboard messages: #4 is invoked when the user presses a hot-key (PSION key with a letter EG PSION-S). This message is rarely un-masked as there is a special mechanism for handling individual hot-keys. A special callback can be provided for each hot-key used in the application. Hotkeys are enabled and disabled by including or excluding the letter in the hotkey mask. This mask is set from a parameter when "fRun:" is started and can subsequently be changed by a callback routine returning either message #130 or #131. If you use this mechanism, do NOT enable message #4 as the special callbacks will then not be invoked. #5 is invoked when the user makes a keystroke which generates a printable character such as "a", "A" or "*". This includes SPACE, but excludes ENTER and DELETE. #6 is invoked when the user presses one of the "Special" keys such as "up arrow" "ESC" "ENTER" etc. (see SPECIAL KEY TABLE below). #9 is invoked when the "MENU" key is pressed. The associated callback would normally bring up a menu system and then return either message #0 or #4. In the latter case, the parameters would be set by the callback to the hotkey of the selected option. The framework will then use the hotkey callback to activate the option as if the hotkey had been pressed. #10 is invoked when the "HELP" key is pressed. For all keyboard messages there is a special additional parameter in the global variable "fKmod%". This gives the modifier status at the time the key was pressed as per the OPL KMOD function. This is particularly useful for detecting shifted special keystrokes. ---------------------------------------------------------------------- TIMER MESSAGES There are two timers: one generates a message every minute and the other every second. Only one timer may be active at any time. The timers are started and stopped by masking and unmasking their respective messages in the usual way. They are synchronised with the Series-3 clock (i.e. the minute timer message happens just after the minutes have changed on the clock). The timers continue to run even if the application is in the background, however they stop when the SERIES-3 switches off. The message parameter shows how many units of time have been missed when the SERIES-3 was off, or was tied up with other things. For stopwatches and similar applications, the parameter should be added to an accumulator each time the message callback is invoked. This is important, because the system does not guarantee that the message will happen every unit of time. Also, the callback may be called with parameter equal to zero when the timer is synchronising and the callback must cope with this. ---------------------------------------------------------------------- SYSTEM MESSAGES Messages #1 to #3 are system messages invoked when the operating system changes the state of the application. Normally they can be left masked as all normal house keeping is done by the framework. Message #11 is the "Nothing better to do" message. It is invoked when there is a gap in the stream of other messages just before the framework suspends the application to await the next message. Un-mask this to perform low-priority or background processing such as "lazy" screen updating. Messages #100 and above are not handled by the normal callback mechanism but may be returned by callback routines to cause the framework to take appropriate actions. For file-based applications, the "aOpen%:", "aCreate%" and "aClose%" callbacks must be provided. The framework handles externally driven file handling using these routines. For application driven file handling DO NOT call these callbacks directly, go through the framework by returning the appropriate messages. #101 should be returned to create a new file. #102 should be returned to open a file. In both cases, the file name should be in fParm$. Messages #129 to #131 can be returned to change the message and hotkey masks while the application is running. The new value of the message mask should be in fParm% and the new value of the hotkey mask in fParm$. #129 changes only the message mask, #130 only the hotkey mask and #131 changes both masks. ---------------------------------------------------------------------- APPLICATION SKELLETON REM Start of skeleton application APP skull TYPE 3 :REM May be of any type See Programming Manual Cp.11 ENDA PROC skull: REM Global Data required by application LOADM "\OPO\FRAMELIB.OPO" :REM Load the Application Framework Code. REM Application initialisation code (prior to file opening) fAutoOff: :REM Enable auto switch-off for this application. fRun:($0100,"AB",0) :REM Run the application, Menu key and hotkeys REM PSION-A and PSION-B enabled. ENDP REM Application call-back routines REM Other application routines REM End of skeleton application ---------------------------------------------------------------------- MESSAGE TABLE Message fParm% fParm$ Mask Event ======= ====== ====== ==== ===== 0 - Null (Nothing happened) 1 $0001 Program was moved to foreground 2 $0002 Program was moved to background 3 $0004 Machine was switched on 4 keycode char $0008 Hot key was pressed 5 keycode char $0010 Printable character was entered 6 keycode $0020 Special key was pressed 7 seconds $0040 Seconds timer elapsed 8 minutes $0080 Minutes timer elapsed 9 $0100 Menu key was pressed 10 $0200 Help key was pressed 11 $0400 Nothing better to do 12-16 app app etc. Application maskable messages 17-99 app app - Application non-maskable messages 100 - Exit from application 101 filename - Create a new file 102 filename - Open an existing file 129 mask - Change the message mask 130 mask - Change the hotkey mask 131 mask mask - Change both masks Message fParm% fParm$ Error ======= ====== ====== ===== -1 ERR ERR$ OPL System Error (Only if enabled) -2 filename Cannot create file -3 filename Cannot open file -4 filename Bad filename ---------------------------------------------------------------------- SPECIAL KEYCODE TABLE Values in fParm% Modifiers (added together in fKmod%) Key Code Key Code === ==== === ==== Esc 27 Shift $0002 Delete 8 Control $0004 Tab 9 PSION $0008 Enter 13 Caps Lock $0010 up 256 down 257 left 259 right 258 Home 262 End 263 PgDn 261 PgUp 260 Dial 803 ---------------------------------------------------------------------- CALLBACK ROUTINE RESTRICTIONS IMPORTANT: Callback routines must not do keyboard handling or message handling themselves. The following keywords must NOT be used: BUSY; CMD$; GET; GET$; GETCMD$; GETEVENT; KEY; KEY$; KEYA; KEYC; KMOD; LOCK; MENU (use fMenu%: instead); SETNAME; STOP; TESTEVENT. The following keywords must be prefixed with fLock: and followed by fUnLock: : ALERT; DIALOG; EDIT; INPUT ---------------------------------------------------------------------- CALLBACK ROUTINES (Written by application programmer) aOpen%: Open a file and perform any per-file initialisation. aCreate%: Create a file and perform any per-file initialisation. aClose%: Perform any tidy-up and close the current file. These routines MUST be provided for type 2, 3 or 4 OPAs. aOpen%: and aCreate%: should return 0 if successful or an appropriate error code (-2, -3 or -4) otherwise. aClose%: should return zero on success or non-zero to abort. aClose%: may include a confirm dialog if desired, this will be visible even for file changes initiated at the system level. aError%:(e%) Error handler. e% is the error number. This routine is optional, if provided it should return either 0 or 100, or pass the error back for handling by the default handler. aMh1%: Message handlers for messages 1-99 above. Should return 0, aMh99%: an error number or another message (NEVER the same message). These routines must be provided for all messages below 99 which are defined and can be unmasked during program execution. aHkA%: Hot Key handlers for keys A to Z. Should return 0, an error aHkZ%: number or another message. These routines must be provided for any Hot Keys which may be unmasked during program execution. ---------------------------------------------------------------------- FRAMEWORK ROUTINES (Provided in library) fRun:(mesMsk%,hkMsk$,sysE%) This is the main routine for the Application Framework system. It is called from the application's main PROC and, on exiting the application run is complete. The parameters are: mesMsk%: Initial value of message mask. hkMsk$: Initial value of hotkey mask. sysE%: True (non zero) if system errors should be trapped. Callback routines (or initialisation code) may themselves call the following framework routines: fMenu%: Use this routine in place of the OPL keyword MENU. It incorporates fLock: and fUnlock: below and also implements a PSION supplied fix for a bug in the MENU command. fLock: Use these before and after any command that waits for user fUnlock: keyboard activity I.E. a dialogue box or alert box. fAutoOff: Call this to allow the Series 3 to switch off when an application using timers is running. fVer%: Returns the version number of FRAMELIB.OPO. ---------------------------------------------------------------------- CONDITIONS OF USE The file FRAMELIB.OPO and the associated documentation and source code is provided as-is and the author will not be liable for any consequences of its use. The file FRAME.ZIP may be freely distributed so long as it is unchanged and complete. The file FRAMELIB.OPO may be freely distributed as part of an application as long as the documentation credits me for my contribution and a copy of the application is made available for my use free of charge. If an application using FRAMELIB.OPO is sold for profit, I request that a donation be made on my behalf to Amnesty International. I would appreciate any bug reports, comments, ideas or suggestions for the further development of this system. John Hind 1a Brunswick Quay, Redriff Road, London SE16 1PU, United Kingdom. CompuServe: 70374,756 CIX: jhind@cix.compulink.co.uk END OF DOCUMENT ----------------------------------------------------------------------