

;ShoFKeys -- help display line for WordPerfect (uses nth line of display)
;
; 12/5/87 by Davidson Corry
;	     4610 SW Lander
;	     Seattle, WA  98116
;	     (206) 935-0244
;
; This program is released to the public domain by its author.
; Please feel free to use it, distribute it and (especially)
; improve it in any way you feel appropriate.
;
; Money contributions are neither required nor expected.  If you like
; the program and want to express your gratitude, do one of the following:
;
;  1) Write some useful program and upload it to your favorite BBS'es
;  2) Help support your local BBS with money, time or interest
;  3) Teach someone something about programming
;  4) Do the dishes tonight
;  5) Don't tell your lover you've heard that old joke (n) times before
;
; ...or some other public service.  Hope you find it useful.  --Davidson
;

; shift status bits from BIOS call
alt	equ	00001000b
ctrl	equ	00000100b
lshift	equ	00000010b
rshift	equ	00000001b
shifts	equ	lshift or rshift
my_hotshift	equ	ctrl or lshift	;hot key is CTRL-LEFTSHIFT-F
my_hotkey	equ	33

ega	equ	1
not_ega equ	0

;Colors/attributes for display attributes
blink	equ	10000000b
intense equ	00001000b
black	equ	0
blue	equ	1
green	equ	2
cyan	equ	3
red	equ	4
magenta equ	5
brown	equ	6
grey	equ	7
yellow	equ	intense or brown
white	equ	intense or grey
underline	equ	blue

; key/function color selections for a color monitor.  Choose your own.
; Use OR rather than + to turn bits in the attribute byte on.
; Background colors occupy the high nibble: (BACKCOLOR SHL 4)
; Foreground colors occupy the low nibble:   FORECOLOR

;KEY	 EQU	 INTENSE OR RED OR (CYAN SHL 4) ;"hot red" on cyan
;FNX	 EQU	 GREY OR (BLUE SHL 4)		;grey on blue

; key/function "color" selections for a monochrome monitor.
; These will work well on both color monitors (bright blue keynumber, grey words)
; and on monochrome monitors (keynumber underlined and bright, grey words)

key    equ     intense or underline	;"hot blue" on black
fnx    equ     grey			;grey on black

in_keypress	equ	1
inactivated	  equ	  10h

_text	segment byte public 'CODE'
	assume cs:_text, ds:_text, es:_text, ss:_text
	org	100h
	public	begin
begin:
	jmp	initialize

	public	users_ss, users_sp, local_stack

users_ss	dw	0
users_sp	dw	0
		dw	20 dup(0)
local_stack	label	word

	public	activity, adapter_type, old_keypress, last_shiftstate, video_seg

activity	db	inactivated	;comes up "dormant" at load time

adapter_type	db	0

old_keypress	dd	0

last_shiftstate db	0

video_seg	dw	0

	public	new_keypress, not_our_hotkey, which_keyset

new_keypress:
	push	ax			;save AX register, we're going to use it
	in	al,60h			;get scancode of key just pressed
	.if	<cmp	 al,my_hotkey>,e	;it's our base hotkey, see if shiftbits are right
		mov	ah,2
		int	16h		;get shiftbits through BIOS
		and	al,0fh		;shiftbits only
		.if	<cmp	al,my_hotshift>,e	;it's our hotkey!! toggle ACTIVATION bit of ACTIVITY byte
			in	al,61h	;These instructions reset
			mov	ah,al	; the keyboard.  "Forgets" the hotkey
			or	al,80h
			out	61h,al
			mov	al,ah
			jmp	short $+2	;I/O delay for fast AT's
			out	61h,al
			cli		;Disable interrupts and
			mov	al,20h	;reset the int controller
			out	20h,al
			sti		;Allow interrupts
			xor	cs:activity,inactivated ;toggle the ACTIVATED bit in activity flag byte
			pop	ax	;restore the AX register saved at entry to hotkey test
			iret		;and return to caller
		.endif
	.endif
	pop	ax			;restore AX register saved above

not_our_hotkey:

