;
;program FASTKEYS for the OSBORNE Executive by  W. vanRiper
;tested with ROM version 1.0
;entered into public domain 12/1/84 with no restrictions on non-profit use
;
;Loads function keys definitions from bank 8, lets the user alter them, and
;then replaces them.  The key set is updated after every change, and the 
;program is exited via a CTRL C from the first prompt.  There is currently 
;no provision for changing the arrow keys or entering control or hex literals
;from the console, thought the program allows a blank after the key 
;definition.  Unchanged key definitions are left alone.
;
;The program loads itself above the bank 8 window (ie: above 4000H), which
;also puts it above the running location of the MBASIC interpreter and most
;other applications.  The program can be called by MBASIC by changing the
;ORG and deleting the loader code, or included in another program such as
;VDO-EX.
;
;Buffer space is used in BIOS which starts at about FAE3.  George Peace
;used the end of this area to store some code associated with his EXCLOCK
;utility, which area I have tried to avoid.  Function key length is about 20
;bytes per key, which shouldn't conflict, but if you change the length
;keep this in mind.
;
;This code is somewhat kludgy but is a quick fix.  I can be reached as
;	W. vanRiper, 91 Park St., Newton Corner, MA., 02158 
;
;
BDOS 	EQU	005
CR	EQU	0DH
LF	EQU	0AH
BANK8	EQU	10000000B	;mask to fade in bank 8
OFFSET	EQU	8000H		;anywhere above 4000H
KEYSTRT	EQU	2155H		;where function key table starts in bank 8
				; for 1.0 ROM
;
	ORG	100H
;
;***************************************************************
;	this loads the actual working code above the 
;	bank 8 window (ie: above 4000H)
;
	LXI	H,START1	;where to start
	LXI	D,OFFSET	;where to
	LXI	B,CODLEN	;how much to move
	DB	0EDH,0B0H	;Z80 LDIR instruction
;
JUMP	JMP	START3		;jump to it
;
;	end of loader code
;***************************************************************
;
START1	EQU	$
;
START3	EQU	$+OFFSET-START1
	LXI	H,KEYSTRT		;keys start here in bank 8
	SHLD	KEYMARK			;temp storage
;
START	EQU	$+OFFSET-START1
	CALL	CLEAR			;clear screen
	CALL	LOADKEY			;get keys from bank 8
	CALL	SHOWKEY			;...and display them
	JMP	NEWKEY			;get console input (=changes)
;
START2	EQU	$+OFFSET-START1
	CALL	STICKIT			;take input and stick in temp buffer
	CALL	PUTBACK			;from buffer to table in bank 1
	CALL	MOVBACK			;take table and stick it back in bank 8
	JMP	START3			;...and do it all over again
;	
;	********************************************
;		beginning of data storage
;	
KEYMARK	EQU	$+OFFSET-START1
	DS	2
;
BANKTMP	EQU	$+OFFSET-START1
	DS	1
;
HEADER	EQU	$+OFFSET-START1
	DB	CR,LF,LF,LF,'The function keys are: ',CR,LF,LF,'$'
;
PROMPT1	EQU	$+OFFSET-START1
	DB	0DH,0AH,'Enter function key # to change: ','$'
;
PROMPT2	EQU	$+OFFSET-START1
	DB	'Enter new function key definition:  ','$'
;
BUFFER  EQU	0FAE3H
;
CLNBUFF	EQU	$+OFFSET-START1
	DB	'                         ','$'
BLANK	EQU	$+OFFSET-START1
	DB	' = ','$'
INDEX0	EQU	$+OFFSET-START1
	DB	'    0: ','$'
INDEX1	EQU	$+OFFSET-START1
	DB	'    1: ','$'
INDEX2	EQU	$+OFFSET-START1
	DB	'    2: ','$'
INDEX3	EQU	$+OFFSET-START1
	DB	'    3: ','$'
INDEX4	EQU	$+OFFSET-START1
	DB	'    4: ','$'
INDEX5	EQU	$+OFFSET-START1
	DB	'    5: ','$'
INDEX6	EQU	$+OFFSET-START1
	DB	'    6: ','$'
INDEX7	EQU	$+OFFSET-START1
	DB	'    7: ','$'
INDEX8	EQU	$+OFFSET-START1
	DB	'    8: ','$'
