190 lines
5.1 KiB
Text
190 lines
5.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)
|
|
// 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
|