OBJNAM KBDTST.LIT ; Created 18-Dec-85, Last modified 11-Jan-86
; by Irv Bromberg, Medic/OS Consultants, 78 Wildginger Way, Toronto,
; Ontario, CANADA, M3H 5X1
RADIX 10
VEDIT=19
VMINOR=1
VMAJOR=3
VSUB=0

IF EQ,1

Under AMOS/L 1.3 KBDTST.LIT 3.1(19) size=732 bytes, hash=413-467-020-176.

Syntax: KBDTST {IMI} {ILC} {DAT} {XLT} {NFK}

Terminal keyboard input/Terminal Driver Input Routine test program. When
no mnemonics are specified a completely data transparent test will be
done setting ECS and DAT and temporarily changing the user's terminal
driver to PSEUDO so that all input characters (single and
multi-character sequences) are passed through unmodified.  The original
terminal driver is automatically restored when KBDTST ends.

The mnemonics shown may be used to set the desired terminal status for
the test (ECS is always set).  Any terminal status mnemonic that is
omitted is cleared for the test.  When DAT is specified prompts user for
exit character otherwise CTRL-C will abort the test. A comma may
optionally be used as separator between terminal status mnemonics. When
a terminal status mode is specified  KBDTST tests the user's current
terminal driver and multi-character sequences (special function keys,
editing keys) may be modified by the terminal driver input processing
routine before they reach KBDTST.

Each character received by KBDTST is displayed in binary, octal,
decimal, hexadecimal and ASCII until the exit character is received (or
CTRL-C abort when DAT is not on).

Examples:
 .kbdtst	; data transparent keyboard test with PSEUDO.TDV
 .kbdtst ilc	; line input mode, lowercase & function keys enabled
 .kbdtst ilc nfk  ; as above but No Function Key translation
 .kbdtst dat xlt  ; 8-bit terminal driver input routine test with user's
		  ; current terminal driver, translate function/editing
		  ; keys to parity-set bytes
 .kbdtst dat nfk  ; 8-bit TDV input test but No Function Key translation
 .kbdtst imi	; image-mode terminal driver input routine test, optionally
		; translate function/editing keys to VUE control codes

Triple ^C can also be used to abort KBDTST in DAT mode, in case you
forget which exit character you specified.

Note that when the NFK bit is set your Terminal Driver input routine can
do to nothing to prevent multi-character keys from passing through
character by character processing since all attempts to invoke the
multi-character processing feature of TRMSER are ignored while NFK is set.

When testing in line input mode (ILC on and both IMI and DAT off) be
aware that TRMSER (and any system input line editor you may have
installed) will process all input before it reaches KBDTST.  This will
be most noticeable for control codes which will probably not be passed
through in line input mode (careful, ^S will freeze the output, ^Q will
resume it).

Edit history:
1.7(13) 16-Dec-85  Corrected bug causing HEX to be output in DEC if OCTPCH on
1.8(14)	17-Dec-85  Added BINARY to output display
1.9(15) 17-Dec-85  Build output line in memory and output in one TTYL call,
		   replace KBD calls with TIN (CMD file processing not needed)
2.0(16) 17-Dec-85  Deleted KBDTST.TDV from in-line code, use monitor's PSEUDO
		   terminal driver instead (safer in case RESET/MURDER used).
2.1(17) 18-Dec-85  Deleted initial clear screen TCRT call.
3.0(18)	18-Dec-85  Major re-write, added Terminal Driver Input Routine testing
		   with ability to specify Terminal Status Mode bits.
3.1(19) 11-Jan-86  backup for RES:/MEM: TDVNAM display only if "TDV" there
ENDC

SEARCH SYS
SEARCH SYSSYM
SEARCH TRM

JCB	=A0
RD50	=A1
Buffer	=A2
Worksp	=A4
TCB	=A5
TDV	=A6
Atemp	=A6

BitNum	=D0
Flags	=D0
Char	=D1
Mnem	=D1
CrtCmd	=D1
ExChar	=D2
AbtCnt	=D3	; ^C abort counter, abort when >2
Dtemp	=D6

