#IFNDEF __lib_keyboard #DEFINE __lib_keyboard 1 GOTO __skip_lib_keyboard // ============================================================================ // KEYBOARD INPUT DRIVER FOR COMMODORE 64 // ============================================================================ // Direct CIA keyboard matrix reading (no IRQ required) // Uses non-interfering keyboard scan technique to avoid conflicts with // joysticks on ports 1 and 2. // // Based on code from: // https://codebase64.c64.org/doku.php?id=base:scanning_the_keyboard_without_joysticks_interfere // // This method converts keycodes to row/column values and performs double-check // scanning to ensure joystick inputs don't interfere with keyboard detection. // // Usage: // #INCLUDE "keyboard.c65" // BYTE key // key_scan(key) // SWITCH key // CASE KEY_F1 // // handle F1 // CASE KEY_F3 // // handle F3 // ENDSWITCH // ============================================================================ // CIA Port addresses WORD CONST CIA_PORTA = $DC00 // Port A - ROW selection (write) WORD CONST CIA_PORTB = $DC01 // Port B - COLUMN reading (read) WORD CONST CIA_DDRA = $DC02 // Port A Data Direction Register WORD CONST CIA_DDRB = $DC03 // Port B Data Direction Register // Key constants (returned by key_scan) BYTE CONST KEY_NONE = 0 BYTE CONST KEY_F1 = 1 BYTE CONST KEY_F3 = 2 BYTE CONST KEY_F7 = 3 BYTE CONST KEY_RUNSTOP = 4 BYTE CONST KEY_RETURN = 5 // C64 Keycode constants (for internal use) // Based on: https://www.c64-wiki.com/wiki/Keyboard BYTE CONST KEYCODE_RETURN = $01 BYTE CONST KEYCODE_F7F8 = $03 BYTE CONST KEYCODE_F1F2 = $04 BYTE CONST KEYCODE_F3F4 = $05 BYTE CONST KEYCODE_RUNSTOP = $3F // Row and column lookup tables for keyboard scanning LABEL key_row_table ASM !8 $FE, $FD, $FB, $F7, $EF, $DF, $BF, $7F ENDASM LABEL key_column_table ASM !8 $01, $02, $04, $08, $10, $20, $40, $80 ENDASM // Key history for debouncing (one byte per tracked key) BYTE key_history_f1 BYTE key_history_f3 BYTE key_history_f7 BYTE key_history_return BYTE key_history_runstop // ============================================================================ // FUNC key_check_raw // Low-level keyboard check for a specific keycode // Uses non-interfering scan method with double-check to avoid joystick conflicts // Returns: result = 1 if pressed, 0 if not pressed // This comes from here: // https://codebase64.c64.org/doku.php?id=base:scanning_the_keyboard_without_joysticks_interfere // ============================================================================ FUNC key_check_raw({BYTE keycode} io:{BYTE histv} out:{BYTE result}) ASM lda |keycode| pha lsr lsr lsr tay lda key_row_table,y sta $dc00 pla and #$07 tay lda $dc01 and key_column_table,y bne _nokey lda #$ff ; key is checked 2nd time, to be sure sta $dc00 ; joy #1 and #2 are not interfering lda $dc01 and key_column_table,y beq _nokey cmp |histv| ; history value? bne _newkey clc ; case #3, key is held down. keep history & set C=0 bcc _backy _nokey asl ; case #1, no keypress, update history value 2x & set C=0 clc !byte $24 ; BIT zero page - skips next 2-byte instruction _newkey sec ; case #2, key pressed&released. update history & set C=1 sta |histv| _backy lda #$ff sta $dc00 ; set default value lda #$7f sta $dc01 ; set default value ; Convert carry flag to result: C=1 -> pressed (1), C=0 -> not pressed (0) lda #0 rol ; shift carry into bit 0 sta |result| ENDASM FEND // ============================================================================ // FUNC key_scan // Scan keyboard and return which key is pressed // Returns KEY_* constant (KEY_NONE if no relevant key pressed) // Uses non-interfering keyboard scan to avoid joystick conflicts // ============================================================================ FUNC key_scan(out:{BYTE key_pressed}) BYTE check_result key_pressed = KEY_NONE // Set up DDR: Port A = output (rows), Port B = input (columns) ASM lda #$ff sta $dc02 // CIA_DDRA lda #$00 sta $dc03 // CIA_DDRB ENDASM // Check F1 key_check_raw(KEYCODE_F1F2, key_history_f1, check_result) IF check_result > 0 key_pressed = KEY_F1 ENDIF // Check F3 IF key_pressed == KEY_NONE key_check_raw(KEYCODE_F3F4, key_history_f3, check_result) IF check_result > 0 key_pressed = KEY_F3 ENDIF ENDIF // Check F7 IF key_pressed == KEY_NONE key_check_raw(KEYCODE_F7F8, key_history_f7, check_result) IF check_result > 0 key_pressed = KEY_F7 ENDIF ENDIF // Check RUN/STOP IF key_pressed == KEY_NONE key_check_raw(KEYCODE_RUNSTOP, key_history_runstop, check_result) IF check_result > 0 key_pressed = KEY_RUNSTOP ENDIF ENDIF // Check RETURN IF key_pressed == KEY_NONE key_check_raw(KEYCODE_RETURN, key_history_return, check_result) IF check_result > 0 key_pressed = KEY_RETURN ENDIF ENDIF FEND LABEL __skip_lib_keyboard #IFEND