EPOC   SDK Home Glossary   Previous Next Up

I/O functions and commands


Contents


Overview

Section Contents

The memory which an OPL program may use is unlimited up to the constraint placed by the machine itself. This means that addresses must be represented by 32-bit integers, the widest numeric type available in OPL.

OPL includes powerful facilities to handle input and output (‘I/O’). These functions and commands can be used to access all types of files in the filing system, as well as various other parts of the low-level software.

This section describes how to open, close, read and write to files, and how to set the position in a file. The data file handling commands and functions have been designed for use specifically with data files. The I/O functions and commands are designed for general file access. You don’t need to use them to handle data files.

These are powerful functions and commands and they must be used with care. Before using them you must read this section closely and have a good grounding in OPL in general.


Error handling

You should have a good understanding of error handling (see Error Handling) before using the I/O functions.

The functions in this section never raise an OPL error message. Instead they return a value - if this is less than zero an error has occurred. It is the responsibility of the programmer to check all return values, and handle errors appropriately. Any error number returned will be one of those in the list given in OPL error values. You can use ERR$ to display the error as usual.


Handles

Many of these functions use a handle, which must be a long integer variable. IOOPEN assigns this handle variable a value, which subsequent I/O functions use to access that particular file. Each file you IOOPEN needs a different handle variable.


var variables

In this section, var denotes an argument which should normally be a LOCAL or GLOBAL variable. (Single elements of arrays may also be used, but not field variables or procedure parameters.) Where you see var the address of the variable is passed, not the value in it. (This happens automatically; don’t use ADDR yourself.)

In many cases the function you are calling passes information back by setting these var variables.

var is just to show you where you must use a suitable variable; you don’t actually type var.

For example: ret%=IOOPEN(var handle&,name$,mode%) in the syntax description indicates that IOOPEN(h&,"abc",0) is correct (provided h& is a simple variable), but IOOPEN(100,"abc",0) is incorrect.

It is possible, though, that you already have the address of the variable to use. It might be that this address is held in a field variable, or is even a constant value, but the most common situation is when the address was passed as a parameter to the current procedure.

If you add a # prefix to a var argument, this tells OPL that the expression following is the address to be used, not a variable whose address is to be taken.

