10
20
30
40
50
60 :
70 OSBYTE=&FFF4:IRQ2V=&206:FXESC=&26C
80 via=&FE60
90 :
100 DIM mcode% &200:load%=&FFFF0A80
110 FOR P=0 TO 1
120 P%=load%:O%=mcode%
130 [OPT P*3+4
140 .exec%
150 PHP:SEI:LDX #1
160 .kbdInitLp1
170 LDA IRQ2V,X:STA oldIRQ2+1,X :\ Claim IRQ2V
180 LDA kbdVectors+0,X:STA IRQ2V,X
190 DEX:BPL kbdInitLp1
200 LDA via+12:AND #&0F
210 ORA #&C0:STA via+12 :\ CB2=low, CB1=negative edge
220 LDA #&90:STA via+14 :\ Enable CB1
230 LDA #&00:STA via+2 :\ PB=input
240 PLP:RTS
250 .kbdVectors
260 EQUW kbdIRQ
270 \ Should also claim KEYV to test SHIFT+CTRL for scrolling
280 :
290 .kbdIRQ
300 LDA via+13:BPL oldIRQ2 :\ b7=0 - Not VIA IRQ
310 AND #&10:BEQ oldIRQ2 :\ b4=0 - Not CB1 IRQ
320 TYA:PHA:TXA:PHA :\ Save registers
330 LDA #&00:STA via+2 :\ PB=input
340 LDA via+12:ORA #&E0:STA via+12 :\ CB2=high
350 LDX via+0 :\ Get kbdstatus, clear CB1
360 AND #&0F:ORA #&C0:STA via+12 :\ CB2=low, CB1=negative edge
370 LDA via+0 :\ Get kbddata
380 CPX via+0:BNE kbdIRQ3 :\ If data=status, no status
390 LDX #0 :\ Make status=0
400 .kbdIRQ3
410 \ A=character
420 \ X=status
430 \ b7=strobe - ignored
440 \ b6=special case - ignored
450 \ b5=ctrl \ so EOR gives
460 \ b4=shift / function key codes
470 :
480 TAY:BPL kbdIRQ4 :\ Not top-bit character
490 TXA:AND #&30:EOR via+0:TAY :\ Mask in CTRL+SHIFT
500 .kbdIRQ4
510 LDX #3
520 .kbdSave
530 LDA &EE,X:PHA:DEX:BNE kbdSave :\ Save OSBYTE parameters
540 LDA #153:JSR OSBYTE:LDX #&FD :\ Insert with Escape processing
550 .kbdRestore
560 PLA:STA &F2,X:INX:BNE kbdRestore :\ Restore OSBYTE parameters
570 PLA:TAX:PLA:TAY :\ Restore registers
580 .oldIRQ2
590 JMP oldIRQ2 :\ And pass on
600 :
610 ]
620 NEXT:IF (P%AND&FFFF)>&B00:PRINT"Code overrun":END
630 IF (kbdIRQ AND &FFFF)<&900:PRINT "Code start too early":END
640 PRINT"*SAVE USRKBD ";~mcode%;" ";~O%;" ";~exec%OR&FFFF0000;" ";~load%