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