Improved C64 Keyboard Reader

JMP $FCE2
MarcWalters
Member
Member
Posts: 50
Joined: Wed Jun 11, 2014 2:33 pm
Location: Lake Macquarie, NSW, Australia

Improved C64 Keyboard Reader

Post by MarcWalters » Tue Jun 26, 2018 8:16 am

This is an improved keyboard reader.
It's main features are:
- slightly shorter
- about 20% faster
- not dependent on interrupts or vectors
- can be used with the Kernal ROM switched out
- Uses a keyboard buffer
- retains all the "features" of the original Kernal ROM routine

It's in C64 Prg Studio format.

To use:
1) Initialise with Keyb_Init at Application Start
Then, in a loop:
2) Call ReadKeyb to capture keypresses
3) Call GetKey to load the accumulator with a key from the keyboard buffer. On exit, Carry is set if the buffer was empty.

For example:

Code: Select all

TestKeyboard
         jsr Keyb_Init

@Loop    lda #$FF
@Raster  cmp $D012
	 bne @Raster

         jsr ReadKeyb
         jsr GetKey
         bcs @Skip
	
	 sta $0400
@Skip    jmp @Loop
Keyboard routines:

Code: Select all

KeyMapVec  word KeyMap1, KeyMap2, KeyMap3, KeyMap4

; Unshifted       
KeyMap1  byte $14, $0D, $1D, $88, $85, $86, $87, $11
         byte $33, $57, $41, $34, $5A, $53, $45, $01
         byte $35, $52, $44, $36, $43, $46, $54, $58
         byte $37, $59, $47, $38, $42, $48, $55, $56
         byte $39, $49, $4A, $30, $4D, $4B, $4F, $4E
         byte $2B, $50, $4C, $2D, $2E, $3A, $40, $2C
         byte $5C, $2A, $3B, $13, $01, $3D, $5E, $2F
         byte $31, $5F, $04, $32, $20, $02, $51, $03
         byte $FF

; Shifted
KeyMap2  byte $94, $8D, $9D, $8C, $89, $8A, $8B, $91
         byte $23, $D7, $C1, $24, $DA, $D3, $C5, $01
         byte $25, $D2, $C4, $26, $C3, $C6, $D4, $D8
         byte $27, $D9, $C7, $28, $C2, $C8, $D5, $D6
         byte $29, $C9, $CA, $30, $CD, $CB, $CF, $CE
         byte $DB, $D0, $CC, $DD, $3E, $5B, $BA, $3C
         byte $A9, $C0, $5D, $9e, $01, $3D, $DE, $3F
         byte $21, $5F, $04, $22, $A0, $02, $D1, $83
         byte $FF

; Commodore
KeyMap3
         byte $94, $8D, $9D, $8C, $89, $8A, $8B, $91
         byte $96, $B3, $B0, $97, $AD, $AE, $B1, $01
         byte $98, $B2, $AC, $99, $BC, $BB, $A3, $BD
         byte $9A, $B7, $A5, $9B, $BF, $B4, $B8, $BE
         byte $29, $A2, $B5, $30, $A7, $A1, $B9, $AA
         byte $A6, $AF, $B6, $DC, $3E, $5B, $A4, $3C
         byte $A8, $DF, $5D, $93, $01, $3D, $DE, $3F
         byte $81, $5F, $04, $95, $A0, $02, $AB, $83
         byte $FF

; Control
KeyMap4
         byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
         byte $1C, $17, $01, $9F, $1A, $13, $05, $FF
         byte $9C, $12, $04, $1E, $03, $06, $14, $18
         byte $1F, $19, $07, $9E, $02, $08, $15, $16
         byte $12, $09, $0A, $92, $0D, $0B, $0F, $0E
         byte $FF, $10, $0C, $FF, $FF, $1B, $00, $FF
         byte $1C, $FF, $1D, $FF, $FF, $1F, $1E, $FF
         byte $90, $06, $FF, $05, $FF, $FF, $11, $FF
         byte $FF

CIA1_KeybWrite    = $DC00
CIA1_KeybRead     = $DC01

cSYS_DelayValue   = 32
cKeybW_Row1       = $FE

KeyR              byte 0

SYS_Keyd          bytes 0 * 10 ; keyboard buffer
SYS_Ndx           byte 0   ; Count of chars in keyboard buffer
SYS_Xmax          byte 10  ; Maximum number of chars in the keyboard buffer