INDEX9	EQU	$+OFFSET-START1
	DB	'    9: ','$'		
;
;  Here are the function key definitions.
;

TABLE	EQU	$+OFFSET-START1
;
FK0	EQU	$+OFFSET-START1
	DB	'                       '   		;KEY #0
	DB	'$'
FK1	EQU	FK0+24
	DB	'                       '   		;KEY #1
	DB	'$'
FK2	EQU	FK0+48
       	DB	'                       '   		;KEY #2
	DB	'$'
FK3	EQU	FK0+72
	DB	'                       '   		;KEY #3
	DB	'$'
FK4	EQU	FK0+96
	DB	'                       '   		;KEY #4
	DB	'$'
FK5	EQU	FK0+120
	DB	'                       '		;KEY #5
	DB	'$'
FK6	EQU	FK0+144
	DB	'                       '		;KEY #6
	DB	'$'
FK7	EQU	FK0+168
	DB	'                        '		;KEY #7
	DB	'$'
FK8	EQU	FK0+193
	DB	'                        '		;KEY #8
	DB	'$'
FK9	EQU	FK0+218
	DB	'                        '		;KEY #9
	DB	'$'
;
;  mandatory end of table sequence = arrow key definitions 
;
EOTABLE	EQU	$+OFFSET-START1
	DB	01,0BH,01,0CH,01,0AH,01,08
	DB	0,0,0,0,0,0,0,0,0,0,0,0,'$'
;
;	    end of data storage
;************************************************
;
LOADKEY	EQU	$+OFFSET-START1
	LXI	D,FK0			;loads FN keys from bank8 into table
	CALL	GETKEY	
	LXI	D,FK1
	CALL	GETKEY
	LXI	D,FK2
	CALL	GETKEY
	LXI	D,FK3
	CALL	GETKEY
	LXI	D,FK4
	CALL	GETKEY
	LXI	D,FK5
	CALL	GETKEY
	LXI	D,FK6
	CALL	GETKEY
	LXI	D,FK7
	CALL	GETKEY
	LXI	D,FK8
	CALL	GETKEY
	LXI	D,FK9
	CALL	GETKEY
	RET
;
GETKEY	EQU	$+OFFSET-START1
	IN	0		;get present bank and store it
	STA	BANKTMP
	ORI	BANK8		;fade in bank 8
	OUT	0