;do nothing if already in the FUNCTION KEY DISPLAY or
;  if the TSR is in the "inactivated" state
	.if	<test	 cs:activity,in_keypress or inactivated>,nz
		jmp	cs:old_keypress
	.endif

which_keyset:
;active and flying, show the function keys appropriate to the shift state
	or	cs:activity,in_keypress	;flag "showing function keys"
	sti
	pushf				;simulate a INT to process the key just pressed/released
	call	cs:old_keypress

	push	ax			;save AX and SI registers, they get local values on shiftstatus
	push	si
	mov	ah,2
	int	16h			;get shiftstatus
	.if	<test  al,alt>,nz	;ALT is on, show ALT function keyset
		mov	al,alt
		mov	si,offset altfunx
	.elseif  <test	al,ctrl>,nz	;ALT not on but CTRL is, CTRL keyset
		mov	al,ctrl
		mov	si,offset ctrlfunx
	.elseif  <test	al,shifts>,nz	;ALT and CTRL not on but a SHIFT key is, show SHIFT keyset
		mov	al,shifts
		mov	si,offset shiftfunx
	.else				;ALT CTRL SHIFT all off, show "NORMAL" keyset
		xor	al,al
		mov	si,offset normfunx
	.endif

	.if	<cmp	al,cs:last_shiftstate>,ne	;display keyset ONLY if this is a change from last shown
		call	show_new_shiftkeys
	.endif

	pop	si			;restore the registers used testing shiftstatus
	pop	ax
	and	cs:activity,not in_keypress	;flag "not displaying keysets"
	iret				;and return to caller

	public	show_new_shiftkeys
show_new_shiftkeys:
		mov	cs:last_shiftstate,al
		cli		;disable interrupts while diddling stack
		mov	cs:users_sp,sp	 ;save old stack
		mov	cs:users_ss,ss
		mov	sp,cs	;establish local stack instead
		mov	ss,sp
		mov	sp,offset local_stack
		sti		;new stack context installed, re-enable interrupts
		push	ds		;save user registers, we need 'em
		push	es
		push	di
		push	cx
		mov	ax,cs		;get local datasegment context
		mov	ds,ax
		mov	cx,24		;assume 25 rows on display, funxkeys shown on #24
		.if	<cmp	adapter_type,ega>,e	;EGA, may be using 43 rows
			mov	ax,0040h
			mov	es,ax
			mov	cl,es:84h	;number of last row in use
		.endif
		mov	ax,80*2 	;number of bytes per display row (byte char + byte attribute)
		mul	cl		;byte*byte = word, doesn't disturb DX
		mov	di,ax		;offset of last row on display
		mov	ax,video_seg	;base of video display memory
		mov	es,ax
		cld
		mov	cx,80
		rep	movsw		;copy keyset databytes directly to video memory
		pop	cx		;restore user's registers
		pop	di
		pop	es
		pop	ds
		cli		;disable interrupts while restoring user's stack context
		mov	ss,cs:users_ss
		mov	sp,cs:users_sp
		sti		;user's stack restored, enable interrupts
	ret


; text (char+attribute) for function-key display lines

	public	normfunx, altfunx, shiftfunx, ctrlfunx

normfunx	db	'1',key
	db	'c',fnx
	db	'a',fnx
	db	'n',fnx
	db	'c',fnx
	db	'e',fnx
	db	'l',fnx
	db	' ',fnx
	db	'2',key
	db	's',fnx
	db	'r',fnx
	db	'c',fnx
	db	'h',fnx
	db	'-',fnx
	db	'>',fnx
	db	' ',fnx
	db	'3',key
	db	' ',fnx
	db	'h',fnx
	db	'e',fnx
	db	'l',fnx
	db	'p',fnx
	db	' ',fnx
	db	' ',fnx
	db	'4',key
	db	'>',fnx
	db	'i',fnx
	db	'n',fnx
	db	'd',fnx
	db	'e',fnx
	db	'n',fnx
	db	't',fnx
	db	'5',key
	db	' ',fnx
	db	'f',fnx
	db	'i',fnx
	db	'l',fnx
	db	'e',fnx
	db	's',fnx
	db	' ',fnx
	db	'6',key
	db	' ',fnx
	db	'b',fnx
	db	'o',fnx
	db	'l',fnx
	db	'd',fnx
	db	' ',fnx
	db	' ',fnx
	db	'7',key
	db	' ',fnx
	db	'e',fnx
	db	'x',fnx
	db	'i',fnx
	db	't',fnx
	db	' ',fnx
	db	' ',fnx
	db	'8',key
	db	'u',fnx
	db	'n',fnx
	db	'd',fnx
	db	'r',fnx
	db	'l',fnx
	db	'i',fnx
	db	'n',fnx
	db	'9',key
	db	'm',fnx
	db	'e',fnx
	db	'r',fnx
	db	'g',fnx
	db	'e',fnx
	db	'R',fnx
	db	' ',fnx
	db	'0',key
	db	' ',fnx
	db	's',fnx
	db	'a',fnx
	db	'v',fnx
	db	'e',fnx
	db	' ',fnx
	db	' ',fnx

