#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) // // C64 Keyboard Matrix: // $DC00 (Port A): Column select (write, active-low) // $DC01 (Port B): Row read (read, active-low) // // Usage: // #INCLUDE "keyboard.c65" // BYTE key // key_scan(key) // SWITCH key // CASE KEY_F1 // // handle F1 // CASE KEY_F3 // // handle F3 // ENDSWITCH // // // Debouncing: wait for KEY_NONE // WHILE key != KEY_NONE // key_scan(key) // WEND // ============================================================================ // 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 BYTE CONST KEY_NONE = 0 BYTE CONST KEY_F1 = 1 BYTE CONST KEY_F3 = 2 BYTE CONST KEY_F7 = 3 BYTE CONST KEY_F8 = 4 // F7 + SHIFT BYTE CONST KEY_RETURN = 5 BYTE CONST KEY_LEFT_ARROW = 6 // ============================================================================ // FUNC key_scan // Scan keyboard and return which key is pressed // Returns KEY_* constant (KEY_NONE if no relevant key pressed) // C64 Keyboard Matrix: // - Write to $DC00 (Port A) to select ROW // - Read from $DC01 (Port B) to detect COLUMN // ============================================================================ FUNC key_scan(out:{BYTE key_pressed}) BYTE col_data BYTE temp BYTE shift_held BYTE saved_ddra BYTE saved_ddrb BYTE saved_porta BYTE row0_data BYTE row1_data BYTE row6_data key_pressed = KEY_NONE shift_held = 0 // Save current DDR state saved_ddra = PEEK CIA_DDRA saved_ddrb = PEEK CIA_DDRB saved_porta = PEEK CIA_PORTA // Set up DDR: Port A = output (rows), Port B = input (columns) POKE CIA_DDRA , $FF POKE CIA_DDRB , $00 // Check F8 FIRST with two-read atomic check // Read 1: Select rows 0+1+6 simultaneously ($BC = 10111100) POKE CIA_PORTA , $BC BYTE multi_row_data multi_row_data = PEEK CIA_PORTB // Read 2: Select ONLY row 0 ($FE = 11111110) POKE CIA_PORTA , $FE col_data = PEEK CIA_PORTB // F8 detection: F7 pressed AND SHIFT pressed // F7 at Row 0, Col 3 - check in row0 data temp = col_data & $08 IF temp == 0 // F7 is pressed, now check if real SHIFT is pressed // Compare multi-row read vs row-0-only read for cols 4 and 7 // If col 4 or 7 was low in multi-row but NOT in row-0-only, it's SHIFT BYTE shift_cols shift_cols = multi_row_data & $90 // Cols 4 and 7 in multi-row read temp = col_data & $90 // Cols 4 and 7 in row 0 only read // If multi-row has a low bit that row-0-only doesn't, it's from rows 1 or 6 (SHIFT) IF shift_cols != temp key_pressed = KEY_F8 ENDIF ENDIF // If not F8, check other Row 0 keys (col_data already has row 0 from above) IF key_pressed == KEY_NONE // Check F1 (Row 0, Column 4) temp = col_data & $10 IF temp == 0 key_pressed = KEY_F1 ENDIF // Check F3 (Row 0, Column 5) IF key_pressed == KEY_NONE temp = col_data & $20 IF temp == 0 key_pressed = KEY_F3 ENDIF ENDIF // Check F7 (Row 0, Column 3) IF key_pressed == KEY_NONE temp = col_data & $08 IF temp == 0 key_pressed = KEY_F7 ENDIF ENDIF // Check RETURN (Row 0, Column 1) IF key_pressed == KEY_NONE temp = col_data & $02 IF temp == 0 key_pressed = KEY_RETURN ENDIF ENDIF // Check Left Arrow (Row 0, Column 7) IF key_pressed == KEY_NONE temp = col_data & $80 IF temp == 0 key_pressed = KEY_LEFT_ARROW ENDIF ENDIF ENDIF // Always restore saved DDR and port state POKE CIA_PORTA , saved_porta POKE CIA_DDRA , saved_ddra POKE CIA_DDRB , saved_ddrb FEND LABEL __skip_lib_keyboard #IFEND