156 lines
4.1 KiB
Text
156 lines
4.1 KiB
Text
|
|
#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
|