;
; *****************************************************************************
;
;				 H O T K E Y S
;				   v. 1.01-U
;			      (c) 1988 J.W. Olsen
;		                  15 May 1988
;
;	   May be used for noncommercial purposes without permission
; 			Inquire for all other purposes
; If given or sold with any other product, the price for which is more than $10
; inclusive of all charges, including but not limited to "shipping & handling,"
; such gift or sale is considered commercial use for purposes of the above.
;
; *****************************************************************************
;
; Allows redefintion of arrow and numeric-keypad keys. Two sets of redefinition
; are permitted in a single, assembled HK program. A run-time, command-line
; toggle key determines which redefinition will be activated. You may freely
; switch between the two configurations at any time. 

; HK simply pokes the copy of CP/M in memory. Thus, it's transitory and won't
; affect disks. When you turn off the computer or press the reset button, the
; effects of HK are gone until you run the program again.
;
; HK is run by typing its name, followed by a "toggle" key of your choice, as
; in "HK W" (e.g., I use "HK B" to run my BBS, "HK W" for word processing with
; with  WordStar or VDE.) You may want to set one configuration for "vanilla" 
; CP/M--info to do so is provided.
;
; This version works on CP/M Kaypros with U-ROMs. Those with other CP/M Kaypros
; should use HKxxx.ASM, distributed with this file. For other machines, see 
; the HKxxx.INF file. The "non-U-ROM" version employs some checks when invoked 
; not contained herein due to some elusiveness in the logic (maybe illogic) of 
; the U-ROM. But try it. If it works once on your U-ROM Kaypro, it can be 
; expected to work consistently.
;
; You can reassign one character for each of the normal arrow keys above your
; main keyboard. And you can assign strings up to EIGHTY characters for each of
; your numeric-keypad keys--up to a maximum of 225 total characters for all
; 14 numeric keys together.
;
; Run your favorite assembler/linker. ASM and MLOAD work fine. 
;
; After assembling, test by first invoking your newly configured "period" key 
; on the numeric keypad. If that works, HK will work on your machine. If it 
; misbehaves, you may have a U-ROM version sufficiently different from mine 
; that some recoding may be needed. If so, outline your experiences and I'll 
; try to help. If ANYTHING doesn't seem to work correctly, RESET YOUR MACHINE
; BEFORE USING AGAIN. An unintended area in high memory will have been
; overwritten, and could consistently or unpredictably produce weird results.
;
; NOTE: Only the arrow keys above the main keyboard and the numeric keypad
; keys are redefined. All other keys are unaffected, including the number keys
; on the main keypad.
;
; This was a quickie effort to meet a special need, but performs its function
; fully. Experienced 8080 programmers (of which it will be readily apparent
; I'm not one) undoubtedly will be able to reduce the code further and suggest
; further improvements. That would be welcomed. But if in the meantime you
; too find HK useful, enjoy. Please direct comments, or check for any updates
; on my BBS.
; 
;   	Jerry Olsen
;	Sysop, The Advocate/NOWAR RCP/M
;	312.939.4411
;	24 hrs., 300/1200/2400, 8/n/1
; 
; ----- Preliminaries
; 
;	ASEG			; Comment out if assembling with other than M80
;
NO	EQU	0		; Leave these alone
YES	EQU	NOT NO
;
; ----- User-settable equates
;
TOGGLE1 EQU	'B'		; Specify two characters as command-line
TOGGLE2	EQU	'W'		; toggles for configurations you desire.
				; A toggle may be any single letter, number
				; or punctuation. LOWER CASE letters are NOT
				; allowed. You might want to set one to "V"
				; for "vanilla" CP/M settings.
; *** You also need to set up the arrays toward the end of this file ***
;
; ----- System-specific equates (change ONLY if these prove incorrect for
;       your system after testing)
;
AROVEC	EQU	0F143H		; Location of first byte of arrow keys
				; are stored.
NUMVEC	EQU	0F060H		; Similarly, for numeric keys
NUMLEN	EQU	0F044H		; Lengths of each numeric-keypad definition
				; are poked beginning here, skipping one byte
				; between addresses to poke (i.e., F044H,
				; F046H, etc.)
MAXLEN	EQU	225		; Max. # of all numeric-keypad reconfiguration
				; strings combined as allowed by U-ROM Kaypros
;
; ----- Miscellaneous equates (leave alone)
;
BDOS	EQU	5		; BDOS entry point
PRINTF	EQU	9		; Print-a-string function
BUFF	EQU	80H		; Command line buffer
CR	EQU	0DH		; Carriage return
LF	EQU	0AH		; Linefeed
SPACE	EQU	20H		; Ordinary blank space
NULL	EQU	0		; May be used in arrays if desired
;
; ----- Begin
;
	ORG	100H		; Normal TPA entry point
;
	LXI	D,SIGNON	; Point to sign-on msg
	MVI	C,PRINTF	; Tell BDOS we want to print a string
	CALL	BDOS		; and do it
;
;	LXI	H,BUFF		; Get address of command-line buffer
	MOV	A,M		; Get buffer length
	CPI	NULL		; Is it a null?
	JZ	ERROR1		; Yep, so print error msg & quit
;
	MOV	B,A		; Nope, so save command-line length
	LXI	H,BUFF+1	; Point to first char of command line
GETIT:	DCR	B		; Decrement our length counter
	MVI	A,NULL		; Prepare for comparison
	CMP	B		; Is counter now a null?
	JZ	ERROR1		; Yep, so print error msg & quit
	MOV	A,M		; Nope, so fetch char
	INX	H		; & increment pointer
	CPI	SPACE		; Is it a space?
	JZ	GETIT		; Yep, try again
;
	CPI	TOGGLE1		; Is it first legal toggle?
	JZ	SAVEIT		; Yep, so skip loop
	CPI	TOGGLE2		; Is it second legal toggle?
	JZ	SAVEIT		; Yep
	JMP	ERROR1		; Nope,so print error msg & quit
;
SAVEIT:	STA	OPTION		; Save it for later
;
	LXI	D,AROVEC	; Point to first location to poke with
				; arrow configuration
	LDA	OPTION		; Get user choice back
	CPI	TOGGLE1		; Was it first choice?
	JNZ	ALT		; Nope, so skip to it
	LXI	H,ARO1		; Yep, so point to first set-up
	JMP	DOIT		; and begin
ALT:	LXI	H,ARO2		; Point to second set-up
;
DOIT:	MVI	B,4		; Counter for # of arrow keys
DOIT2:	MOV	A,M		; Fetch first byte
	STAX	D		; and poke it
	DCR	B		; See if counter is done
	MVI	A,NULL
	CMP	B		; If done...
	JZ	DOIT3		; go deal with numeric-keypad configurations
;
	INX	D		; If not done 
	INX	H		; increment both pointers
	JMP	DOIT2		; and keep truckin' 
;
DOIT3:	LXI	D,NUMVEC	; Point to first location to poke with
				; numeric keypad strings
	LDA	OPTION		; Get choice back
	CPI	TOGGLE1		; First choice?
	JNZ	ALT2		; Nope
	LXI	H,NUM1		; Yep, so point to its numeric configs
	JMP	DOIT4
ALT2:	LXI	H,NUM2		; Point to 2nd numeric configs
;
DOIT4:	MVI	B,NULL		; We'll use (B) as a counter
DOIT5:	MOV	A,M		; Fetch first byte
	CPI	0FFH		; Reached our end-of-strings indicator?
	JZ	DOIT6		; Yep
	STAX	D		; Nope, so poke it
	INR	B		; Count # of bytes poked,
	INX	D		; increment both pointers,
	INX	H		; 
	JMP	DOIT5		; & continue
;
DOIT6:	MVI	A,0FFH		; The U-ROM expects 2 0FFh chars after our
	STAX	D		; string
	INX	D
	STAX	D
;
	MOV	A,B		; Prepare to save counter
	STA	COUNT		; & do it
;
	LXI	D,NUMLEN	; Point to first location to poke with LENGTH
				; of each numeric-keypad definition
	LDA	OPTION		; Get choice back
	CPI	TOGGLE1		; First choice?
	JNZ	ALT3		; Nope
	LXI	H,NLEN1		; Yep, so point to 1st set of string lengths
	JMP	DOIT7
ALT3:	LXI	H,NLEN2		; Point to 2nd set
;
DOIT7:	MVI	B,NULL		; Again, our counter
;
	MOV	A,M		; Fetch first byte
	PUSH	A		; Save it for a moment
	ADD	B		; Our # of bytes counter
	MOV	B,A		; Save byte counter
	POP	A		; Get our character back again
	MOV	C,A		; Start an offset value CP/M needs
	STAX	D		; Poke it
	INX	D		; Increment both of our pointers
	INX	H		; 
	LDAX	D		; Grab following byte
	ADD	C		; Add it to CP/M's offset value 
	MOV	C,A		; & save it
	INX	D		; Bump (DE) once again
;
; Repeat for succeeding bytes, with variations on the theme
;
DOIT8:	MOV	A,M		; Fetch next byte
	CPI	0FFH		; Reached our end-of-strings indicator?
	JZ	DOIT9		; Yep
	PUSH	A		; Nope, so deal with our byte counter 
	ADD	B
	MOV	B,A
	POP	A
	STAX	D		; Poke our NLEN byte
	PUSH	A		; Save again
	MOV	A,C		; Get CP/M's current running offset
	INX	D		; Increment our pointer
	STAX	D		; & poke CP/M's offset now
	POP	A		; OK, get value back
	ADD	C		; & add it to the running CP/M offset
	MOV	C,A		; ... which needs to be saved again
	INX	H		; Now increment (HL) pointer
	INX	D		; & bump (DE) again
	JMP	DOIT8		; ... & finally, time to fetch next
;
DOIT9:	LDA	COUNT		; Get our 1st counter back
	CMP	B	 	; Is it the same?
	JNZ	ERROR2		; Nope, so tell 'em & quit
	MVI	A,MAXLEN	; Max. # of bytes allowed for all numeric-
				; keypad reconfigs allowed by U-ROM Kaypros
	CMP	B		; Too many bytes? 
	JC	ERROR3		; Yep, so tell 'em & quit
	LXI	D,OKMSG		; Otherwise, point to "all's OK" sign-off msg
				; and...
;
EXIT:	MVI	C,PRINTF	; Tell BDOS to print a string
	CALL	BDOS		; & do it
	RET			; then quit
;	
; ----- Subroutine to print error msg if invalid command-line toggle
;
ERROR1:	LXI	D,ERR1		; Point to error msg
	JMP	EXIT		; Go print it & quit
;
; ----- Exit routines if assembly-time error detected
;
ERROR2:	LXI	D,ERR2		; Point to error msg
	JMP	EXIT		; Go print & exit
;
ERROR3:	LXI	D,ERR3		; Point to error msg and...
	JMP	EXIT		; Go print & exit
;
; ----- Storage Area
;
SIGNON:	DB	CR,LF,'HOTKEYS v. 1.00U, (c) 1988, J.W. Olsen',CR,LF,'$'
ERR1:	DB	CR,LF,'Syntax: HK ',TOGGLE1,' or HK ',TOGGLE2,CR,LF,'$'
ERR2	DB	CR,LF,7,'ASSEMBLY-TIME ERROR: For the selected option,'
	DB	CR,LF,'number of bytes for "NUM" and "NLEN" don''t match'
	DB	CR,LF,'$'
ERR3:	DB	CR,LF,7,'ASSEMBLY-TIME ERROR: For the selected option,'
	DB	CR,LF,'combined length of numeric-keypad definitions too long'
	DB	CR,LF,'$'
OKMSG:	DB	'"'	; Printing of exit msg begins here, continues thru...
OPTION: DS	1	; User choice (filled when TOGGLE1 or TOGGLE2 selected)
OKMSG2:	DB	'" configuration INSTALLED',CR,LF
	DB	'$'	; ...end of exit msg (used only if HK is successful)
COUNT:	DS	1	; Will be filled with # of numeric-keypad bytes poked
;
; Enter your 1-character preferences for each arrow key below. (For nonprintable
; characters, which you'll almost sure want, use hex. For others, use either hex
; or alphanumeric. Alphanumeric characters may be placed within SINGLE quote
; marks, as in: DB	'A'.)
;
; FOR TOGGLE1
;
ARO1:	DB	05H	; Value for UP arrow key
	DB	18H	; DOWN arrow
	DB	13H	; LEFT arrow
	DB	04H	; RIGHT arrow
	DB	0FFH	; Don't alter this
;
; FOR TOGGLE2
;
ARO2:	DB	05H	; UP arrow
	DB	18H	; DOWN arrow
	DB	13H	; LEFT arrow
	DB	04H	; RIGHT arrow
	DB	0FFH	; Don't alter this
;
; Enter your strings for each numeric-keypad character below. For alphanumeric
; redefinitions, place between single quote marks. For control characters,
; enter hex values. They may be combined, if separated by commas. Example:
; 'this is a sample of alphanumeric characters',0DH,0AH,'separated by hex'
; The MAXIMUM length of EACH string is 80 characters. The maximum TOTAL length
; of ALL strings for "NUM1" strings is 225 characters. Same for "NUM2" strings.
; Enter each string on the line following the comment designating the key that
; it will redefine.
;
; FOR TOGGLE1
;
; "0" key on numeric keypad:
NUM1:	DB	'0'
; "1":
	DB	'1'
; "2":
	DB	'2'
; "3":
	DB	'3'
; "4":
	DB	'4'
; "5":
	DB	'5'
; "6":
	DB	'6'
; "7":	
	DB	'7'
; "8"
	DB	'8'
; "9":
	DB	'9'
; Hyphen key on numeric keypad:
	DB	'-'
; Comma:
	DB	','
; Enter key:
	DB	0DH
; Period:
	DB	'.'
; Don't alter next line
	DB	0FFH
;
; FOR TOGGLE2
;
; "0" key on numeric keypad:
NUM2:	DB	'0'
; "1":
	DB	'1'
; "2":
	DB	'2'
; "3":
	DB	'3'
; "4":
	DB	'4'
; "5":
	DB	'5'
; "6":
	DB	'6'
; "7":	
	DB	'7'
; "8"
	DB	'8'
; "9":
	DB	'9'
; Hyphen key on numeric keypad:
	DB	'-'
; Comma:
	DB	','
; Enter key:
	DB	0DH
; Period:
	DB	'.'
; Don't alter next line
	DB	0FFH
;
; Enter the LENGTH of each "NUM1" string above, in HEX. Be sure the total
; doesn't exceed 225 bytes.
;
; FOR TOGGLE1:
;
NLEN1:	DB	01H	; For 0 key
	DB	01H	; For 1 key
	DB	01H	; For 2 key
	DB	01H	; For 3 key
	DB	01H	; For 4 key
	DB	01H	; For 5 key
	DB	01H	; For 6 key
	DB	01H	; For 7 key
	DB	01H	; For 8 key
	DB	01H	; For 9 key
	DB	01H	; For hyphen
	DB	01H	; For comma 
	DB	01H	; For enter 
	DB	01H	; For period 
	DB	0FFH	; Don't alter this
;
; FOR TOGGLE2:
;
NLEN2:	DB	01H	; For 0 key
	DB	01H	; For 1 key
	DB	01H	; For 2 key
	DB	01H	; For 3 key
	DB	01H	; For 4 key
	DB	01H	; For 5 key
	DB	01H	; For 6 key
	DB	01H	; For 7 key
	DB	01H	; For 8 key
	DB	01H	; For 9 key
	DB	01H	; For hyphen
	DB	01H	; For comma 
	DB	01H	; For enter 
	DB	01H	; For period 
	DB	0FFH	; Don't alter this
;
; ----- That's all, folks
;
	END