ETX=3
CR=13
SPACE=32
XLT=^O40	; define XLT & NFK here in case assembled under AMOS/L
NFK=^O100	; versions before defined (1.1 & 1.3 respectively)
J.DEC=J.HEX*256

	PHDR	-1,0,PH$REE!PH$REU 

	PUSH	#50			; get 50-byte line workspace
	PUSH
	GETMEM	@SP
	BEQ	10$
	TYPECR	<?Out of memory>
	EXIT
10$:	POP	Worksp
	POP

	CLR	AbtCnt			; pre-clear
	MOV	JOBCUR,JCB		; get user's TCB
	MOV	JOBTRM(JCB),TCB
	PUSH	T.TDV(TCB)		; save user's Terminal Driver

TSTS:	MOVW	#ECS,Flags		; pre-set ECS default
	LIN				; any parameters?
	BNE	PackIt			; yes, go process them
; No parameters, change user's terminal driver to PSEUDO and set DAT mode
; so that the test will be guaranteed completely 8-bit data transparent
; for all input characters or sequences.
	ORW	#DAT,Flags		; set DAT mode too
	LEA	TDV,TRMTDC		; index the terminal driver chain
	MOV	@TDV,TDV		; first driver is PSEUDO.TDV
	ADD	#8,TDV			; bypass link and name longwords
	MOV	TDV,T.TDV(TCB)		; set user TDV=PSEUDO
	TYPE	<Keyboard test (8-bit data transparent)>
	BR	SetMode
	
PackIt:	MOV	Worksp,RD50		; pack into workspace
	PACK				; pack first specified mnemonic
	MOVW	@Worksp,Dtemp		; get word for table lookup
	LEA	Atemp,Table		; index T.STS flags table
10$:	MOVW	(Atemp)+,Mnem		; get next packed mnemonic
	BEQ	Syntax			; illegal mnemonic
	CMPW	Mnem,Dtemp		; match here?
	BNE	20$
	ORW	@Atemp,Flags		; set that bit in Flags
	BYP
	CMPB	@Buffer,#',		; allow comma separators
	BNE	15$
	INC	Buffer
	BYP				; skip spaces/tabs
15$:	LIN				; end of line yet?
	BNE	PackIt			; no, go back for more
	TYPE	<Terminal Driver Input test>
	BR	SetMode
20$:	ADD	#2,Atemp		; point to next entry
	BR	10$			; search for more
	
Syntax:	TYPECR	<?Syntax:  KBDTST {IMI} {ILC} {DAT} {XLT} {NFK}>
	EXIT

SetMode:ORW	Flags,T.STS(TCB)	; set specified T.STS mode
	MOV	#-1,ExChar		; special signal for no exit character
	ANDW	#DAT,Flags		; was DAT specified?
	BEQ	NoExit
	CRLF
	TYPE	<Enter exit character: >
	TIN				; input exit character
	MOV	Char,ExChar		; save exit character
	BR	SavTYP