shiftfunx	 db	 '1',key
	db	's',fnx
	db	'u',fnx
	db	'p',fnx
	db	'/',fnx
	db	's',fnx
	db	'u',fnx
	db	'b',fnx
	db	'2',key
	db	'<',fnx
	db	'-',fnx
	db	's',fnx
	db	'r',fnx
	db	'c',fnx
	db	'h',fnx
	db	' ',fnx
	db	'3',key
	db	's',fnx
	db	'w',fnx
	db	'i',fnx
	db	't',fnx
	db	'c',fnx
	db	'h',fnx
	db	' ',fnx
	db	'4',key
	db	'>',fnx
	db	'i',fnx
	db	'n',fnx
	db	'd',fnx
	db	'n',fnx
	db	't',fnx
	db	'<',fnx
	db	'5',key
	db	' ',fnx
	db	'd',fnx
	db	'a',fnx
	db	't',fnx
	db	'e',fnx
	db	' ',fnx
	db	' ',fnx
	db	'6',key
	db	'c',fnx
	db	'e',fnx
	db	'n',fnx
	db	't',fnx
	db	'e',fnx
	db	'r',fnx
	db	' ',fnx
	db	'7',key
	db	' ',fnx
	db	'P',fnx
	db	'r',fnx
	db	'i',fnx
	db	'n',fnx
	db	't',fnx
	db	' ',fnx
	db	'8',key
	db	'L',fnx
	db	'i',fnx
	db	'n',fnx
	db	'e',fnx
	db	'F',fnx
	db	'm',fnx
	db	't',fnx
	db	'9',key
	db	'm',fnx
	db	'e',fnx
	db	'r',fnx
	db	'g',fnx
	db	'e',fnx
	db	'E',fnx
	db	' ',fnx
	db	'0',key
	db	'r',fnx
	db	'e',fnx
	db	't',fnx
	db	'r',fnx
	db	'i',fnx
	db	'e',fnx
	db	'v',fnx

ctrlfunx	db	'1',key
	db	' ',fnx
	db	's',fnx
	db	'h',fnx
	db	'e',fnx
	db	'l',fnx
	db	'l',fnx
	db	' ',fnx
	db	'2',key
	db	' ',fnx
	db	's',fnx
	db	'p',fnx
	db	'e',fnx
	db	'l',fnx
	db	'l',fnx
	db	' ',fnx
	db	'3',key
	db	's',fnx
	db	'c',fnx
	db	'r',fnx
	db	'e',fnx
	db	'e',fnx
	db	'n',fnx
	db	' ',fnx
	db	'4',key
	db	' ',fnx
	db	'm',fnx
	db	'o',fnx
	db	'v',fnx
	db	'e',fnx
	db	' ',fnx
	db	' ',fnx
	db	'5',key
	db	'T',fnx
	db	'e',fnx
	db	'x',fnx
	db	't',fnx
	db	' ',fnx
	db	'I',fnx
	db	'O',fnx
	db	'6',key
	db	'T',fnx
	db	'a',fnx
	db	'b',fnx
	db	'A',fnx
	db	'l',fnx
	db	'g',fnx
	db	'n',fnx
	db	'7',key
	db	'f',fnx
	db	'o',fnx
	db	'o',fnx
	db	't',fnx
	db	'n',fnx
	db	'o',fnx
	db	't',fnx
	db	'8',key
	db	'P',fnx
	db	'r',fnx
	db	'n',fnx
	db	't',fnx
	db	'F',fnx
	db	'm',fnx
	db	't',fnx
	db	'9',key
	db	'M',fnx
	db	'r',fnx
	db	'g',fnx
	db	'S',fnx
	db	'o',fnx
	db	'r',fnx
	db	't',fnx
	db	'0',key
	db	'D',fnx
	db	'e',fnx
	db	'f',fnx
	db	'M',fnx
	db	'a',fnx
	db	'c',fnx
	db	'r',fnx