SYS_Shflag        byte 0   ; Shift collection (Shift=1, Commodore = 2, Control = 4)
SYS_Sfdx          byte 0   ; Previous key pressed. Keyboard Matrix Coordinate. Same value as SYS_Lstx.
SYS_Lstx          byte 0   ; Newest key Pressed (not shifts). $40 = no key.
SYS_Delay         byte 0   ; Repeat countdown. 16 to 0, so 0.25 second.
SYS_Kount         byte 0
SYS_Lstshf        byte 0

Keyb_Init
         lda #64
         sta SYS_Lstx
         sta SYS_Sfdx

         lda #cSYS_DelayValue
         sta SYS_Delay

         lda #6
         sta SYS_Kount

         lda #0
         sta SYS_Shflag
         sta SYS_Lstshf

         sta SYS_Ndx
         rts

ReadKeyb
         lda #<KeyMap1
         sta @SMC_Vec + 1
         lda #>KeyMap1
         sta @SMC_Vec + 2
         
         ; Clear Shift Flag
         lda #$40
         sta SYS_Sfdx

         lda #0
         sta SYS_Shflag

         sta CIA1_KeybWrite
         ldx CIA1_KeybRead
         cpx #$FF
         beq @Cleanup

         ldy #$00

         lda #7
         sta KeyR

         lda #cKeybW_Row1
         sta @SMC_Row + 1
@SMC_Row lda #0

         sta CIA1_KeybWrite

@Loop_Debounce
         lda CIA1_KeybRead
         cmp CIA1_KeybRead
         bne @Loop_Debounce

         ldx #7
@Loop_Col lsr
         bcs  @NextKey
         sta @SMC_A + 1

@SMC_Vec lda $FFFF,Y

         ; If <4 then is Stop or a Shift Key
         cmp #$05 
         bcs @NotShift ; Not Shift

         cmp #$03 
         beq @NotShift ; Stop Key
         
         ; Accumulate shift key types (SHIFT=1, COMM=2, CTRL=4)
         ora SYS_Shflag
         sta SYS_Shflag
         bpl @SMC_A

@NotShift sty SYS_Sfdx

@SMC_A   lda #0

@NextKey iny
         dex
         bpl @Loop_Col

         sec
         rol @SMC_Row + 1
         dec KeyR
         bpl @SMC_Row

         jmp @ProcKeyImg

; Handles the key repeat
@Process ldy SYS_Sfdx
@SMC_Key lda $FFFF,Y
         tax
         cpy SYS_Lstx
         beq @SameKey

         ldy #cSYS_DelayValue
         sty SYS_Delay     ; Repeat delay counter
         bne @Cleanup
         
@SameKey and #$7F
         ldy SYS_Delay
         beq @EndDelay
         dec SYS_Delay
         bne @Exit

@EndDelay dec SYS_Kount
         bne @Exit

         ldy #$04
         sty SYS_Kount
         ldy SYS_Ndx
         dey
         bpl @Exit

; Updates the previous key and shift storage
@Cleanup ldy SYS_Sfdx
         sty SYS_Lstx
         ldy SYS_Shflag
         sty SYS_Lstshf

         cpx #$FF
         beq @Exit
         txa
         ldx SYS_Ndx
         cpx SYS_Xmax
         bcs @Exit

         sta SYS_Keyd,X
         inx
         stx SYS_Ndx

@Exit    lda #$7F
         sta CIA1_KeybWrite
         rts

@ProcKeyImg 
         lda SYS_Shflag
         cmp #$03 ; C= + SHIFT
         bne @SetDecodeTable
         cmp SYS_Lstshf
         beq @Exit

@SetDecodeTable
         asl
         cmp #8   ; CONTROL
         bcc @Cont
         lda #$06
@Cont    tax
         lda KeyMapVec,X
         sta @SMC_Key + 1
         lda KeyMapVec + 1,X
         sta @SMC_Key + 2
         jmp @Process

; --------------------------
GetKey   lda SYS_Ndx
         bne @IsKey

@NoKey   lda #255 ; Null
         sec
         rts

@IsKey   ldy SYS_Keyd
         ldx #0
@Loop    lda SYS_Keyd + 1,X
         sta SYS_Keyd,X
         inx
         cpx SYS_Ndx
         bne @Loop 
         dec SYS_Ndx
         tya
         clc
         rts