Here is an example program:

    PROC doopen:(phandle&, name$, mode%)
          LOCAL error%
          REM IOOPEN, handling errors
          error% = IOOPEN(#phandle&, name$, mode%)
          IF error% : RAISE error% : ENDIF
    ENDP

The current value held in phandle& is passed to IOOPEN. You might call doopen: like this:

    LOCAL filhand%,...
    ...
    doopen:(ADDR(filhand%),"log.txt",$23)
    ...

The doopen: procedure calls IOOPEN with the address of filhand%, and IOOPEN will write the handle into filhand%.


Opening a file with IOOPEN

Section Contents

    ret%=IOOPEN(var handle%,name$,mode%

or

    ret%=IOOPEN(var handle%,address&,mode%)

for unique file creation.

Creates or opens a file (or device) called name$ and sets handle% to the handle to be used by the other I/O functions.

mode% specifies how the file is to be opened. It is formed by ORing together values which fall into the three following categories:


Mode Category 1 - Open mode

One and only one of the following values must be chosen from this category.

$0000

Open an existing file (or device). The initial current position is set to the start of the file.

$0001

Create a file which must not already exist.

$0002

Replace a file (truncate it to zero length) or create it if it does not exist.

$0003

Open an existing file for appending. The initial current position is set to the end of the file. For text format files (see $0020 below) this is the only way to position to end of file.

$0004

Creates a file with a unique name. For this case, you must use the address of a string instead of name$. This string specifies only the path of the file to be created (any file name in the string is ignored). The string at address% is then set by IOOPEN to the unique file name generated (this will include the full path). The string must be large enough to take 130 characters (the maximum length file specification). For example:

    s$="C:\home\"
    IOOPEN(handle%,ADDR(s$),mode%)

This mode is typically used for temporary files which will later be deleted or renamed.


Mode Category 2 - File format

One and only one of the following values must be chosen from this category. When creating a file, this value specifies the format of the new file. When opening an existing file, make sure you use the format with which it was created.

$0000

The file is treated as a byte stream of binary data with no restriction on the value of any byte and no structure imposed upon the data. Up to 16K can be read from or written to the file in a single operation.

$0020

The file is treated as a sequence of variable length records. The records are assumed to contain text terminated by any combination of the CR and LF ($0D, $0A) characters. The maximum record length is 256 bytes and Control-Z ($1A) marks the end of the file.

These values are declared as constants in Const.oph. See Including header files.


Mode Category 3 - Access flags

Any combination of the following values may be chosen from this category.

$0100

Update flag. Allows the file to be written to as well as read. If not set, the file is opened for reading only. You must use this flag when creating or replacing a file.

$0200

Choose this value if you want the file to be open for random access (not sequential access), using the IOSEEK function.

$0400

Specifies that the file is being opened for sharing for example, with other running programs. Use if you want to read, not write to the file. If the file is opened for writing ($0100 above), this flag is ignored, since sharing is then not feasible. If not specified, the file is locked and may only be used by this running program.


Closing a file with IOCLOSE

Files should be closed when no longer being accessed. This releases memory and other resources back to the system.

    ret%=IOCLOSE(handle%)

Closes a file (or device) with the handle handle% as set by IOOPEN.


Reading a file with IOREAD

Section Contents

    ret%=IOREAD(handle%,address&,maxLen%)

Reads up to maxLen% bytes from a file with the handle handle% as set by IOOPEN. address& is the address of a buffer into which the data is read. This buffer must be large enough to hold a maximum of maxLen% bytes. The buffer could be an array or even a single integer as required. No more than 16K bytes can be read at a time.

The value returned to ret% is the actual number of bytes read or, if negative, is an error value.


Text files

If maxLen% exceeds the current record length, data only up to the end of the record is read into the buffer. No error is returned and the file position is set to the next record.

If a record is longer than maxLen%, the error value ‘Record too large’ (-43) is returned. In this case the data read is valid but is truncated to length maxLen%, and the file position is set to the next record.

A string array buffer$(255) could be used, but make sure that you pass the address ADDR(buffer$)+1 to IOREAD. This leaves the leading byte free. You can then POKEB the leading byte with the count (returned to ret%) so that the string conforms to normal string format. See the example program.


Binary files

If you request more bytes than are left in the file, the number of bytes actually read (even zero) will be less than the number requested. So if ret%<maxLen%, end of file has been reached. No error is returned by IOREAD in this case, but the next IOREAD would return the error value ‘End of file’ (-36).

To read up to 16K bytes (8192 integers), you could declare an integer array buffer%(8192).


Writing to a file

    ret%=IOWRITE(handle%,address&,length%)

Writes length% bytes stored in a buffer at address& to a file with the handle handle%.

When a file is opened as a binary file, the data written by IOWRITE overwrites data at the current position.

When a file is opened as a text file, IOWRITE writes a single record; the closing CR/LF is automatically added.


Positioning within a file

ret%=IOSEEK(handle%,mode%,var offset&)

Seeks to a position in a file that has been opened for random access (see IOOPEN above).

mode% specifies how the argument offset& is to be used. offset& may be positive to move forwards or negative to move backwards. The values you can use for mode% are:

1

Set position in a binary file to the absolute value specified in offset&, with 0 for the first byte in the file.

2

Set position in a binary file to offset& bytes from the end of the file

3

Set position in a binary file to offset& bytes relative to the current position.

6

Rewind a text file to the first record. offset& is not used, but you must still pass it as a argument, for compatibility with the other cases.

IOSEEK sets the variable offset& to the absolute position set.


Example — displaying a plain text file

This program opens a plain text file — such as one created with the Export as text option in the File menu of the Program editor — and types it to the screen. Press Esc to quit and any other key to pause the typing to the screen.

    PROC ioType:
          LOCAL ret%,fName$(128),txt$(255),address&
          LOCAL handle%,mode%,k%
          PRINT "Filename?", :INPUT fName$ : CLS
          mode%=$0400 OR $0020  REM open=$0000,text=$0020,share=$0400
          ret%=IOOPEN(handle%,fName$,mode%)
          IF ret%<0
                showErr:(ret%)
                RETURN
          ENDIF
          address&=ADDR(txt$)
          WHILE 1
                k%=KEY
                IF k%                        REM if keypress
                      IF k%=27                   REM Esc pressed
                            RETURN            REM otherwise wait for a key
                      ELSEIF GET=27
                            RETURN            REM Esc pressed
                      ENDIF
                ENDIF
                ret%=IOREAD(handle%,address&+1,255)
                IF ret%<0
                      IF ret%<>-36            REM NOT EOF
                            showErr:(ret%)
                      ENDIF
                      BREAK
                ELSE 
                      POKEB address&,ret%      REM leading byte count
                      PRINT txt$
                ENDIF
          ENDWH
          ret%=IOCLOSE(handle%)
          IF ret% 
                showErr:(ret%)
          ENDIF
          PAUSE -100 :KEY
    ENDP
    
    PROC showErr:(val%)
          PRINT "Error",val%,err$(val%)
          GET
    ENDP

Asynchronous requests and semaphores

Section Contents

This section provides the general background necessary for understanding how EPOC I/O devices can be accessed by an OPL application program.


Asynchronous requests

Many operating system services are implemented in two steps:

  1. make the service request (sometimes referred to as the queuing of a request)
  2. wait for the requested operation to complete

In most cases, as well as providing functions for each step, the system provides a function containing both the above steps. Such functions are called synchronous because they automatically synchronise the requesting process by waiting until the operation has completed. The internal function that makes the request without waiting for completion is called an asynchronous function.

Examples of asynchronous request functions are:

IOC (or IOA)

for requests on an open I/O channel

KEYA

for requests on the keyboard channel

GETEVENTA32

for requests of events from the window server

PLAYSOUNDA:

(in System.opx) for requests to play sound files

The synchronous versions of the above functions are IOW , GET, GETEVENT32 and PLAYSOUND: respectively.

Applications use asynchronous requests in situations like the following:

  1. make request A
  2. make request B
  3. wait for either of the requested operations to complete

Processes wait for the completion of asynchronous requests by waiting on their I/O semaphore where each request is associated with a status word.


The I/O semaphore

When a process is created, the system automatically creates an I/O semaphore on its behalf (a more accurately descriptive name would have been the asynchronous request semaphore). After making one or more asynchronous requests using IOC or IOA, a process calls IOWAIT to wait on the I/O semaphore for one of the requests to complete. A typical application spends most of its time waiting on its I/O semaphore. For example, an interactive application process that is waiting for user input is waiting on the I/O semaphore.

Semaphores are provided to synchronise cooperating processes (where, in this context, a process includes a hardware interrupt). In OPL semaphores are used for synchronising the completion of asynchronous requests.

The semaphores in EPOC are counting semaphores, having a signed value that is incremented by calling IOSIGNAL and decremented by calling IOWAIT. A semaphore with a negative value implies that a process must wait for the completion of an event.

The process or the hardware interrupt handler that implements the requested operation sends a signal to the process (using a generalised version of IOSIGNAL directed to the required process) to indicate that the operation has completed. If one or more wait handlers have been installed (wait handlers are described below), they may process the signal and re-signal using IOSIGNAL. In some cases, it is convenient for the requester to use IOSIGNAL to signal itself and subsequently to process that signal in a central call to IOWAIT.


Status words

Although the arguments to asynchronous request functions vary, they all take a so-called status word argument, which subsequently contains the status of the requested operation. The status word is a 16-bit integer except when calling an asynchronous OPX procedure that specifically requires a 32-bit integer status word, such as PLAYSOUNDA: in System.opx.

All asynchronous requests exhibit the following behaviour:

Making a request while a previous request on the same status word is still pending will normally result in a system panic where the program is killed immediately, without being able to trap the error.

When there are multiple requests, each request is associated with a different status word. After returning from IOWAIT, the caller typically polls each status word until one is found that contains other than -46. That completion is then processed (which might include renewing the asynchronous request) and IOWAIT is called again to process the next completion.


Cancelling an asynchronous request

Most asynchronous request functions made using IOC (or IOA) can be cancelled. To cancel such requests use the IOCANCEL function.

For asynchronous requests made using a mechanism other than IOC (or IOA), a specific cancelling function must be used instead:

The following general principles apply to all functions that cancel an asynchronous request:

A 16-bit status word is set to -48 when a request has been effective.

A 32-bit status word is set to -3 (EPOC’s error code for ‘Cancel error’) when a request using a 32-bit status word is cancelled.


Waiting for a particular completion

When waiting for the completion of a particular asynchronous request, the wait on the I/O semaphore must be sure that it is not fooled into a premature return by the completion of any other pending asynchronous request. This is done by calling IOWAITSTAT which behaves in a similar way to IOWAIT except that it only returns when the associated status word is other than -46.

For a 32-bit status word request, IOWAITSTAT32 is used instead, again behaving in a similar way to IOWAIT except that it only returns when the associated 32-bit status word is other than &80000001.

In general, IOWAITSTAT (IOWAITSTAT32) is a safer option than IOWAIT to "use up" the signal resulting from the cancelled operation. If the cancel is not immediately effective and another completion causes IOWAIT to return, the program could continue and make another request before the cancelled operation completes (which would result in a process panic).


A first example using asynchronous I/O

In the following example, the opened asynchronous timer timChan% is used to construct a synchronous function which attempts to write the passed string to the opened serial channel serChan%. If it takes more that 5 seconds to complete the write, the procedure raises the ‘inactivity’ error -54. For simplicity it is assumed that there are no other outstanding events which could complete and that both requests started successfully. Thus it is certain that on return from the call to IOWAIT, one of the two asynchronous requests has completed.

    PROC strToSer:(inStr$)
          LOCAL str$(255)      REM local copy of inStr$ needed for ADDR
          LOCAL len%,timStat%,serStat%,timeout%,ret%,pStr&
    
          str$=inStr$
          pStr&=ADDR(str$)+1
                      REM pointer to string skipping leading count byte
          len%=LEN(str$)
          IOC(serChan%,2,serStat%,#pStr&,len%)
          REM request asynchronous serial write
          timeout%=50                        REM 5 second timeout
          IOC(timChan%,1,timStat%,timeout%)
                                              REM Relative timer - function 1
          IOWAIT
          IF serStat%=-46                  REM must have timed out
          IOCANCEL(serChan%)                  REM cancel serial request
          IOWAITSTAT serStat%            REM use up the signal
          RAISE -54                              REM inactivity timeout
          ENDIF
          IOCANCEL(timChan%)                  REM cancel timer request
          IOWAITSTAT timStat%            REM use up the signal
    ENDP

Polling rather than waiting

In a multi-tasking operating system it is extremely anti-social to wait for an operation to complete by polling the status word in a tight loop rather than call IOWAIT (because the polling will "hog" the processor to no benefit). However, when there is useful work to be done between each poll, it can be appropriate to poll - for example, to check periodically for user input while performing an extended calculation.

When a poll detects a completed status word, it is still obligatory to "use up" the signal by calling IOWAIT (otherwise you will get a "stray signal" later).


Polling example

The status word will be set only when either IOWAIT or IOYIELD is called. For a 32-bit status word, call IOWAITSTAT32 instead.

For example:

    ...
    IOC(handle%,func%,stat%,#pBuf&,len%)
    DO
          calc:
          REM perform part of some calculation until request complete
          IOYIELD                                REM allow status word to be set
    UNTIL stat%<>-46
    ...

I/O device handling and the asynchronous request functions

The following I/O functions provide access to devices. A full description is not within the scope of this manual, since these functions require extensive knowledge of the EPOC operating system and related programming techniques. The syntax and argument descriptions are provided here for completeness.

The previous section explains in detail the semantics of asynchronous I/O. In the descriptions of the asynchronous I/O functions below, a careful reading of that section is assumed.

ret%=IOW(handle%,func%,var arg1,var arg2)
The device driver opened with handle% (as returned by IOOPEN) performs the synchronous I/O function func% with the two further arguments. The size and structure of these two arguments is specified by the particular device driver’s documentation.

IOC(handle%,func%,var stat%,var a1,var a2)
IOC(handle%,func%,var stat%,var a1)
IOC(handle%,func%,var stat%)
Make an I/O request with guaranteed completion. The device driver opened with handle% (as returned by IOOPEN) performs the asynchronous I/O function func% with up to two further arguments. The size and structure of these arguments is specified by the particular device driver’s documentation.

As explained in detail in the previous section, asynchronous means that the IOC returns immediately, and the OPL program can carry on with other statements. status% will always be set to -46, which means that the function is still pending.

When, at some later time, the function completes, status% is automatically changed. (For this reason, status% should usually be global since if the program is still running, status% must be available when the request completes, or the program will probably crash). If status%>=0, the function completed without error. If status%<0, the function completed with error. The return values and error codes are specific to the device driver.

If an OPL program is ready to exit, it does not have to wait for any signals from pending IOC calls.

ret%=IOA(handle%,func%,var status%,var arg1,var arg2)
The device driver opened with handle% (as returned by IOOPEN) performs the asynchronous I/O function func% with two further arguments. The size and structure of these two arguments is specified by the particular device driver’s documentation.

This has the same form as IOC, but the return value cannot be ignored. IOC is effectively the same as:

    ret%=IOA(h%,f%,stat%,...)
    IF ret%<0
          stat%=ret%
          IOSIGNAL
    ENDIF

IOC allows you to assume that the request started successfully - any error is always given in the status word stat%. If there was an error, stat% contains the error code and the IOSIGNAL causes the next IOWAIT to return immediately as if the error occurred after completion. There is seldom a requirement to know whether an error occurred on starting a function, and IOC should therefore nearly always be used in preference to IOA.

IOWAIT
Wait for an asynchronous request (such as one requested by IOC, KEYA or GETEVENTA32) to complete. IOWAIT returns when any asynchronous I/O function completes. Check status% to find out which request has completed. Use IOWAITSTAT with the relevant status word to wait for a particular request to complete.

IOSIGNAL
Replace a signal of an I/O function’s completion.

As shown in ‘A simple example using asynchronous I/O’ in the previous section, it is sometimes useful to construct a synchronous operation from two asynchronous operations by waiting for either to complete before returning. In that case it waited for either the serial write request or a timeout. As noted there, the example assumed that there were no other outstanding asynchronous requests. If there had been one or more asynchronous requests made before calling that procedure, such as a request to play a sound file, and if that request had completed before both the serial write and the timer request, the procedure would incorrectly assume that the timer had completed:

    IOWAIT
    IF serStat%=-46                  REM must have timed out
          IOCANCEL(serChan%)            REM cancel serial request
          IOWAITSTAT serStat%      REM use up the signal
          RAISE -54                        REM inactivity timeout
    ENDIF
    IOCANCEL(timChan%)                  REM cancel timer request
    IOWAITSTAT timStat%            REM use up the signal

To deal with this situation correctly, the procedure should instead check that one of the particular two requests it knows about has completed and re-signal to ‘put back’ the signal consumed for the sound file completion:

    PROC strToSer:(inStr$)
          LOCAL str$(255)      REM local copy of inStr$ needed for ADDR
          LOCAL len%,timStat%,serStat%,timeout%,ret%,pStr&
          LOCAL signals%            REM count of external signals
          LOCAL err%
    
          str$=inStr$
          pStr&=ADDR(str$)+1
                            REM ptr to string skipping leading count byte
          len%=LEN(str$)
          IOC(serChan%,2,serStat%,#pStr&,len%)
          REM request asynchronous serial write
          timeout%=50                  REM 5 second timeout
          IOC(timChan%,1,timStat%,timeout%)
                                        REM relative timer - function 1
          WHILE 1                        REM forever loop
                IOWAIT                        REM wait for any completion
                IF timStat%<>-46            REM timed out
                      IOCANCEL(serChan%)            REM cancel serial request
                      IOWAITSTAT serStat%      REM use up the signal
                      err%=-54            REM inactivity timeout (raised 
                                        REM below after re-signalling)
                      BREAK                  REM stop waiting and re-signal
                ELSEIF serStat%<>-46            REM serial write complete
                      IOCANCEL(timChan%)            REM cancel timer request
                      IOWAITSTAT timStat%      REM use up the signal
                      BREAK                  REM stop waiting and re-signal
                ELSE                                    REM other unknown request
                      signals%=signal%+1            REM count other signals
                                                    REM loop again for next
                ENDIF
          ENDWH
          WHILE signals%>0      
                REM now re-signal any consumed external signals
                IOSIGNAL
                signals%=signals%-1
          ENDWH
          IF err%
                RAISE err%
          ENDIF
    ENDP

IOSIGNAL is called only after exiting the IOWAIT loop, otherwise the signal would cause the IOWAIT to return immediately.

IOWAITSTAT var status%
Wait for a particular asynchronous function, called with IOC, to complete.

IOWAITSTAT32 var stat&
Similar to IOWAITSTAT but takes a 32-bit status word. IOWAITSTAT32 should be called only when you need to wait for completion of a request made using a 32-bit status word when calling an asynchronous OPX procedure. status& will be &80000001 while the function is still pending, and on completion will be set to the appropriate EPOC error code, listed in Error Handling. See also About OPXs and Keyword Reference.

IOYIELD
Ensures that any asynchronous function is given a chance to run. Some devices are unable to perform an asynchronous request if an OPL program becomes computationally intensive, using no I/O (screen, keyboard etc.) at all. In such cases, the OPL program should use IOYIELD before checking its status% variable. This is always the case under EPOC. IOYIELD is the equivalent of IOSIGNAL followed by IOWAIT - the IOWAIT returns immediately with the signal from IOSIGNAL, but the IOWAIT causes any asynchronous handlers to run.

IOCANCEL(handle%)
Cancels any outstanding asynchronous I/O request made using IOC (or IOA) on the specified channel, causing them to complete with the completion status word containing -48 (‘I/O cancelled’). The return value is always zero and may be ignored.

The IOCANCEL function is harmless if no request is outstanding (e.g. if the function completed just before cancellation requested).

GETEVENTA32(var status%,var event&())
This is an asynchronous window server read function. You must declare a long integer array with at least 16 elements. If a window server event occurs, the information is returned in event&() as described under GETEVENT32 in the alphabetic listing.

GETEVENTC(var status%)
Cancels a GETEVENTA32. Note that IOWAITSTAT should not be called after GETEVENTC - OPL consumes the GETEVENTC signal.

err%=KEYA(var status%,key%())
This is an asynchronous keyboard read function. You must declare an integer array with two elements here, key%(1) and key%(2) to receive the keypress information. If a key is pressed, the information is returned in this way:

key%(1) is assigned the character code of the key.

The least significant byte of key%(2) takes the key modifier, in the same way as KMOD 2 for Shift down, 4 for Control down and so on. KMOD cannot be used with KEYA.

The most significant byte of key%(2) takes the count of keys pressed (0 or 1).

KEYA needs an IOWAIT in the same way as IOC.


Some useful IOW functions

IOW has this specification:

    ret%=IOW(handle%,func%,var arg1,var arg2)

Here are some uses:

    LOCAL a%(6)
    IOW(-2,8,a%(),a%())             REM 2nd a% is ignored

senses the current text window (as set by the most recent SCREEN command) and the text cursor position ignoring any values already in the array a%(). This gives the same information as SCREENINFO, which should be used in preference (see Keyword Reference).

The first four elements are set to represent the offset of the current text window from the default text window. a%(1) is set to the x-offset of the top left corner of the current text window from the default text window’s top left corner and a%(2) to the y-offset of the top left corner of current text window. Similarly a%(3) and a%(4) give the offset of bottom right corner of text window from the bottom right corner of the default text window. For example, if the most recent SCREEN command was SCREEN 10,11,4,5 the first four elements of the array a%() would be set to (3,4,13,15). The x and y positions of the cursor relative to the current text window are written to a%(5) and a%(6) respectively. All positions and offsets take 0,0, not 1,1, as the point at the top left.

    LOCAL i%,a%(6)
    i%=2
    a%(1)=x1% :a%(2)=y1%
    a%(3)=x2% :a%(4)=y2%
    IOW(-2,7,i%,a%())

clears a rectangle at x1%,y1% (top left), x2%,y2% (bottom right). If y2% is one greater than y1%, this will clear part or all of a line.


Example of IOW screen functions

The final two procedures in this module call the two IOW screen functions described beforehand. The rest of the module lets you select the function and values to use. It uses the technique used in Menus of handling menus and short-cut keys by calling procedures with string expressions.

    PROC iotest:
          GLOBAL x1%,x2%,y1%,y2%
          LOCAL i%,h$(2),a$(5)
          x1%=2 :y1%=2
          x2%=25 :y2%=5                         REM our test screensize
          SCREEN x2%-x1%,y2%-y1%,x1%,y1%
          AT 1,1
          PRINT "Text window IO test"
          PRINT "Control-Q quits"
          h$="cr"                               REM our shortcut keys
          DO       
                i%=GET
                IF i%=$122                  REM MENU key
                      mINIT
                      mCARD "Set","Rect",%r
                      mCARD "Sense","Cursor",%c
                      i%=MENU
                      IF i% AND INTF(LOC(h$,CHR$(i%)))
                            a$="proc"+chr$(i%)
                            @(a$):
                      ENDIF
                ELSEIF i% AND $200                  REM shortcut key
                      i%=(i%-$200)
                      i%=LOC(h$,CHR$(i%))      REM One of ours? 
                      IF i%
                            a$="proc"+MID$(h$,i%,1)
                            @(a$):
                      ENDIF            REM ignore other weird keypresses
                ELSE                        REM some other key, so return it
                      PRINT CHR$(i%);
                ENDIF
          UNTIL 0
    ENDP
    
    PROC procc:
          LOCAL a&
          a&=iocurs&:
          PRINT "x";1+(a& AND &ffff);
          PRINT "y";1+(a&/&10000)
    ENDP
    
    PROC procr:
          LOCAL xx1%,yy1%,xx2%,yy2%
          LOCAL xx1&,yy1&,xx2&,yy2&
          dINIT "Clear rectangle"
          dLONG xx1&,"Top left x",1,x2%-x1%
          dLONG yy1&,"Top left y",1,y2%-y1%
          dLONG xx2&,"Bottom left x",2,x2%-x1%
          dLONG yy2&,"Bottom left y",2,y2%-y1%
          IF DIALOG
                xx1%=xx1&-1 :xx2%=xx2&-1
                yy1%=yy1&-1 :yy2%=yy2&-1
                iorect:(xx1%,yy1%,xx2%,yy2%)
          ENDIF
    ENDP
    
    PROC iocurs&:
          LOCAL a%(4),a&
          REM don’t change the order of these!
          a%(1)=x1% :a%(2)=y1%
          a%(3)=x2% :a%(4)=y2%
          IOW(-2,8,a%(),a%())       REM 2nd a% is ignored
          RETURN a&
    ENDP
    
    PROC iorect:(xx1%,yy1%,xx2%,yy2%)
          LOCAL i%,a%(6)
          i%=2 :REM "clear rect" option
          a%(1)=xx1% :a%(2)=yy1%
          a%(3)=xx2% :a%(4)=yy2%
          IOW(-2,7,i%,a%())
    ENDP
EPOC       SDK Home Glossary   Previous Next Up