10
20
30 :
40
50
60
70 :
80
90
100
110
120 :
130
140
150
160
170 :
180
190
200
210 :
220 kbd%=1
230 OSBYTE=&FFF4:OSARGS=&FFDA
240 EVNTV=&220:KEYV=&228:INSV=&22A
250 usb_D=&FCF8:usb_S=&FCF9
260 :
270 DIM mcode% &300:load%=&FFFF08BC
280 FOR P=0 TO 1
290 P%=load%:O%=mcode%
300 [OPT P*3+4
310 .exec%
320 .usb_Init
330 LDX #usb_SCS-usb_Cmd:JSR usb_CmdSend6
340 JSR usb_Flush:CMP #&80 :\ Cy=HUB
350 AND #8:BEQ usb_NoKbd
360 BCS usb_InitLp1a :\ HUB, start at device 1
370 .usb_InitLp1
380 LDX #usb_SC0-usb_Cmd:JSR usb_CmdSend6
390 JSR usb_Flush:CMP #8:BEQ usb_Init2
400 .usb_InitLp1a
410 INC usb_SC0+2:LDA usb_SC0+2
420 CMP #13:BNE usb_InitLp1:BEQ usb_NoKbd
430 .usb_Init2
440 PHP:SEI:LDX #1
450 .usb_InitLp3
460 LDA KEYV,X:STA oldKEYV+1,X
470 LDA usb_Vectors+0,X:STA KEYV,X
480 LDA usb_Vectors+2,X:STA EVNTV,X
490 DEX:BPL usb_InitLp3
500 PLP:LDA #14:LDX #4:JMP OSBYTE
510 .usb_Vectors
520 EQUW usb_KEY:EQUW usb_EVNT
530 :
540 .usb_NoKbd
550 BRK:EQUB 214:EQUS "No kbd?":\BRK
560 .kbd_lastK:BRK:.kbd_modify:BRK
570 :
580 .usb_CmdSend6
590 LDY #6
600 .usb_CmdSend
610 TXA:PHA:JSR usb_Flush:PLA:TAX
620 .usb_CmdSendLp1
630 LDA usb_Cmd,X:JSR usb_Wr
640 INX:DEY:BEQ usb_Rd
650 CMP #13:BNE usb_CmdSendLp1
660 .usb_CmdSendLp2
670 JSR usb_Rd:CMP #13:BNE usb_CmdSendLp2
680 BEQ usb_CmdSend
690 :
700 .usb_Flush :BIT usb_D:LDX #64
710 .usb_FlushLp:DEX:BNE usb_FlushLp
720 BIT usb_S:BPL usb_Flush:RTS
730 :
740 .usb_Rd:BIT &FF:BMI usb_Rd2:BIT usb_S:BMI usb_Rd
750 .usb_Rd2:LDA usb_D:RTS
760 .usb_Wr:BIT &FF:BMI usb_Wr2:BIT usb_S:BVS usb_Wr
770 .usb_Wr2:STA usb_D:.usb_bye:RTS
780 :
790 .usb_KEY
800 BVS oldKEYV:BCS oldKEYV
810 JSR oldKEYV:BMI usb_bye:BVS usb_bye :\ oldKEYV Shift or Ctrl pressed
820 BIT kbd_modify:PHP:PLA:RTS :\ Set flags and A from Shift/Ctrl
830 .oldKEYV
840 JMP 0
850 :
860 .usb_EVNT
870 CMP #4:BNE usb_bye :\ Not VSync
880 :
890 \ We are running event code, so all IRQs are disabled
900 \ So we can use IRQ workspace at &FA/&FB
910 \
920 LDX #0:LDY #12:JSR usb_CmdSend :\ Read from keyboard
930 CLC:BEQ kbd_flush:CMP #9:BCS kbd_flush :\ Null packet or invalid packet
940 JSR usb_Rd:JSR usb_Rd:TAY :\ Y=modifiers
950 JSR usb_Rd:JSR usb_Rd:CMP #&FF :\ A=keypress, set CC+NE
960 .kbd_flush
970 PHP:JSR usb_Flush:PLP:BCS kbd_exit :\ Not our data packet
980 \BIT usb_D:\BIT sub_S:\BPL kbd_flush:\BCS kbd_exit:\TAX
990 :
1000 \ CS =null/invalid packet
1010 \ CC+EQ=no data received, no change to keys pressed
1020 \ CC+NE=keypress, might be same or different to last key
1030 BEQ kbd_repeat :\ No key change
1040 PHA:TYA:STA &FA :\ A=gascgasc
1050 ASL A:ASL A:ASL A:ASL A :\ A=gasc0000
1060 ORA &FA:AND #&F0 :\ A=GASC0000
1070 ASL A:ASL A:ROL A :\ A=C000000A, Cy=S
1080 BCC P%+4:ORA #&40 :\ A=CS00000A
1090 STA kbd_modify :\ b7=ctrl, b6=shift, b0=alt
1100 :
1110 PLA:CMP kbd_lastK:BEQ kbd_repeat :\ Same key pressed down
1120 STA kbd_lastK :\ New or no keypress
1130 LDX &254:STX &E7 :\ Copy KeyDelay to KeyCountdown
1140 .kbd_keypress
1150 JSR kbd_convert:BCS kbd_exit :\ No keypress
1160 TAY:EOR &26C:BNE kbd_insert :\ Not Escape
1170 STA &E7 :\ Cancel autorepeat
1180 .kbd_insert
1190 LDX #3
1200 .kbd_save
1210 LDA &EE,X:PHA:DEX:BNE kbd_save :\ Save OSBYTE parameters
1220 LDA #153:JSR OSBYTE:LDX #&FD :\ Insert with Escape processing
1230 .kbd_restore
1240 PLA:STA &F2,X:INX:BNE kbd_restore :\ Restore OSBYTE parameters
1250 .kbd_exit
1260 RTS
1270 :
1280 .kbd_repeat
1290 LDA &E7:BEQ kbd_exit :\ Repeat disabled
1300 DEC &E7:BEQ P%+6:DEC &E7:BNE kbd_exit :\ Countdown not reached
1310 LDA &255:STA &E7 :\ Copy KeyRepeat to KeyCountdown
1320 LDA kbd_lastK:JMP kbd_keypress :\ Insert another keypress
1330 :
1340 .kbd_convert
1350 CMP #&39:BNE kbd_notcaps
1360 LDA &25A:EOR #16:STA &25A:RTS :\ CAPS
1370 .kbd_notcaps
1380 SEC:SBC #4:BPL kbd_test:SBC #&1F :\ Reduce range if &84+
1390 .kbd_test
1400 CMP #&69:BCS kbd_exit :\ No keypress
1410 LDX kbd_modify:STX &FA :\ Get modifiers
1420 ADC #ASC"A":CMP #ASC"[":BCC kbd_tab :\ Letter
1430 SBC #42:CMP #ASC"9"+1:BCC kbd_tab :\ Digit
1440 TAX:LDA kbd_keytable-58,X
1450 BNE kbd_tab:LDA &26B :\ TAB
1460 .kbd_tab
1470 CMP #ASC"!":BCC kbd_exit :\ ctrls+spc
1480 CMP #127:BEQ kbd_done:BCS kbd_topset :\ DEL and topbit keys
1490 CPX #&7B:BEQ kbd_nonalpha :\ Special JP '\'
1500 CMP #ASC"_":BCS kbd_nonalpha :\ &5F and &60
1510 CMP #ASC"A":BCS kbd_alpha :\ Letters and [\]^
1520 .kbd_nonalpha
1530 BIT &FA:BVC kbd_noshift :\ No SHIFT
1540 AND #&1F:TAX:LDA kbd_shift,X :\ Get shifted character
1550 .kbd_noshift
1560 CMP #ASC"@":BCS kbd_ctrl:RTS :\ If alpha, check for CTRL
1570 .kbd_topset
1580 CMP #&E0:BCC kbd_top1 :\ Not keypad keys
1590 BNE kbd_keypad:LDA #&CD :\ Special case for KRet
1600 .kbd_keypad
1610 LDX &27E:BNE kbd_keypad1:SBC #&D0:SEC :\ If base=0, use '0'
1620 .kbd_keypad1
1630 SBC #&F0:CLC:ADC &27E:\CLC:\RTS :\ Translate keypad keys
1640 BPL kbd_done :\ b7=0, return keypress
1650 .kbd_top1
1660 LSR &FA :\ &FA=0CS00000, Cy=A
1670 ROR &FA :\ &FA=A0CS0000, Cy=0
1680 BPL P%+4:EOR #&B0 :\ Apply ALT
1690 EOR &FA:RTS :\ Apply CTRL and SHIFT
1700 .kbd_alpha
1710 CMP #ASC"[":BCS tab_alpha2 :\ Skip past if not a letter
1720 ROR A:EOR &25A:AND #&EF:EOR &25A:ROL A :\ Apply CAPS to letters
1730 .tab_alpha2
1740 BIT &FA:BVC kbd_ctrl:EOR #32 :\ Apply SHIFT
1750 .kbd_ctrl
1760 BIT &FA:BPL kbd_done:AND #31 :\ Apply CTRL
1770 .kbd_done
1780 CLC:RTS
1790 :
1800 .usb_Cmd
1810 .usb_SCS:EQUB &10:EQUB 13
1820 .usb_IPH:EQUB &91:EQUB 13
1830 .usb_QP2:EQUB &2C:EQUB 13
1840 .usb_SC0:EQUB &86:EQUB &20:EQUB &00:EQUB 13
1850 .usb_DRD:EQUB &84:EQUB 13
1860 :
1870 .kbd_shift
1880 EQUS LEFT$("~!@~$%&""()*+<_>?)!@#$%^&*(*:<+>?",kbd%=0):\ US
1890 EQUS LEFT$("~!@~$%&@()*+<_>?)!""`$%^&*(*:<+>?",kbd%=1):\ UK
1900 \EQUSLEFT$("@!@~$%&'()*+<=>?0!""#$%&'()*+<+>`",kbd%=2):\ JP/BBC/ECMA
1910 EQUS LEFT$("@!@~$%&'()*+<=>?_!""#$%&'()*+_+>`",kbd%=2):\ JP/BBC/ECMA
1920 \ Shift+ !"#$%&'()*+,-./012 3456789c;<=>?
1930 \ @ABCDEFGHIJKLMNOPQR STUVWXYZ[\]^_
1940 \ `abcdefghijklmnopqr stuvwxyz{|}~
1950 \
1960 .kbd_keytable
1970 EQUB 48:EQUB 13:EQUB 27:EQUB 127:EQUB 0:EQUS " -"
1980 EQUS LEFT$("=[]\#;'`",kbd%=0):\ US
1990 EQUS LEFT$("=[]\#;'`",kbd%=1):\ UK
2000 EQUS LEFT$("^@[\];:_",kbd%=2):\ JP/BBC/ECMA
2010 EQUS ",./":EQUB 1:EQUB &81:EQUB &82:EQUB &83:EQUB &84:EQUB &85:EQUB &86
2020 EQUB &87:EQUB &88:EQUB &89:EQUB &CA:EQUB &CB:EQUB &CC:EQUB &80:EQUB &C3
2030 EQUB &8A:EQUB &CD:EQUB &C8:EQUB &9F:EQUB &7F:EQUB &8B:EQUB &9E:EQUB &8D
2040 EQUB &8C:EQUB &8E:EQUB &8F:EQUB &C2
2050 EQUB &C0+ASC"/":EQUB &C0+ASC"*":EQUB &C0+ASC"-":EQUB &C0+ASC"+"
2060 EQUB &E0 :EQUB &C0+ASC"1":EQUB &C0+ASC"2":EQUB &C0+ASC"3"
2070 EQUB &C0+ASC"4":EQUB &C0+ASC"5":EQUB &C0+ASC"6":EQUB &C0+ASC"7"
2080 EQUB &C0+ASC"8":EQUB &C0+ASC"9":EQUB &C0+ASC"0":EQUB &C0+ASC"."
2090 EQUS "\" :EQUB &C1 :EQUB &C0+ASC",":EQUB &C0+ASC"="
2100 EQUS "\":EQUB &C7:EQUS "\":EQUB &C6:EQUB &C5
2110 \ Note, calculating function/keypad key codes takes 10 bytes but only
2120 \ save 9 bytes in the lookup table
2130 :
2140 ]
2150 NEXT:IF (P%AND&FFFF)>&B00:PRINT"Code overrun":END
2160 IF (kbd_lastK AND &FFFF)<&900:PRINT "Code start too early":END
2170 PRINT"*SAVE USBKBD ";~mcode%;" ";~O%;" ";~exec%OR&FFFF0000;" ";~load%