Testing for a keypress on PDP11 platforms ========================================= mdfs.net/Info/Comp/PDP11/ProgTips/KbdTest - J.G.Harston All operating systems and bare-metal systems have a method of waiting for input from the user. However, in some cases you don't want to wait for the user, you just want to see if there is any response from the user, and do something else if there isn't. A very common requirement is testing for a pending keypress is checking for a multiple character sequence, for instance to test between and . Also, a program may want to continously do some processing, but want to allow the user to interupt the process or change the process. As a note, it is often best to test twice to allow for any delays from the keyboard. Some systems provide an API method of testing for a keypress, some don't. This lists different methods for working on different environments. Need to keep close to the API to allow for the operating system redirecting the input from sources other than specific hardware. RT11/RSTS ========= EMT &o241, &E0, 224 - TTY_IN Returns CS - no keypress waiting CC - keypress waiting R0=keypress TTYtest: emt 224 ; TTYIN bcc GETttyOk ; Call twice to allow for delays emt 224 ; TTYIN GETttyOk: rts pc ; CS: no keypress waiting ; CC: keypress waiting ; R0=keypress Bell Unix ========= There is no API call to test for pending input. Instead, you have to peek inside the operating system workspace at the input queue. Before doing this you have to find the input queue, which is in different places in different versions. .tty_Init #if KBD_TICK=0 clrb SV_TICKER ; Reset Escape ticker #else movb #KBD_TICK,SV_TICKER ; Reset Escape ticker #endif #ifndef BSD211 ; Pre-BSD211 we need to find TTYRDY status mov #&8913,SV_KBDFETCH+0 ; Store trap seek()/lseek() clr r0 ; R0=STDIN sec ; Set carry to prepare for ioctrl() support trap 0 ; Indirect system call equw tty_rdctrl ; Point to ioctrl(stdin,TIOCGETP,SV_OSIOCTL) ; This will return: ; CC - Unix7, R0=??? STDIN is a tty ; CS - Unix7, R0=&19 STDIN is not a tty ; CS - Unix6, R0=&00 STDIN unknown call ; CS - Unix5, R0=&00 STDIN unknown call ; bcc tty_InitV7 ; ioctl() exists, STDIN is a tty tst r0 bne tty_InitV7 ; R0<>0, ioctrl() does exist, STD isn't a tty, UnixV7 or BSD2.9 ; ; Unix V5 or V6 clr r2 ; R2=&00, UnixV5 clr r1 ; Prepare result=0 trap 5 ; open() equw IO_TTYmem ; =>"/dev/mem" equw 0 ; 0=read bcs tty_Init1 ; Failed to open, leave offset as zero ; mov #&0030,r1 jsr pc,IO_TTYfetchR1 ; seek(&30), fetch !&30 to R1, eg &AC jsr pc,IO_TTYfetch4 ; PTR=R1+4, seek(&B0), fetch !&B0, eg &554E jsr pc,IO_TTYfetch4 ; PTR=R1+4, seek(&5552), fetch !&5552 bic #&00FF,r1 ; &00xx = v5, offset=0, <>&00xx = v6, offset=&16 beq tty_InitV5 mov #&0016,r1 ; offset for v6 ;add #-4,SV_KBDFETCH+2 ; Step back four bytes ;;asr r2 ; R2=&04, UnixV6 mov #FLG_UNIXV6,r2 ; R2=&02, UnixV6 .tty_InitV5 mov r1,-(sp) ; Save offset .tty_InitLp jsr pc,IO_TTYfetch1 cmp r1,#&65C2 bne tty_InitLp ; Search for ADD #nnnn,R2 instruction jsr pc,IO_TTYfetch1 cmp r1,#&0100 bcs tty_InitLp ; Seach for offset>&00FF add (sp)+,r1 ; Add saved offset from base ;add #18-4,SV_KBDFETCH+2 ; Step forward 18 or 14 bytes ;jsr pc,IO_TTYfetch ; seek(), fetch !word, final offset ;trap 6 ; close() ;add (sp)+,r1 ; add saved offset from base ;bcc tty_InitDone ;mov #TTY_KBDQ6,r1 ; Hard-wired .tty_InitDone mov r1,SV_KBDFETCH+2 ; Store offset to kbdQ ; bisb r2,SV_SYS ; Set Unix version in flags, indicate ioctrl()/lseek()/etc Unix v7 available br tty_Init1 ; .tty_InitV7 ; bisb #FLG_UNIXV7,SV_SYS ; &04, UnixV7 ;clr SV_KBDFETCH+2 mov #TTY_KBDQ7,SV_KBDFETCH+4 ; Hard-wired, offset to v7 keyboard buffer mov SV_IOCTL+0,SV_OSIOCTL+0 ; Save host's Interupt/Quit characters ;mov #&1F1B,SV_IOCTL+0 ; Change SIGINT to CHR$27, SIGQUIT to CHR$31 movb #27,SV_IOCTL+0 ; Change SIGINT to CHR$27, leave SIGQUIT as CHR$28 trap 54 ; ioctrl() equw 0 ; stdin equb 17,"t" ; TIOCSETP equw SV_IOCTL ; Write settings on stdin mov #FLG_UNIXV7,r2 ; &04, UnixV7 #endif ; Get TTY settings and set to raw input ; ------------------------------------- .tty_Init1 bisb r2,SV_SYS ; Set Unix version in flags, indicate ioctrl()/lseek()/etc Unix v7+ available #if FLG_NOTTY0<>1 #error FLG_NOTTY0 must be &01 #endif #ifdef BSD211 mov #SV_TTY,-(sp) ; =>argbuf mov #ASC"t"*256+8,-(sp) ; TIOCGETP mov #&o40006,-(sp) ; b14=get, b7-b0=6 bytes to read clr -(sp) ; 0=STDIN clr -(sp) ; Padding trap 54 ; ioctrl() add #10,sp ; Drop from stack #else rorb SV_SYS ; Move bit 0 out of flags clr r0 ; R0=STDIN trap 32 ; gtty() equw SV_TTY ; Read host's TTY setting rolb SV_SYS ; Move NotTTY flag into bit 0 of flags #endif mov SV_TTY+4,SV_OSTTY ; Save host's TTY flags ; Continue to set raw TTY KBD_TestKey: ; On exit, EQ=no key waiting, R0=0 ; NE=keypress present, R0=non-zero ; mov r1,-(sp) ; seek() and ioctl() modifies R1 clrb SV_KBDTEST ; Prepare 'none' mov SV_KBDFETCH+2,r0 bis SV_KBDFETCH+4,r0 beq KBD_TestKeyExit ; If offset=0, no kbdQ found trap 5 ; open() equw KBD_TTYmem ; =>"/dev/mem" equw 0 ; 0=read bcs KBD_TestKeyExit ; Failed to open, return prepared 0 jsr pc,IO_TTYfetch ; Seek to kbdQ and fetch trap 6 ; close() KBD_TestKeyExit: mov (sp)+,r1 ; Restore R1 for caller movb SV_KBDTEST,r0 ; Get the word read, setting EQ rts pc IO_TTYfetch4: add #4,r1 ; PTR=R1+4 IO_TTYfetchR1: mov r1,SV_KBDFETCH+2 ; Set PTR IO_TTYfetch: mov r0,-(sp) ; Save handle trap 0 equw SV_KBDFETCH ; seek() mov (sp)+,r0 ; Get handle IO_TTYfetch1: mov r0,-(sp) ; Save handle trap 3 ; read() equw SV_KBDTEST ; =>buffer equw 2 ; read two bytes mov (sp)+,r0 ; Get handle back mov SV_KBDTEST,r1 rts pc IO_TTYmem: equs "/dev/mem",0 align SV_KBDTEST: equw 0 ; returns high word equw 0 ; returns low word BSD2.9 Unix =========== BSD Unix has an ioctl() call to read how many pending input characters there are. The BSD2.9 call API is the same as Bell Unix. KBD_TestKey: ; On exit, EQ=no key waiting, R0=0 ; NE=keypress present, R0=non-zero ; mov r1,-(sp) ; ioctl() modifies R1 trap 54 ; ioctrl() equw 0 ; stdin equb 127,"f" ; FIONREAD equw SV_KBDTEST-2 ; Read number of keys pending mov (sp)+,r1 ; Restore R1 for caller movb SV_KBDTEST,r0 ; Get the word read, setting EQ rts pc SV_KBDTEST: equw 0 ; returns high word equw 0 ; returns low word BSD Unix ======== BSD Unix has an ioctl() call to read how many pending input characters there are. The BSD2.11 and later passes parameters via the stack. TTYtest: mov r1,-(sp) ; ioctl() modifies R1 mov #SV_KBDTEST,-(sp) ; will return high word, low word mov #ASC"f"*256+127,-(sp) ; FIONREAD mov #&4004,-(sp) ; b14=get, 4 bytes to read clr -(sp) ; fd=STDIN clr -(sp) ; Padding trap 54 ; SYS ioctl add #10,sp ; Drop from stack mov (sp)+,r1 ; Restore R1 mov SV_KBDTEST+2,r0 ; Get the word read, setting EQ rts pc ; R0=0, EQ: no keypress waiting ; R0>0, NE: keypress waiting, next read(STDIN) will return a character SV_KBDTEST: equw 0 ; returns high word equw 0 ; returns low word