NoExit:	TYPECR	< - hit CTRLC to abort>
SavTYP:	PUSHW	JOBTYP(JCB)		; save J.HEX and J.DEC status
	MOVB	#13+128,Char		; cursor return
	TTY
	; overwrite prompt with header:
	TYPE	<-BINARY-  OCT  DEC  HEX  ASCII  (Terminal driver = >

TDVNAM:	MOV	T.TDV(TCB),RD50		; index the terminal driver
	MOV	MEMBAS,Atemp		; is driver in user partition?
	CMP	RD50,Atemp
	BLO	10$
	TYPE	<MEM:>			; yes, tell user that it is
	BR	20$
10$:	MOV	SYSBAS,Atemp		; is driver in SYSTEM memory?
	CMP	RD50,Atemp
	BLO	30$
	TYPE	<RES:>
20$:	CMPW	-2(RD50),#[TDV]		; if it's a module, with .TDV
	BNE	30$			; extension then back up two more
	SUB	#2,RD50
30$:	SUB	#4,RD50			; back up to terminal driver name
	MOV	Worksp,Buffer
	UNPACK			; unpack & display name pointed to by A1
	UNPACK
Strip:	CMPB	-(Buffer),#SPACE	; strip trailing spaces
	BNE	10$
	CLRB	@Buffer
	BR	Strip
10$:	INC	Buffer			; compensate for last pre-decrement
	MOVB	#'),(Buffer)+		; ) CR-LF-NULL to end
	MOVB	#CR,(Buffer)+
	CLRB	@Buffer
	TTYL	@Worksp

	; the exit character will always be the first one displayed
	MOV	ExChar,Char		; restore character for display
	BMI	Wait			; none defined, wait for input
Show:	MOV	Worksp,Buffer		; point to start of workspace
	MOV	#8-1,BitNum		; set pre-decremented bit# counter
TstBit:	BTST	BitNum,Char		; test the next bit
	BNE	One
Zero:	MOVB	#'0,(Buffer)+		; output a "0" to workspace if 0
	BR	NxtBit
One:	MOVB	#'1,(Buffer)+		; else output a "1" to workspace
NxtBit:	DBF	BitNum,TstBit		; loop until done
	MOVB	#SPACE,(Buffer)+		; output a trailing space
	ANDW	#^C<J.DEC!J.HEX>,JOBTYP(JCB)	; turn off DEC/HEX bits
	OCVT	3,OT$MEM!OT$LSP!OT$ZER!OT$TSP	; output in octal
	DCVT	3,OT$LSP!OT$MEM!OT$TSP!OT$ZER	; output in decimal
	ORW	#J.HEX,JOBTYP(JCB)
	OCVT	2,OT$MEM!OT$LSP!OT$TSP	; output in hex
	MOVB	#SPACE,(Buffer)+
	MOVB	#SPACE,(Buffer)+
	MOVB	#SPACE,(Buffer)+
	ANDB	#127,Char		; strip parity bit
	CMPB	Char,#SPACE		; ?control code
	BHIS	Normal
	MOVB	#'^,(Buffer)+
	ADDB	#64,Char		; make printable
	BR	ASC
Normal:	MOVB	#SPACE,(Buffer)+
ASC:	MOVB	Char,(Buffer)+		; display ASCII value
	MOVB	#CR,(Buffer)+		; terminate with CR-LF-NULL
	CLRB	@Buffer
	TTYL	@Worksp			; output the assembled buffer
	MOVW	T.STS(TCB),Dtemp	; IMI or DAT set?
	ANDW	#IMI!DAT,Dtemp
	BEQ	Wait			; no, do line input char wait
	TIN				; yes, efficient wait for next char
	BR	ChkChr			; and go process it

Wait:	; Special loop to wait for an input character to arrive in line
	; input mode without wasting a lot of CPU time, then grab it
	; from input buffer (therefore need not wait for CR to be hit):
	TST	T.ICC(TCB)		; any input yet?
	BNE	GetChr
	TSTB	JOBSTS(JCB)		; ^C abort pending?
	JMI	Exit
	SLEEP	#1000			; no, wait 0.1 s
	BR	Wait
GetChr:	TTYIN				; yes, get the input

ChkChr:	TSTB	JOBSTS(JCB)		; abort if ^C pending (not DAT)
	JMI	Exit
	MOVB	Char,Dtemp		; check for ^C
	ANDB	#^H7F,Dtemp		; strip parity
	CMPB	Char,#ETX		; is it ^C?
	BNE	10$
	INCB	AbtCnt			; increment abort counter
	CMPB	AbtCnt,#3		; >2 ^C's in a row?
	BLO	20$			; no, keep going
	TYPE	<Triple ^C in a row - >
	BR	Exit
10$:	CLR	AbtCnt			; clear abort counter, wasn't ^C
20$:	TST	ExChar			; exit character defined?
	JMI	Show			; no, just show the char
	CMPB	Char,ExChar		; exit?
	JNE	Show			; no, show it
	
Exit:	POPW	JOBTYP(JCB)
	POP	T.TDV(TCB)		; restore user's terminal driver
	ANDW	#^C<J.CCC>,JOBSTS(JCB)	; clear pending ^C if any
	TYPECR	<KBDTST exit>
	EXIT	; Note: allow the monitor to restore normal Terminal Status

Table:	WORD	[IMI],IMI	; OIP LCL ECS intentionally left out
	WORD	[ILC],ILC	; OIP is not concerned with input
	WORD	[DAT],DAT	; ECS is always set
	WORD	[XLT],XLT	; LCL has no further effect if ECS set
	WORD	[NFK],NFK
	WORD	0
	EVEN

	END