311 lines
8.9 KiB
Plaintext
311 lines
8.9 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
|
|
;; @ref kb::MOD "status of the modifier keys"
|
|
modifier: .res 1
|
|
.bss
|
|
;; previous scancode is used to determine if a key was released (BREAK sent previously)
|
|
;; will be $ff if the previous scancode was K_BREAK
|
|
previous_scancode: .res 1
|
|
;; 0 when no key or non-character key was pressed, otherwise character of the key (with modifiers applied)
|
|
char: .res 1
|
|
;; @ref kb::K "keycode" of the last key that was pressed or 0 if none was pressed
|
|
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 @ref kb::keycode
|
|
;; If the key is an ascii character, the corresponding ascii character is stored in @ref 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
|
|
|
|
cpx #$60 ; codes >= 60 in separate table to reduce memory consumption
|
|
bcs x_ge_60
|
|
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
|
|
modralt:
|
|
lda CHARS_MODRALT,x
|
|
bra check_char
|
|
modshift:
|
|
lda CHARS_MODSHIFT,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
|
|
|
|
x_ge_60: ; x >= $60
|
|
cpx #$90 ; only BREAK is higher than 8F, (also code table only has 8F bytes)
|
|
bcs check_release
|
|
; CHARS_NUMLOCK_OFF - CHARS_NOMOD = 60 -> no need to subtract $60 first
|
|
; CHARS_NUMLOCK_ON - CHARS_MODSHIFT = 60 -> no need to subtract $60 first
|
|
bbs kb::MOD::NUMLOCK, modifier, modshift ; if numlock active
|
|
lda CHARS_NOMOD,x
|
|
bra check_char
|
|
check_release: ; x >= $90
|
|
cpx #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"
|
|
;; numlock range characters where numlock is off
|
|
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_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_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"
|
|
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"
|