;
	LXI	B,0000H
	LHLD	KEYMARK		;get start of fnk definition in bank 8
	MOV	A,M		;get length of fnk definition
	INX	H		;move pointer to first byte of fnk definition
	MOV	C,A     	;# of bytes to move
	DB	0EDH,0B0H	;do it
				;(where to move should be in DE already
	SHLD	KEYMARK		;save pointer to next fnk definition
;
	
	LDA	BANKTMP		;get old bank status
	OUT	0		;...and get back to it
	RET
;
SHOWKEY	EQU	$+OFFSET-START1
	LXI	D,HEADER	;..to pretty up screen display
	MVI	C,9
	CALL	BDOS
;
	LXI	D,INDEX0	;...and some more to make it look nice
	CALL	PRINT
	LXI	H,FK0
	CALL	PRNTKEY
	LXI	D,INDEX1
	CALL	PRINT
	LXI	H,FK1
	CALL	PRNTKEY
	LXI	D,INDEX2
	CALL	PRINT
	LXI	H,FK2
	CALL	PRNTKEY
	LXI	D,INDEX3
	CALL	PRINT
	LXI	H,FK3
	CALL	PRNTKEY
	LXI	D,INDEX4
	CALL	PRINT
	LXI	H,FK4
	CALL	PRNTKEY
	LXI	D,INDEX5
	CALL	PRINT
	LXI	H,FK5
	CALL	PRNTKEY
	LXI	D,INDEX6
	CALL	PRINT
	LXI	H,FK6
	CALL	PRNTKEY
	LXI	D,INDEX7
	CALL	PRINT
	LXI	H,FK7
	CALL	PRNTKEY
	LXI	D,INDEX8
	CALL	PRINT
	LXI	H,FK8
	CALL	PRNTKEY
	LXI	D,INDEX9
	CALL	PRINT
	LXI	H,FK9
	CALL	PRNTKEY
	RET
;
PRNTKEY	EQU	$+OFFSET-START1
	MOV	E,M			;print fnk definition byte by byte
	PUSH	H
	MVI	C,2
	CALL	BDOS
	POP	H
	INX	H
	MOV	A,M			;check for blank at end of fnk def
	CPI	20H
	JNZ	PRNTKEY			;if not then do it again
	PUSH	H
	INX	H
	MOV	A,M			;check for a second space
	CPI	20H
	POP	H
	JNZ	PRNTKEY			;if not two in a row then do it again
	MVI	E,CR			;if two spaces are found then CR,LF
	MVI	C,2
	CALL	BDOS
	MVI	E,LF
	MVI	C,2
	CALL	BDOS
	RET
;
PRINT	EQU	$+OFFSET-START1
	MVI	C,9
	CALL	BDOS
	RET
;
NEWKEY	EQU	$+OFFSET-START1
	LXI	D,PROMPT1		;print the prompt
	MVI	C,9
	CALL	BDOS
;
	MVI	C,1			;get number of key desired
	CALL	BDOS
	CPI	3			;here is the warm boot exit point
	JZ	EXIT
;
	CPI	'0'			;get which FN key to change
	JZ	LOAD0
	CPI	'1'
	JZ	LOAD1
	CPI	'2'
	JZ	LOAD2
	CPI	'3'
	JZ	LOAD3
	CPI	'4'
	JZ	LOAD4
	CPI	'5'
	JZ	LOAD5
	CPI	'6'
	JZ	LOAD6
	CPI	'7'
	JZ	LOAD7
	CPI	'8'
	JZ	LOAD8
	CPI	'9'
	JZ	LOAD9
	JNZ	NEWKEY
;
LOAD0	EQU	$+OFFSET-START1			;points to each key definition
	LXI	H,FK0
	JMP	DOIT
LOAD1	EQU	$+offset-start1
	LXI	H,FK1
	JMP	DOIT
LOAD2	EQU	$+OFFSET-START1
	LXI	H,FK2
	JMP	DOIT
LOAD3	EQU	$+OFFSET-START1
	LXI	H,FK3
	JMP	DOIT
LOAD4	EQU	$+OFFSET-START1
	LXI	H,FK4
	JMP	DOIT
LOAD5	EQU	$+OFFSET-START1
	LXI	H,FK5
	JMP	DOIT
LOAD6	EQU	$+OFFSET-START1
	LXI	H,FK6
	JMP	DOIT
LOAD7	EQU	$+OFFSET-START1
	LXI	H,FK7
	JMP	DOIT
LOAD8	EQU	$+OFFSET-START1
	LXI	H,FK8
	JMP	DOIT
LOAD9	EQU	$+OFFSET-START1
	LXI	H,FK9
	JMP	DOIT
;
DOIT	EQU	$+OFFSET-START1		;prints out FN keys each time
	SHLD	HTEMP
	LXI	D,BLANK
	PUSH	H
	CALL	PRINT
	POP	H
	CALL	PRNTKEY
	LXI	D,PROMPT2
	CALL	PRINT
	JMP	START2
		

STICKIT	EQU	$+OFFSET-START1
	LXI	H,CLNBUFF		;fill buffer area with zeros first
	LXI	D,BUFFER
	LXI	B,25
	DB	0EDH,0B0H
	MVI	A,25			;read console buffer and stick it up
	STA	BUFFER			;  in BIOS free area
	LXI	D,BUFFER
	MVI	C,0AH
	CALL	BDOS
	RET
;
PUTBACK	EQU	$+OFFSET-START1
	LHLD	HTEMP			;find out which fnk (where to go)
	XCHG				;put it in D to set up the LDIR
	LXI	H,BUFFER+2		;where from
	LXI	B,21			;how many bytes
	DB	0EDH,0B0H		;move them...
	RET
	
MOVBACK	EQU	$+OFFSET-START1
	CALL	CLEAR8			;erase old FN keys in bank8
	LXI	H,KEYSTRT		;where the FN keys start in bank8
	SHLD	SPOTIN8			;temp storage for pointer
	MVI	A,0			;initialize FN key size temp storage
	STA	KEYSIZE
;
	LXI	H,FK0			;gets size of key definition and 
	CALL	GETLEN			;  inserts it into bank 8
;
	LXI	H,FK1
	CALL	GETLEN
;
	LXI	H,FK2
	CALL	GETLEN		
;
	LXI	H,FK3
	CALL	GETLEN
;
	LXI	H,FK4
	CALL	GETLEN
;
	LXI	H,FK5
	CALL	GETLEN
;
	LXI	H,FK6
	CALL	GETLEN
;
	LXI	H,FK7
	CALL	GETLEN
;
	LXI	H,FK8
	CALL	GETLEN
;
	LXI	H,FK9
	CALL	GETLEN	
;
;
	CALL	ENDTBL		;inserts arrow key def at end of table in 8
;
	RET
;
GETLEN	EQU	$+OFFSET-START1
	IN	0		;fade in bank 8
	STA	BANKTMP
	ORI	BANK8
	OUT	0
;	
	LXI	B,0000H		;make sure B is zeroed
	SHLD	HTEMP		;store which fnk cause we'll need it again
GET2	EQU	$+OFFSET-START1
	INX	H		;move H along fnk definition
	INR	B		;count then number of characters
	MOV	A,M		;check if it's a blank
	CPI	' '
	JNZ	GET2		;repeat until a blank is found at end of fnk
;
GET3	EQU	$+OFFSET-START1
	PUSH	H		;check for a second blank
	INX	H
	MOV	A,M
	CPI	' '
	POP	H
	JNZ	GET2
GET4	EQU	$+OFFSET-START1
	PUSH	H		;check for a third blank
	INX	H
	INX	H
	MOV	M,A
	CPI	' '
	POP	H
	JNZ	GET2
;
	MOV	A,B		;store fnk length
	INR	A
	STA	KEYSIZE
;
	LHLD	SPOTIN8		;where are we in bank 8?
	MOV	M,A		;write fnk length to bank 8
	XCHG			;DE now has where to move fnk definition
	INX	D		;...which should be 1 past where the length is
	LHLD	HTEMP		;= where fnk definition is in bank 1
	LDA	KEYSIZE
	MOV	C,A		;fnk length = # of bytes to move
	MVI	B,0		;make sure B is cleared
	DB	0EDH,0B0H	;LDIR 
;
	XCHG			;DE had the new spot in bank 8 - now in HL
	SHLD	SPOTIN8		;store it away and return for another
;
;
	LDA	BANKTMP		;...fade out bank 8
	OUT	0
	RET
;
ENDTBL	EQU	$+OFFSET-START1
	IN	0		;fade in bank 8
	STA	BANKTMP
	ORI	BANK8
	OUT 	0
;
	LXI	B,0000H		;just to make sure that it is clear
	MVI	C,0AH		;length of arrow keys
	LHLD	SPOTIN8		;where we currently are in bank 8
	XCHG			;...which is where we're going
	LXI	H,EOTABLE	;this is what's being moved
	DB	0EDH,0B0H	;...BLAMMO...
;
	LDA	BANKTMP		;fade out bank 8
	OUT	0
	RET
;
CLEAR	EQU	$+OFFSET-START1
	MVI	C,2		;clear screen
	MVI	E,26
	CALL	BDOS
	RET
;
CLEAR8	EQU	$+OFFSET-START1
	IN	0		;fade in bank 8
	STA	BANKTMP
	ORI	BANK8
	OUT	0
;
	MVI	B,0c8H		;we're going to print 200 zeros in bank 8 to
	LXI	H,KEYSTRT	; leave room for Geo. Peace's EXCLOCK
;
CLEAR2	EQU	$+OFFSET-START1
	MVI	A,0		;fill the area in bank 8 with zeros
	MOV	M,A
	INX	H
	DCR	B
	MOV	A,B
	CPI	0
	JNZ	CLEAR2
;
	LDA	BANKTMP		;get rid of bank 8
	OUT	0
	RET
;	
EXIT 	EQU	$+OFFSET-START1
	MVI	E,1AH
	MVI	C,2
	CALL	BDOS
	MVI	C,0
	CALL	BDOS
	
KEYSIZE	EQU	$+OFFSET-START1
	DS	1	
SPOTIN8	EQU	$+OFFSET-START1
	DS	2
HTEMP	EQU	$+OFFSET-START1
	DS	2
;
;	end of code to be moved above bank 8 window
;********************************************************
;
;	the following is needed by the loader
;	at the beginning of the program
; 
CODEND	EQU	$
CODLEN	EQU	CODEND-START1	
;
	END
he following is needed by the loader
;	at the beginning 