|Z88 Developers' Notes|
9. Input and the keyboard decoder
Input from the keyboard can be achieved by treating it as a device and using the file I/O calls. Four calls read from the standard input, which unless it has been rebound by the CLI, will be the keyboard. These calls are:
OS_In read a character from the standard input OS_Tin read a character from the standard input, with timeout GN_Sip standard input line routine OS_Sr reads a character when doing a "Page Wait". Returns always ASCII 8 or an RC_ error code.GN_Sip is described later in this section and OS_Sr is discussed in "Miscellaneous useful routines". OS_In and OS_Tin return the character read in register A and Fc = 0 to indicate success. Since these are pre-emptable calls they may return Fc = 1 and any of RC_SUSP, RC_DRAW, RC_ESC, RC_QUIT and, in the case of OS_Tin, RC_TIME. These calls usually returns ASCII values, but for special Z88 keys and menu commands, some other encoding is required. The solution is that when a special key or menu command occurrs, the OS_In or OS_Tin will return a zero. The call is then made again and the value returned by this second call corresponds to the special key or menu command. The codes for the special keyboard sequences are shown below, those marked * are not zero prefixed. Keys marked with ** are internal keycodes and not available to applications. Finally, note that register pair AF and the alternate registers are corrupted by OS_In (as almost all system calls). OS_Tin waits for keyboard input for as long as the number of centiseconds specified in the BC(in) register pair, and on exit BC will be the centiseconds of the timeout remaining, and so BC will have changed as well as AF and the alternate register set.
Key normal <SQUARE> <DIAMOND> <SHIFT> <SQUARE> IN_SQU, $B8 ** <DIAMOND> IN_DIA, $C8 ** <SHIFT> IN_SHI, $D8 ** <LOCK> IN_LOCK, $E8 *** <SPACE> IN_SPC, $20 IN_ASPC, $B0 IN_DSPC, $C0 - <ENTER> IN_ENT, $0D * IN_AENT, $B1 IN_DENT, $C1 IN_SENT, $D1 <TAB> IN_TAB, $09 * IN_ATAB, $B2 IN_DTAB, $C2 IN_STAB, $D2 <DEL> IN_DEL, $7F * IN_ADEL, $B3 IN_DDEL, $C3 IN_SDEL, $D3 <ESC> IN_ESC, $1B * IN_AESC, $B4 IN_DESC, $C4 IN_SESC, $D4 ** <MENU> IN_MEN, $E5 ** IN_AMEN, $B5 IN_DMEN, $C5 IN_SMEN, $D5 <INDEX> IN_IDX, $E6 ** IN_AIDX, $B6 IN_DIDX, $C6 IN_SIDX, $D6 <HELP> IN_HLP, $E7 ** IN_AHEL, $B7 IN_DHEL, $C7 IN_SHEL, $D7 <LEFT> IN_LFT, $FC IN_ALFT, $F0 IN_DLFT, $F4 IN_SLFT, $F8 <RIGHT> IN_RGT, $FD IN_ARGT, $F1 IN_DRGT, $F5 IN_SRGT, $F9 <DOWN> IN_DWN, $FE IN_ADWN, $F2 IN_DDWN, $F6 IN_SDWN, $FA <UP> IN_UP, $FF IN_AUP, $F3 IN_DUP, $F7 IN_SUP, $FB***) This 'key' is the forces Lock out state produced by switching the machine on, and while holding both <SHIFT> keys down, pressing the <CAPS> lock key.
Note that the diamond key operates like a <CTRL> key on a conventional keyboard and can be used to generate the sub-32 control characters, eg. <>G for BEL,
provided the key in question is not a menu command. The following is a list of obtainable control characters:
HEX DECIMAL SYMBOL KEYS DESCRIPTION $00 0 NUL <>= NULL $01 1 SOH <>A Start of header $02 2 STX <>B Start of text $03 3 ETX <>C End of text $04 4 EOT <>D End of transmission $05 5 ENQ <>E Enquiry $06 6 ACK <>F Acknowledge $07 7 BEL <>G Bell $08 8 BS <>H Backspace $09 9 HT <>I Horizontal tabulation $0A 10 LF <>J Line feed $0B 11 VT <>K Vertical tabulation $0C 12 FF <>L Form feed $0D 13 CR <>M Carriage return $0E 14 SO <>N Shift out $0F 15 SI <>O Shift in $10 16 DLE <>P Data link escape $11 17 DC1 <>Q Device control 1 (XON) $12 18 DC2 <>R Device control 2 $13 19 DC3 <>S Device control 1 (XOFF) $14 20 DC4 <>T Device control 4 $15 21 NAK <>U Negative acknowledge $16 22 SYN <>V Synchronous idle $17 23 ETB <>W End of transmitted block $18 24 CAN <>X Cancel line $19 25 EM <>Y End of medium $1A 26 SUB <>Z Substitute (End of file) $1B 27 ESC <>[ or ESC Escape $1C 28 FS <>\ File separator $1D 29 GS <>] Group separator $1E 30 RS <>` Record separator $1F 31 US <>- Unit separatorThe Input Line Routine
GN_Sip is the standard system input line routine and used by most of the applications (Diary uses it for editing individual lines on a date page). It provides access to all the standard editing commands which are:
<>DEL Delete line <>D Delete to end of line <>G Delete character under cursor, rightward <>M <ENTER> <>S Swap case <>T Delete word under cursor <>U Insert character <>V Insert/Overtype (see below for complications) <><LEFT> Start of line <><RIGHT> End of line <SHIFT><LEFT> Previous word <SHIFT><RIGHT> Next wordWhere appropriate the following editing commands should be implemented (this is machine conventions):
<>J Next option , where input is limited all the option can be cycled through using this command <><UP> Top of current page <><DOWN> Bottom of current page <SHIFT><UP> Move up a screenful <SHIFT><DOWN> Move down a screenful <TAB> Next column or TAB <SHIFT><TAB> Previous column or TABThe basic specifications of GN_Sip is as follows:
GN_Sip, system input line routine
RST 20H, DEFW $3909
DE = buffer for input string A0 = 1, buffer already contains data to be edited A1 = 1, force insert/overwrite mode (see A2) A2 = 1, if A1 = 1, 0 = insert mode, 1 = overwrite mode A3 = 1, return unexpected characters A4 = 1, return if wrap occurs A5 = 1, single line lock control A6 = 1, disply in reverse video A7 = 1, if A3 = 1, allow for insert/overwrite return B = length of buffer C = cursor position, if A0 = 1 L = width of line, if A5 = 1 (incl. null-terminator)OUT, if call successful:
Fc = 0 B = length of line entered, including terminating null C = cursor position on exit A = character which caused end of inputOUT, if call failed:
Fc = 1 A = error code: RC_BAD ($04), bad arguments RC_WRAP ($0D), wrapping has occurred (only if A4 = 1) RC_SUSP ($69), suspicion of suspension RC_DRAW ($66), application screen needs redrawing RC_QUIT ($67), kill request (e.g. from INDEX) RC_ESC ($01), if escape detection is enabledRegisters changed after return:
....DEHL/IXIY same AFBC..../.... different
If bit 0 of register A is set then DE should point to a null-terminated string which is no greater than the buffer length specified in B. GN_Sip will write this string to standard output starting at the cursor position and then place the cursor at the position in the buffer indicated by C. If C is greater than B, then the cursor is placed at the end of the buffer. Note that if GN_Sip is suspended then to continue editing the cursor needs to be repositioned to the start of the input line and GN_Sip called again with A0 set and the buffer length reset to its initial value. Unless this is done suspension will not be transparent, eg. whenever <DIAMOND> is inadvertently pressed during input, the input would be terminated or ots output would be corrupted.
Setting A1 allows you to force insert or overtype mode, with A2, as the mode to be used in the input line, rather than using the default as set by the Panel. This can be useful in its own right and in addition can be used to implement a local insert or overtype mode.
If A3 is not set then input is terminated only by <ENTER>, A = IN_ENT, or <ESC>. <ESC> will return with A = IN_ESC if escape detection is disabled, or A = RC_ESC and Fc = 1 if escape detection is enabled. However, if A3 is set then many more key sequences will cause the routine to exit. All the single letter Diamond codes will return their control character, except for <>D, <>G, <>S, <>T, <>U and <>V, which carry out their normal editing functions. Menu commands in the form of diamond sequences, excepting those starting with D, G, S, T, U and V, will return their command code. <>S and the <LEFT> and <RIGHT> arrows, with or without <SHIFT> or <DIAMOND>, will return their codes if an attempt is made to move outside of the buffer and A4 is not set. Any other key sequence which has no meaning in the input line routine will cause an exit, eg. <SHIFT><UP> will return with A = IN_SUP. Note that if A7 is set then <>V will cause an exit, thus allowing a local inseert/overtype mode to be established, as is done in PipeDream.
If A4 is set then an attempt to move outside the limits of the buffer will cause an exit with A = RC_WRAP, and the key which caused the wrapping will be lost.
A5 is set to select single line lock mode. This sets up a horizontal
window of length L and will scroll the input buffer, if necessary, within
this window. This feature is useful if you have a limited space to display
the input line, but may need a long input string.
The following example uses a locked line width of 15 characters. When <ENTER> is pressed the full input line is displayed. When the buffer is nearly full, try suspending GN_Sip, eg. by pressing the Square key twice, and you will see a slight flicker as GN_Sip re-displays and scrolls the line.
include "#stdio.def" ; get standard I/O definitions include "#errors.def" ; get error code definitions defc init = 32 ; mode for GN_Sip (single line lock) ; assume that on entry IY points to 40 bytes of free space ; code starts here...
.main ld a, 12 call_oz(OS_Out) ; clear screen call fetch ; fetch the line ; may need to check errors here... push iy pop hl ; HL points at start of input buffer call_oz(GN_Nln) ; output a newline call_oz(GN_Sop) ; display input buffer call_oz(GN_Nln) ; terminate with another newline ret
; actual input line subroutine
.fetch ld a, init ; initial mode of GN_Sip push iy pop de ; DE points at input buffer ld b, 30 ; max. buffer size ld c, 0 ; cursor position at beginning .sip ld hl, pos ; input prompt text call_oz(GN_Sop) ; to standard output ld l, 15 ; max. line width call_oz(GN_Sip) ; edit line buffer... ret nc ; return if no errors cp RC_SUSP ; check for suspension ret nz ; return if some other error ld b, 30 ; reset buffer length ld a, init | 1 ; buffer contains data jr sip ; re-enter GN_Sip
; define constant string
.pos defm 1 & "3@" & 32 & 35 ; cursor at (0,3) defm "Input: " ; prompt defb 0 ; null-terminator
|File Input / Output||Input and the keyboard decoder||Filters|