altfunx        db      '1',key
	db	't',fnx
	db	'h',fnx
	db	's',fnx
	db	'a',fnx
	db	'r',fnx
	db	'u',fnx
	db	's',fnx
	db	'2',key
	db	'r',fnx
	db	'e',fnx
	db	'p',fnx
	db	'l',fnx
	db	'a',fnx
	db	'c',fnx
	db	'e',fnx
	db	'3',key
	db	'S',fnx
	db	'h',fnx
	db	'o',fnx
	db	'C',fnx
	db	'o',fnx
	db	'd',fnx
	db	'e',fnx
	db	'4',key
	db	' ',fnx
	db	'b',fnx
	db	'l',fnx
	db	'o',fnx
	db	'c',fnx
	db	'k',fnx
	db	' ',fnx
	db	'5',key
	db	' ',fnx
	db	'm',fnx
	db	'a',fnx
	db	'r',fnx
	db	'k',fnx
	db	' ',fnx
	db	' ',fnx
	db	'6',key
	db	'F',fnx
	db	'l',fnx
	db	'u',fnx
	db	's',fnx
	db	'h',fnx
	db	'R',fnx
	db	't',fnx
	db	'7',key
	db	'M',fnx
	db	't',fnx
	db	'h',fnx
	db	'+',fnx
	db	'C',fnx
	db	'o',fnx
	db	'l',fnx
	db	'8',key
	db	'P',fnx
	db	'a',fnx
	db	'g',fnx
	db	'e',fnx
	db	'F',fnx
	db	'm',fnx
	db	't',fnx
	db	'9',key
	db	'M',fnx
	db	'r',fnx
	db	'g',fnx
	db	'C',fnx
	db	'o',fnx
	db	'd',fnx
	db	'e',fnx
	db	'0',key
	db	' ',fnx
	db	'M',fnx
	db	'a',fnx
	db	'c',fnx
	db	'r',fnx
	db	'o',fnx
	db	' ',fnx


	public	initialize

initialize:
;  Deallocate the copy of the environment loaded with the program.

	mov	ax,word ptr ds:[2ch]	;Address of environment
	mov	es,ax			;In ES register
	mov	ah,49h			;Release allocated memory
	int	21h			;Thru DOS

;
;what kind of video adapter are we using??
;
	mov	adapter_type,not_ega
	mov	ax,0040h		;BIOS data segment
	mov	es,ax
	mov     ah,12h			;see if EGA is present
	mov     bl,10h
	int	10h
	.if  <cmp bl,10h>,ne		;EGA.  Assume it's active.
		mov	ax,0b800h
		mov	adapter_type,ega
	.elseif	<test	word ptr es:63h,40h>,nz	;CGA
		mov	ax,0b800h
	.else				;MDA
		mov	ax,0b000h
	.endif
	mov	video_seg,ax		;base segment for video display memory

;
;grab the "keypress" interrupt (9)
	mov	ax,3509h
	int	21h
	mov	word ptr old_keypress[0],bx
	mov	word ptr old_keypress[2],es
	mov	dx,offset new_keypress
	mov	ax,2509h
	int	21h

;
;say how to use the program
	mov	dx,offset usagemsg
	mov	ah,9
	int	21h

;
;exit retaining resident portion of code
	mov	dx,(offset initialize - offset _text + 15)/16
	mov	ax,3100h
	int	21h

usagemsg	db	'CTRL-LEFTSHIFT-F toggles WordPerfect function key list on last display line$'

_text	ends
	end	begin
