;**************************************************************************** ; PS2 keyboard Interface for the 6502 Microprocessor utilizing a 6522 VIA ; (or suitable substitute), polling the I/O for data. ; ; Designed and Written by Daryl Rictor (c) 2001 65c02@altavista.com ; Offered as freeware. No warranty is given. Use at your own risk. ; Original code at https://sbc.rictor.org/pckb6522.html ; ; Edited by J.G.Harston for ca65 style assemblers, 2018. ; Example usage: as65 -i -w125 -x -lps2kbd1.lst -ops2kbd1.bin ps2kbd1.asm ; Amended to use regular keyboard map. ; ; The software requires about 930 bytes of memory for code storage and only 4 bytes ; in RAM for temporary storage. Zero page locations can be used but are NOT required. ; ; Hardware utilizes any two bidirection I/O bits from a 6522 VIA connected directly ; to a 5-pin DIN socket (or 6 pin PS2 DIN). In this example I'm using the ; 6522 PB4 (Clk) & PB5 (Data) pins connected to a 5-pin DIN. The code could be ; rewritten to support other IO arrangements as well. ; ________________________________________________________________________________ ;| | ;| 6502 <-> PS2 Keyboard Interface Schematic by Daryl Rictor (c) 2001 | ;| 65c02@altavista.com | ;| | ;| __________ | ;| ____________________________________| | | ;| / Keyboard Data 15 |PB5 | | ;| | | | | ;| _____|_____ | | | ;| / | \ | 6522 | | ;| / o \ +5vdc (300mA) | VIA | | ;| /-------o 2 o--------------------o----> | | | ;| | | 4 5 | | | | | ;| | | | *C1 __|__ | | | ;| | | o 1 3 o | _____ | | | ;| | | | | | | | | ;| | \ | / __|__ | | | ;| | \| _ / ___ | | | ;| | |____| |____/ - | | | ;| | | *C1 0.1uF Bypass Cap | | | ;| | | | | | ;| | \__________________________________________| | | ;| | Keyboard Clock 14 | PB4 | | ;| __|__ |__________| | ;| ___ | ;| - | ;| Keyboard Socket (not the keyboard cable) | ;| (As viewed facing the holes) | ;| | ;|________________________________________________________________________________| ; ; Software communicates to/from the keyboard and converts the received scan-codes ; into usable ASCII code. ASCII codes 01-7F are decoded as well as extra codes ; in order to access all the extra keys including cursor, num pad, function, and ; windows keys. It was tested on two inexpensive keyboards with no errors. ; Just in case, though, I've coded the - key combination to ; perform a keyboard re-initialization just in case it goes south during data entry. ; ; Recommended Routines callable from external programs ; ; KBINIT - Initialize the keyboard and associated variables and set the LEDs ; KBINPUT - wait for a key press and return with its assigned ASCII code in A. ; KBGET - wait for a key press and return with its unprocessed scancode in A. ; KBSCAN - Scan the keyboard for 105us, returns 0 in A if no key pressed. ; Return ambiguous data in A if key is pressed. Use KBINPUT OR KBGET ; to get the key information. You can modify the code to automatically ; jump to either routine if your application needs it. ; ;**************************************************************************** ; ; All standard keys and control keys are decoded to 7 bit (bit 7=0) standard ASCII. ; Control key note: It is being assumed that if you hold down the ctrl key, ; you are going to press an alpha key (A-Z) with it (except break key defined below). ; If you press another key, the lower 5 bits of the ascii code will be returned as a ; control code. For example, Ctrl-1 returns $11, Ctrl-; returns $1B (Esc). ; ; The following non-ASCII keys are decoded with bit 7=1, bit 5=1 if ctrl pressed, ; bit 4=1 if shifted, and bits 5-0 identify the key. ; ; Function key translation: ; ASCII / Shift / Ctrl / SH+CT ; F1 - 81 / 91 / A1 / B1 ; F2 - 82 / 92 / A2 / B2 ; F3 - 83 / 93 / A3 / B3 ; F4 - 84 / 94 / A4 / B4 ; F5 - 85 / 95 / A5 / B5 ; F6 - 86 / 96 / A6 / B6 ; F7 - 87 / 97 / A7 / B7 ; F8 - 88 / 98 / A8 / B8 ; F9 - 89 / 99 / A9 / B9 ; F10 - 8A / 9A / AA / BA ; F11 - 8B / 9B / AB / BB ; F12 - 8C / 9C / AC / BC ; ; The Print screen and Pause/Break keys are decoded as: ; ASCII / Shift / Ctrl / SH+CT ; Print Screen - 80 / 90 / A0 / B0 ; Num Lock - 8D / 9D / AD / BD if not intercepted ; Scroll Lock - 8E / 9E / AE / BE ; Pause/Break - 8F / 9F / AF / BF ; Ctrl-PrtScn - performs keyboard reinitialization in case of errors ; (haven't had any yet - can be removed or changed by user) ; ; The Alt key is decoded as a hold down (like shift and ctrl) but does not ; alter the ASCII code of the key(s) that follow. Rather, it sends ; a Alt key-down code and a seperate Alt key-up code. The user program ; can keep track of it if they want to use Alt keys. ; ; Alt down - A0 ; Alt up - B0 ; ; Example byte stream of the Alt-F1 sequence: A0 81 B0. If Alt is held down longer ; than the repeat delay, a series of A0s will preceeed the 81 B0. ; i.e. A0 A0 A0 A0 A0 A0 81 B0. ; ; The three Windows keys are decoded as follows: ; ASCII / Shift / Ctrl / SH+CT ; Left Windows Key - C0 / D0 / E0 / F0 ; Right Windows Key - D0 / C0 / F0 / E0 ; Menu Key - C1 / D1 / E1 / F1 ; ; The following "special" keys ignore the shift key and return their special key code ; when numlock is off or their direct labeled key is pressed. When numlock is on, the digits ; are returned regardless of shift key state. The normal cursor/editing keys also return ; keypad keycodes. ; ; keypad(NumLock off) or Direct - ASCII Keypad(NumLock on) ASCII ; Keypad 5 (blank) - C5 35 ; Keypad 0 Ins - C6 30 ; Keypad . Del - C7 2E ; Keypad 7 Home - C8 37 ; Keypad 1 End - C9 31 ; Keypad 3 PgDn - CA 33 ; Keypad 9 PgUp - CB 39 ; Keypad 4 LfArrow - CC 34 ; Keypad 6 RtArrow - CD 36 ; Keypad 2 DnArrow - CE 32 ; Keypad 8 UpArrow - CF 38 ; ;**************************************************************************** ; ; ; CPU speed MHZ = 100 ; 1MHz CPU clock speed ; ; I/O Port definitions kbportreg = $7F01 ; 6522 IO port register B kbportddr = $7F03 ; 6522 IO data direction register B kbclk = $10 ; 6522 IO port clock bit mask (PB4) kbdata = $20 ; 6522 IO port data bit mask (PB5) ; ; temporary storage locations (zero page can be used but not necessary) byte = $02D0 ; byte send/received parity = $02D1 ; parity holder for rx special = $02D2 ; ctrl, shift, caps and kbd LED holder lastbyte = $02D3 ; last byte received ; bit definitions for the special variable ; (1 is active, 0 inactive) ; special = 01 - Scroll Lock \ ; 02 - Num Lock } ordered for SetLEDs command ; 04 - Caps lock / ; 10 - shift (either left or right) \ ordered to ; 20 - control (either left or right) / modify keycode ; ; Scroll Lock LED is used to tell when ready for input ; Scroll Lock LED on = Not ready for input ; Scroll Lock LED off = Waiting (ready) for input ; ; Num Lock and Caps Lock LEDs are used normally to ; indicate their respective states. ; ;*************************************************************************************** ; ; test program - reads input, prints the ascii code to the terminal and loops until the ; target keyboard key is pressed. ; ; external routine "print_char" prints character in A to the terminal ; external routine "print_hex" prints A register as two hexadecimal characters ; external routine "print_newl" prints characters $0D & $0A to the terminal ; (substitute your own routines as needed) ; ; org $1000 ; locate program at $1000 ; jsr kbinit ; init the keyboard, LEDs, and flags ;lp0 jsr print_newl ; prints 0D 0A (CR LF) to the terminal ;lp1 jsr kbinput ; wait for a keypress, return decoded ASCII code in A ; cmp #$0d ; if CR, then print CR LF to terminal ; beq lp0 ; ; cmp #$1B ; esc ascii code ; beq lp2 ; ; cmp #$20 ; ; bcc lp3 ; control key, print as except $0D (CR) & $1B (Esc) ; cmp #$80 ; ; bcs lp3 ; extended key, just print the hex ascii code as ; jsr print_char ; prints contents of A reg to the Terminal, ascii 20-7F ; bra lp1 ; ;lp2 rts ; done ;lp3 pha ; ; lda #$3C ; < ; jsr print_char ; ; pla ; ; jsr print_hex ; print one byte in hex ; lda #$3E ; > ; jsr print_char ; ; bra lp1 ; ; ;************************************************************************************** ; ; Decoding routines ; ; KBINPUT is the main routine to call to get an ascii char from the keyboard ; (waits for a non-zero ascii code) ; org $7000 ; arbitary start address at $7000 kbreinit jsr kbinit ; kbinput jsr kbtscrl ; turn off scroll lock (ready to input) bne kbinput ; ensure it's off kbinput1 jsr kbget ; get a code (wait for a key to be pressed) jsr kbcsrch ; scan for 14 special case codes kbcnvt beq kbinput1 ; 0=complete, get next scancode tax ; set up scancode as table pointer cmp #$78 ; see if it's F11 beq kbcnvt1 ; it is, skip keypad test cmp #$69 ; test for keypad codes 69 bmi kbcnvt1 ; thru cmp #$7E ; 7D (except 78 tested above) bpl kbcnvt1 ; skip if not a keypad code lda special ; test numlock bit #$02 ; numlock on? beq kbcnvt2 ; no, set shifted table for special keys bra kbcnvt3 ; skip shift test kbcnvt1 lda special ; bit #$10 ; shift pressed? beq kbcnvt3 ; no kbcnvt2 txa ; yes ora #$80 ; set shifted table tax ; kbcnvt3 lda special ; bit #$20 ; control? beq kbcnvt4 ; no lda asciitbl,x ; get ascii code beq kbinput1 ; if ascii code is 0, invalid scancode, get another bmi kbcnvt3a ; top-bit code ; ; cmp #KPRN ; {ctrl-Printscrn - do re-init or user can remove this code } ; beq kbreinit ; {do kb reinit } ; and #$1F ; mask control code (assumes @,A-Z,[\]^_ is pressed) bra kbdone ; kbcnvt3a ora #$20 ; set bit 5 for control pressed bra kbdone kbcnvt4 lda asciitbl,x ; get ascii code beq kbinput1 ; if ascii code is 0, invalid scancode, get another tax ; save ascii code in X reg lda special ; bit #$04 ; test caps lock beq kbdone1 ; caps lock off txa ; caps lock on - get ascii code cmp #$61 ; test for lower case a bcc kbdone1 ; if less than, skip down cmp #$7B ; test for lower case z bcs kbdone1 ; if greater than, skip down and $5F ; if caps on and lowercase, change to upper kbdone tax ; put new ascii to X reg kbdone1 phx ; save ascii to stack kbdone2 jsr kbtscrl ; turn on scroll lock (not ready to receive) beq kbdone2 ; ensure scroll lock is on pla ; get ASCII code back rts ; return to calling program ; ;****************************************************************************** ; ; scan code processing routines ; ; kbtrap83 lda #$02 ; traps the F7 code of $83 and change rts ; ; kbsshift lda #$10 ; *** neat trick to tuck code inside harmless instruction db $2C ; *** use BIT Absolute to skip lda #$02 below kbsctrl lda #$20 ; *** disassembles as LDA #$10 ora special ; BIT $A902 sta special ; ORA $02D3 bra kbnull ; return with 0 in A ; kbtnum lda special ; toggle numlock bit in special eor #$02 ; sta special ; jsr kbsled ; update keyboard LEDs bra kbnull ; return with 0 in A ; kbresend lda lastbyte ; jsr kbsend ; bra kbnull ; return with 0 in A ; kbtcaps lda special ; toggle caps bit in special eor #$04 ; sta special ; jsr kbsled ; set new status LEDs kbnull lda #$00 ; set caps, get next code rts ; ; kbExt jsr kbget ; get next code cmp #$F0 ; is it an extended key release? beq kbexrls ; test for shift, ctrl, caps cmp #$14 ; right control? beq kbsctrl ; set control and get next scancode ldx #$03 ; test for 4 scancode to be relocated kbext1 cmp kbextlst,x ; scan list beq kbext3 ; get data if match found dex ; get next item bpl kbext1 ; cmp #$3F ; not in list, test range 00-3F or 40-7F bmi kbExt2 ; it's a windows/alt key, just return unshifted ora #$80 ; return scancode and point to shifted table kbExt2 rts ; kbext3 lda kbextdat,x ; get new scancode rts ; ; kbextlst db $7E ; E07E ctrl-break scancode db $4A ; E04A kp/ db $12 ; E012 scancode db $7C ; E07C prt scrn ; kbextdat db $20 ; new ctrl-brk scancode db $6F ; new kp/ scancode db $00 ; do nothing (return and get next scancode) db $0F ; new prt scrn scancode ; kbexrls jsr kbget ; cmp #$12 ; is it a release of the E012 code? bne kbrlse1 ; no - process normal release bra kbnull ; return with 0 in A ; kbRlse jsr kbget ; test for shift & ctrl cmp #$12 ; beq kbrshift ; reset shift bit cmp #$59 ; beq kbrshift ; kbrlse1 cmp #$14 ; beq kbrctrl ; cmp #$11 ; alt key release bne kbnull ; return with 0 in A kbralt lda #$17 ; new alt release scancode rts ; kbrctrl lda #$DF ; reset ctrl bit in special db $2C ; use (BIT Absolute) to skip lda #$EF if passing down kbrshift lda #$EF ; reset shift bit in special and special ; sta special ; bra kbnull ; return with 0 in A ; kbtscrl lda special ; toggle scroll lock bit in special eor #$01 ; sta special ; jsr kbsled ; update keyboard LEDs lda special ; bit #$01 ; check scroll lock status bit rts ; return ; kbBrk ldx #$07 ; ignore next 7 scancodes then kbBrk1 jsr kbget ; get scancode dex ; bne kbBrk1 ; lda #$10 ; new scan code rts ; ; kbcsrch ldx #$0E ; 14 codes to check kbcsrch1 cmp kbclst,x ; search scancode table for special processing beq kbcsrch2 ; if found run the routine dex ; bpl kbcsrch1 ; rts ; no match, return from here for further processing kbcsrch2 txa ; code found - get index asl a ; mult by two tax ; save back to x lda byte ; load scancode back into A jmp (kbccmd,x) ; execute scancode routine, return 0 if done ; nonzero scancode if ready for ascii conversion ; ;keyboard command/scancode test list ; db=define byte, stores one byte of data ; kbclst db $83 ; F7 - move to scancode 02 db $58 ; caps db $12 ; Lshift db $59 ; Rshift db $14 ; ctrl db $77 ; num lock db $E1 ; Extended pause break db $E0 ; Extended key handler db $F0 ; Release 1 byte key code db $FA ; Ack db $AA ; POST passed db $EE ; Echo db $FE ; resend db $FF ; overflow/error db $00 ; underflow/error ; ; command/scancode jump table ; kbccmd dw kbtrap83 ; dw kbtcaps ; dw kbsshift ; dw kbsshift ; dw kbsctrl ; dw kbtnum ; dw kbBrk ; dw kbExt ; dw kbRlse ; dw kbnull ; dw kbnull ; dw kbnull ; dw kbresend ; dw kbflush ; dw kbflush ; ; ;************************************************************** ; ; Keyboard I/O support ; ; ; KBSCAN will scan the keyboard for incoming data for about ; 105us and returns with A=0 if no data was received. ; It does not decode anything, the non-zero value in A if data ; is ready is ambiguous. You must call KBGET or KBINPUT to ; get the keyboard data. ; KBSCAN ldx #MHZ/20 ; timer: X = (cycles - 40)/13 (105-40)/13=5 @ 1MHz lda kbportddr ; and #$FF-kbdata-kbclk ; set clk to input sta kbportddr ; kbscan1 lda #kbclk ; bit kbportreg ; beq kbscan2 ; if clk goes low, data ready dex ; decrement timer bne kbscan1 ; wait while clk is high jsr kbdis ; timed out, no data, disable receiver lda #$00 ; set data not ready flag rts ; return kbscan2 jsr kbdis ; disable the receiver so other routines get it ; Three alternative exits if data is ready to be received: Either return or jmp to handler rts ; return (A<>0, A=clk bit mask value from kbdis) ; jmp KBINPUT ; if key pressed, decode it with KBINPUT ; jmp KBGET ; if key pressed, decode it with KBGET ; ; kbflush lda #$F4 ; flush buffer ; ; send a byte to the keyboard ; kbsend sta byte ; save byte to send phx ; save registers phy ; sta lastbyte ; keep just in case the send fails lda kbportreg ; and #$FF-kbclk ; clk low, data high ora #kbdata ; sta kbportreg ; lda kbportddr ; ora #kbclk+kbdata ; set bits high sta kbportddr ; set outputs, clk=0, data=1 lda #MHZ*4/25 ; CPU clock delay (delay = cpuclk/62500) = 16 @ 1MHz kbsendw dec a ; bne kbsendw ; 64us delay ldy #$00 ; parity counter ldx #$08 ; bit counter lda kbportreg ; and #$FF-kbclk-kbdata ; clk low, data low sta kbportreg ; lda kbportddr ; and #$FF-kbclk ; set clk as input sta kbportddr ; set outputs jsr kbhighlow ; kbsend1 ror byte ; get lsb first bcs kbmark ; lda kbportreg ; and #$FF-kbdata ; turn off data bit sta kbportreg ; bra kbnext ; kbmark lda kbportreg ; ora #kbdata ; sta kbportreg ; iny ; inc parity counter kbnext jsr kbhighlow ; dex ; bne kbsend1 ; send 8 data bits tya ; get parity count and #$01 ; get odd or even bne kbpclr ; if odd, send 0 lda kbportreg ; ora #kbdata ; if even, send 1 sta kbportreg ; bra kback ; kbpclr lda kbportreg ; and #$FF-kbdata ; send data=0 sta kbportreg ; kback jsr kbhighlow ; lda kbportddr ; and #$FF-kbdata-kbclk ; set clk & data to input sta kbportddr ; ply ; restore saved registers plx ; jsr kbhighlow ; wait for ack from keyboard bne kbinit ; VERY RUDE error handler - re-init the keyboard kbsend2 lda kbportreg ; and #kbclk ; beq kbsend2 ; wait while clk low bra kbdis ; disable kbd sending ; ; KBGET waits for one scancode from the keyboard ; kberror lda #$FE ; resend cmd jsr kbsend ; kbget KBGET phx ; phy ; lda #$00 ; sta byte ; clear scankey holder sta parity ; clear parity holder ldy #$00 ; clear parity counter ldx #$08 ; bit counter lda kbportddr ; and #$FF-kbdata-kbclk ; set clk & data to input sta kbportddr ; kbget1 lda #kbclk ; bit kbportreg ; bne kbget1 ; wait while clk is high lda kbportreg ; and #kbdata ; get start bit bne kbget1 ; if 1, false start bit, do again kbget2 jsr kbhighlow ; wait for clk to return high then go low again cmp #$01 ; set c if data bit=1, clr if data bit=0 ; (change if port bits change) ok unless data=01 or 80 ; in that case, use ASL or LSR to set carry bit ror byte ; save bit to byte holder bpl kbget3 ; iny ; add 1 to parity counter kbget3 dex ; dec bit counter bne kbget2 ; get next bit if bit count > 0 jsr kbhighlow ; wait for parity bit beq kbget4 ; if parity bit 0 do nothing inc parity ; if 1, set parity to 1 kbget4 tya ; get parity count ply ; plx ; eor parity ; compare with parity bit and #$01 ; mask bit 1 only beq kberror ; bad parity jsr kbhighlow ; wait for stop bit beq kberror ; 0=bad stop bit lda byte ; if byte & parity 0, beq kbget ; no data, do again jsr kbdis ; lda byte ; rts ; ; kbdis lda kbportreg ; disable kbd from sending more data and #$FF-kbclk ; clk = 0 sta kbportreg ; lda kbportddr ; set clk to ouput low and #$FF-kbdata-kbclk ; (stop more data until ready) ora #kbclk ; sta kbportddr ; rts ; ; kbinit KBINIT lda #$02 ; init - num lock on, all other off sta special ; kbinit1 lda #$ff ; keyboard reset jsr kbsend ; reset keyboard jsr kbget ; cmp #$FA ; ack? bne kbinit1 ; resend reset cmd jsr kbget ; cmp #$AA ; reset ok bne kbinit1 ; resend reset cmd ; fall into to set the LEDs kbsled lda #$ED ; Set the keyboard LEDs from kbleds variable jsr kbsend ; jsr kbget ; cmp #$FA ; ack? bne kbsled ; resend led cmd lda special ; and #$07 ; ensure bits 7-3 are 0 jsr kbsend ; rts ; ; kbhighlow lda #kbclk ; wait for a low to high to low transition bit kbportreg ; beq kbhighlow ; wait while clk low kbhl1 bit kbportreg ; bne kbhl1 ; wait while clk is high lda kbportreg ; and #kbdata ; get data line state rts ; ;************************************************************* ; Special keycodes KPRN = $80 ; PRINTSCRN KNUM = $8D ; NUMLOCK KSCR = $8E ; SCRLOCK KBRK = $8F ; PAUSE/BREAK ; ; Unshifted table for scancodes to ascii conversion ; Scan|Keyboard ; Code|Key ; ----|---------- asciitbl db $00 ; 00 no key pressed db $89 ; 01 F9 db $87 ; 02 relocated F7 db $85 ; 03 F5 db $83 ; 04 F3 db $81 ; 05 F1 db $82 ; 06 F2 db $8C ; 07 F12 db $00 ; 08 db $8A ; 09 F10 db $88 ; 0A F8 db $86 ; 0B F6 db $84 ; 0C F4 db $09 ; 0D tab db $60 ; 0E `~ db KPRN ; 0F relocated Print Screen key db KBRK ; 10 relocated Pause/Break key db $A0 ; 11 left alt (right alt too) db $00 ; 12 left shift db $00 ; 13 International: Katakana db $00 ; 14 left ctrl (right ctrl too) db $71 ; 15 qQ db $31 ; 16 1! db $B0 ; 17 relocated Alt release code db $00 ; 18 db $00 ; 19 db $7A ; 1A zZ db $73 ; 1B sS db $61 ; 1C aA db $77 ; 1D wW db $32 ; 1E 2@ db $C0 ; 1F Windows menu key (left side) db KBRK+$20 ; 20 relocated ctrl-break key db $63 ; 21 cC db $78 ; 22 xX db $64 ; 23 dD db $65 ; 24 eE db $34 ; 25 4$ db $33 ; 26 3# db $D0 ; 27 Windows menu key (right side) db $00 ; 28 db $20 ; 29 space db $76 ; 2A vV db $66 ; 2B fF db $74 ; 2C tT db $72 ; 2D rR db $35 ; 2E 5% db $C1 ; 2F Windows option key (right click, right side) db $00 ; 30 db $6E ; 31 nN db $62 ; 32 bB db $68 ; 33 hH db $67 ; 34 gG db $79 ; 35 yY db $36 ; 36 6^ db $00 ; 37 db $00 ; 38 db $00 ; 39 db $6D ; 3A mM db $6A ; 3B jJ db $75 ; 3C uU db $37 ; 3D 7& db $38 ; 3E 8* db $00 ; 3F db $00 ; 40 db $2C ; 41 ,< db $6B ; 42 kK db $69 ; 43 iI db $6F ; 44 oO db $30 ; 45 0) db $39 ; 46 9( db $00 ; 47 db $00 ; 48 db $2E ; 49 .> db $2F ; 4A /? db $6C ; 4B lL db $3B ; 4C ;: db $70 ; 4D pP db $2D ; 4E -_ db $00 ; 4F db $00 ; 50 db $00 ; 51 International 3 db $27 ; 52 '" db $00 ; 53 db $5B ; 54 [{ db $3D ; 55 =+ db $00 ; 56 db $00 ; 57 db $00 ; 58 caps db $00 ; 59 r shift db $0D ; 5A db $5D ; 5B ]} db $00 ; 5C db $5C ; 5D \| db $00 ; 5E db $00 ; 5F db $00 ; 60 db $08 ; 61 International: BACKSPC db $00 ; 62 International: Furigana db $00 ; 63 db $00 ; 64 International: Kanji db $00 ; 65 db $08 ; 66 bkspace db $00 ; 67 International: Hiragana db $00 ; 68 db $31 ; 69 kp 1 db $00 ; 6A International 4 db $34 ; 6B kp 4 db $37 ; 6C kp 7 db $00 ; 6D International 5 db $00 ; 6E db $2F ; 6F kp / converted from E04A in code db $30 ; 70 kp 0 db $2E ; 71 kp . db $32 ; 72 kp 2 db $35 ; 73 kp 5 db $36 ; 74 kp 6 db $38 ; 75 kp 8 db $1B ; 76 esc db KNUM ; 77 num lock db $8B ; 78 F11 db $2B ; 79 kp + db $33 ; 7A kp 3 db $2D ; 7B kp - db $2A ; 7C kp * db $39 ; 7D kp 9 db KSCR ; 7E scroll lock db $00 ; 7F ; ; Table for shifted scancodes ; db $00 ; 80 db $99 ; 81 F9 db $97 ; 82 relocated F7 db $95 ; 83 F5 (F7 actual scancode=83) db $93 ; 84 F3 db $91 ; 85 F1 db $92 ; 86 F2 db $9C ; 87 F12 db $00 ; 88 db $9A ; 89 F10 db $98 ; 8A F8 db $96 ; 8B F6 db $94 ; 8C F4 db $09 ; 8D tab db $7E ; 8E `~ db KPRN+$10 ; 8F relocated Print Screen key db KBRK+$10 ; 90 relocated Pause/Break key db $A0 ; 91 left alt (right alt) db $00 ; 92 left shift db $00 ; 93 International: Katakana db $00 ; 94 left ctrl (and right ctrl) db $51 ; 95 qQ db $21 ; 96 1! db $B0 ; 97 relocated Alt release code db $00 ; 98 db $00 ; 99 db $5A ; 9A zZ db $53 ; 9B sS db $41 ; 9C aA db $57 ; 9D wW db $40 ; 9E 2@ db $D0 ; 9F Windows menu key (left side) db KBRK+$30 ; A0 relocated ctrl-break key db $43 ; A1 cC db $58 ; A2 xX db $44 ; A3 dD db $45 ; A4 eE db $24 ; A5 4$ db $23 ; A6 3# db $C0 ; A7 Windows menu key (right side) db $00 ; A8 db $20 ; A9 space db $56 ; AA vV db $46 ; AB fF db $54 ; AC tT db $52 ; AD rR db $25 ; AE 5% db $D1 ; AF Windows option key (right click, right side) db $00 ; B0 db $4E ; B1 nN db $42 ; B2 bB db $48 ; B3 hH db $47 ; B4 gG db $59 ; B5 yY db $5E ; B6 6^ db $00 ; B7 db $00 ; B8 db $00 ; B9 db $4D ; BA mM db $4A ; BB jJ db $55 ; BC uU db $26 ; BD 7& db $2A ; BE 8* db $00 ; BF db $00 ; C0 db $3C ; C1 ,< db $4B ; C2 kK db $49 ; C3 iI db $4F ; C4 oO db $29 ; C5 0) db $28 ; C6 9( db $00 ; C7 db $00 ; C8 db $3E ; C9 .> db $3F ; CA /? db $4C ; CB lL db $3A ; CC ;: db $50 ; CD pP db $5F ; CE -_ db $00 ; CF db $00 ; D0 db $00 ; D1 International 3 db $22 ; D2 '" db $00 ; D3 db $7B ; D4 [{ db $2B ; D5 =+ db $00 ; D6 db $00 ; D7 db $00 ; D8 caps db $00 ; D9 r shift db $0D ; DA db $7D ; DB ]} db $00 ; DC db $7C ; DD \| db $00 ; DE db $00 ; DF db $00 ; E0 db $08 ; E1 International: BACKSPC db $00 ; E2 International: Furigana db $00 ; E3 db $00 ; E4 International: Kanji db $00 ; E5 db $08 ; E6 bkspace db $00 ; E7 International: Hiragana db $00 ; E8 db $C9 ; E9 kp 1 db $00 ; EA International 4 db $CC ; EB kp 4 db $C8 ; EC kp 7 db $00 ; ED International 5 db $00 ; EE db $2F ; EF kp / converted from E04A in code db $C6 ; F0 kp 0 db $C7 ; F1 kp . db $CE ; F2 kp 2 db $C5 ; F3 kp 5 db $CD ; F4 kp 6 db $CF ; F5 kp 8 db $1B ; F6 esc db KNUM+$10 ; F7 num lock db $9B ; F8 F11 db $2B ; F9 kp + db $CA ; FA kp 3 db $2D ; FB kp - db $2A ; FC kp * db $CB ; FD kp 9 db KSCR+$10 ; FE scroll lock ; NOT USED db $00 ; FF ; end