6502-OS/programs/ps2_keyboard_text_handler.s65
2024-01-09 02:29:18 +01:00

307 lines
8.4 KiB
Plaintext

.include "ps2_keyboard_text_handler.h65"
Export kb, init, char, keycode
Export kb, CHARS_NOMOD, CHARS_MODRALT, CHARS_MODSHIFT, CHARS_NUMLOCK_OFF, CHARS_NUMLOCK_ON
ExportZp kb, modifier
.zeropage
modifier: .res 1
.bss
previous_scancode: .res 1 ; all 1 if previous_scancode is break
char: .res 1
keycode: .res 1
.code
;;********************************************************************************
;; @function Initialize the keyboard handler
;; @returns Z: Z = 1 => success, Z = 0 => failure
;; @details:
;; Initializes the PS/2 keyboard driver and the handler.
;; If any PS/2 command fails, init returns with Z = 0. The failed command (and parameter) can be loaded from `ps2kb::send_cmd` and `ps2kb::send_data`
;; After init, the keyboard will be able to send scancodes.
;; @modifies A, X, Y
;;********************************************************************************
.proc init
stz modifier
stz char
stz keycode
stz previous_scancode
jsr ps2kb::init
; init & reset
ps2kb_CmdSelfTest
ps2kb_WaitFinishCmd
lda ps2kb::cmd_response+1
cmp #$aa
bne fail
; set set 3
ps2kb_CmdSetScancodeSet 3
ps2kb_WaitFinishCmd
lda ps2kb::cmd_response+1
cmp #ps2kb::ACK
bne fail
; toggle-behaving keys
ldx #kb::K::CAPSLOCK
jsr set_make
ldx #kb::K::NUMLOCK
jsr set_make
ldx #kb::K::SCROLLLOCK
jsr set_make
; modifiers
ldx #kb::K::LEFTSHIFT
jsr set_make_release
ldx #kb::K::RIGHTSHIFT
jsr set_make_release
ldx #kb::K::LEFTCTRL
jsr set_make_release
ldx #kb::K::RIGHTCTRL
jsr set_make_release
ldx #kb::K::LEFTALT
jsr set_make_release
ldx #kb::K::RIGHTALT
jsr set_make_release
ldx #kb::K::LEFTMETA
jsr set_make_release
ldx #kb::K::RIGHTMETA
jsr set_make_release
ps2kb_CmdEnable
ps2kb_WaitFinishCmd
lda ps2kb::cmd_response
cmp #ps2kb::ACK
bne fail
StoreDByte process_scancode, ps2kb::scancode_handler
jsr ps2kb::begin_receive
lda #0 ; set Z = success
fail:
rts
set_make:
; x must be set to scancode
lda #$fd
bra set
set_make_release:
; x must be set to scancode
lda #$fc
set:
ldy #0
jsr ps2kb::send_command
ps2kb_WaitFinishCmd
lda ps2kb::cmd_response+1
cmp #ps2kb::ACK
bne fail
rts
.endproc
;;********************************************************************************
;; @function Process a scancode
;; @details
;; Update modifier bits if a mod key is pressed.
;; If the key is not a mod key, the keycode is stored in kb::keycode
;; If the key is an ascii character, the corresponding ascii character is stored in kb::char
;; @modifies A, X
;;********************************************************************************
.proc process_scancode
; check how this scancode needs to be interpreted
ldx ps2kb::scancode
bit previous_scancode
jmi break_key ; bit 7 set = BREAK
cmp #$90 ; only BREAK is higher than 8F, (also code table only has 8F bytes)
bcs check_release
cmp #$60 ; codes >= 60 in separate table to reduce memory consumption
bcs upper_range
bbs kb::MOD::SHIFT, modifier, modshift ; if shift active
bbs kb::MOD::RALT, modifier, modralt ; if ralt active
; load from the correct table, if 0 => non-char, if 1 => non-char but mod, else char
nomod:
lda CHARS_NOMOD,x
bra check_char
upper_range:
bbs kb::MOD::NUMLOCK, modifier, modnumlock ; if numlock active
; numlock off
lda CHARS_NUMLOCK_OFF,x
bra check_char
modnumlock:
lda CHARS_NUMLOCK_ON,x
bra check_char
modshift:
lda CHARS_MODSHIFT,x
bra check_char
modralt:
lda CHARS_MODRALT,x
check_char:
beq not_mod ; 0 => not mod and not char
cmp #1 ; 1 => mod
beq is_mod
@char: ; store char
sta char
not_mod: ; store keycode if not mod
stx keycode
_rts:
rts
check_release:
cmp #kb::K_BREAK
bne _rts
lda #$ff
sta previous_scancode
rts
is_mod:
; check which mod
cpx #kb::K::LEFTSHIFT
beq set_shift
cpx #kb::K::RIGHTSHIFT
beq set_shift
cpx #kb::K::RIGHTALT
beq set_rightalt
cpx #kb::K::LEFTALT
beq set_leftalt
cpx #kb::K::RIGHTMETA
beq set_meta
cpx #kb::K::LEFTMETA
beq set_meta
cpx #kb::K::RIGHTCTRL
beq set_ctrl
cpx #kb::K::LEFTCTRL
beq set_ctrl
cpx #kb::K::CAPSLOCK
beq toggle_capslock
cpx #kb::K::NUMLOCK
beq toggle_numlock
cpx #kb::K::SCROLLLOCK
beq toggle_scrolllock
; a real keycode and not a released keycode, twobyte or release scancode
set_ctrl:
smb kb::MOD::CTRL, modifier
rts
set_meta:
smb kb::MOD::META, modifier
rts
set_leftalt:
smb kb::MOD::LALT, modifier
rts
set_rightalt:
smb kb::MOD::RALT, modifier
rts
set_shift: ; process shift
bbs kb::MOD::CAPSLOCK, modifier, @unset_shift ; CAPSLOCK unset shift when capslock is on
@set_shift:
smb kb::MOD::SHIFT, modifier
rts
@unset_shift:
rmb kb::MOD::SHIFT, modifier
rts
toggle_numlock: ; toggle numlock
lda modifier
eor #kb::MOD::NUMLOCK
sta modifier
bra update_leds
toggle_scrolllock: ; toggle numlock
lda modifier
eor #kb::MOD::SCROLLLOCK
sta modifier
bra update_leds
toggle_capslock: ; toggle capslock & shift
lda modifier
eor #(kb::MOD::CAPSLOCK | kb::MOD::SHIFT)
sta modifier
; fallthrough
load_update_leds:
lda modifier
update_leds:
and #%00000111 ; only bottom 3 bits allowed - otherwise command fails
tax
ps2kb_CmdSetLeds
rts
.endproc
;;********************************************************************************
;; @details
;; Unset modifier bits if a mod key is released.
;; @param X: The scancode
;; @modifies:
;;********************************************************************************
.proc break_key
; rmb kb::PREVIOUS::BREAK, kb::previous_scancode
stz previous_scancode
; check mod keys
cpx #kb::K::LEFTSHIFT
beq unset_shift
cpx #kb::K::RIGHTSHIFT
beq unset_shift
cpx #kb::K::RIGHTALT
beq unset_rightalt
cpx #kb::K::LEFTALT
beq unset_leftalt
cpx #kb::K::RIGHTMETA
beq unset_meta
cpx #kb::K::LEFTMETA
beq unset_meta
cpx #kb::K::RIGHTCTRL
beq unset_ctrl
cpx #kb::K::LEFTCTRL
rts
unset_shift: ; process shift
bbs kb::MOD::CAPSLOCK, modifier, @set_shift ; set shift when capslock is on
rmb kb::MOD::SHIFT, modifier ; unset if capslock is off
rts
@set_shift:
smb kb::MOD::SHIFT, modifier
rts
unset_ctrl:
rmb kb::MOD::CTRL, modifier
rts
unset_meta:
rmb kb::MOD::META, modifier
rts
unset_leftalt:
rmb kb::MOD::LALT, modifier
rts
unset_rightalt:
rmb kb::MOD::RALT, modifier
rts
.endproc
.rodata
.align 256
CHARS_NOMOD:
.byte "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00^\x00"
.byte "\x00\x01\x01<\x01q1\x00\x00\x01ysaw2\x00"
.byte "\x00cxde43\x00\x00 vftr5\x00"
.byte "\x00nbhgz6\x00\x00\x01mju78\x00"
.byte "\x00,kio09\x00\x00.-l\xEFp\xE2\x00"
.byte "\x00\x00\xE1#\xF5`\x00\x00\x01\x01\x00\x00\x00\x00\x00\x01"
CHARS_MODSHIFT:
.byte "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xDF\x00"
.byte "\x00\x01\x01>\x01Q!\x00\x00\x01YSAW\"\x00"
.byte "\x00CXDE$\xED\x00\x00 VFTR%\x00"
.byte "\x00NBHGZ&\x00\x00\x01MJU/(\x00"
.byte "\x00;KIO=)\x00\x00:_L\xEFP\xE2\x00"
.byte "\x00\x00\xE1'\xF5`\x00\x00\x01\x01\x00\x00\x00\x00\x00\x01"
CHARS_MODRALT:
.byte "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\x00"
.byte "\x00\x01\x01|\x01\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00"
.byte "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
.byte "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00{[\x00"
.byte "\x00\x00\x00\x00\x00}]\x00\x00\xA5\xB0\x00\x00\x00\x00\x00"
.byte "\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x00\x00\x00\x00\x00\x01"
CHARS_NUMLOCK_OFF:
.byte "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
.byte "\x00\x00\x00\x00\x00\x00\x01/\x00\x00\x00\x00+\x00*\x00"
.byte "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x00-\x00"
CHARS_NUMLOCK_ON:
.byte "\x00\x00\x00\x00\x00\x00\x00\x00\x001\x0047\x00\x00\x00"
.byte "0.2568\x01\x00\x00\x003\x00\x009\x00\x00"
.byte "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x00\x00\x00"