Code: Select all
; coded by Ketmar // Invisible Vector
; public domain
org 32768
main_entry:
halt
call TestKempstonJ
ld a,1
ld (curr_choice),a
dec a
ld (allow_key_kempston),a
ld a,(kempston_here)
or a
jr z,.nokj
ld a,2
ld (curr_choice),a
dec a
ld (allow_key_kempston),a
.nokj:
restart_main_menu:
xor a
out (#fe),a
ld hl,#5800
ld de,#5801
ld bc,767
ld (hl),a
ldir
ld hl,#4000
ld de,#4001
ld bc,6143
ld (hl),a
ldir
; open channel #2 for printing
ld a,2
call #1601
menu_loop:
;call reset_choices
ld a,(curr_choice)
call set_active_choice
ld hl,menu_text
call printstr
ld hl,menu_text_start
call printstr
; setup scan table
ld a,(curr_choice)
dec a
ld c,a
; *5
add a,a
add a,a
add a,c
ld b,0
ld c,a
ld hl,keystick_table_kb
add hl,bc
ld (active_scan_table+1),hl
.wait_release:
call ReadAnyKey
jr c,.wait_release
.wait_press:
call ReadAnyKeyASCII
jr nc,.wait_press
cp '0'
jr z,start_test
cp '1'
jr c,.not_a_choice
cp '5'
jr nc,.not_a_choice
; new choice
sub a,'0'
ld (curr_choice),a
jr menu_loop
.not_a_choice:
cp a,'5'
jr nz,.not_redefine
; set keyboard
ld a,1
ld (curr_choice),a
call doRedefine
jr menu_loop
.not_redefine:
cp 'X'
jr nz,.not_toggle_x
ld a,(allow_key_kempston)
xor #01
ld (allow_key_kempston),a
jr menu_loop
.not_toggle_x:
jr menu_loop
curr_choice: defb 1
allow_key_kempston: defb 0
start_test:
ld a,7
.fade_loop:
halt
ld hl,#5800
ld de,#5801
ld bc,767
ld (hl),a
ldir
halt
halt
sub a,1
jr nc,.fade_loop
ld hl,#4000
ld de,#4001
ld bc,6143
ld (hl),0
ldir
ld hl,#5800
ld de,#5801
ld bc,767
ld (hl),7
ldir
xor a
ld (txt_char+1),a
ld (txt_char+2),a
.move_loop:
ld hl,txt_char
call printstr
; wait
xor a
ld (stick_state),a
;call read_controls
halt
;call read_controls
halt
call read_controls
halt
call read_controls
; erase
ld a,32
ld (txt_char_end-3),a
xor a
ld (txt_char_end-4),a
ld hl,txt_char
call printstr
ld a,'@'
ld (txt_char_end-3),a
ld a,1
ld (txt_char_end-4),a
; check movement
ld a,(stick_state)
ld c,a
bit 0,c ; fire
jp nz,restart_main_menu
bit 4,c
call nz,.do_left
bit 3,c
call nz,.do_right
bit 2,c
call nz,.do_up
bit 1,c
call nz,.do_down
jr .move_loop
.do_left:
ld a,(txt_char+2)
sub a,1
ret c
ld (txt_char+2),a
ret
.do_right:
ld a,(txt_char+2)
inc a
cp 32
ret z
ld (txt_char+2),a
ret
.do_up:
ld a,(txt_char+1)
sub a,1
ret c
ld (txt_char+1),a
ret
.do_down:
ld a,(txt_char+1)
inc a
cp 21
ret z
ld (txt_char+1),a
ret
txt_char:
defm 22,0,0, 16,7, 17,0, 19,0, 20,1
defm "@"
defb 20,0|0x80
txt_char_end:
;; LRUDF; F is #01
stick_state: defb 0
read_controls:
active_scan_table:
ld hl,0 ; will be modified by the main code
call readStick
ld hl,stick_state
or (hl)
ld (hl),a
; scan kempston?
ld a,(allow_key_kempston)
or a
ret z
; already kempston?
ld a,(curr_choice)
cp 2
ret z
ld hl,keystick_table_kempston
call readStick
ld hl,stick_state
or (hl)
ld (hl),a
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; in:
;; A: choice (1-4)
set_active_choice:
push af
call reset_choices
ld a,(allow_key_kempston)
or a
jr z,.skp
ld ix,menu_text_xkk
call .fix_it
.skp:
pop af
ld ix,menu_text_1kb
dec a
jr z,.fix_it
ld ix,menu_text_2kj
dec a
jr z,.fix_it
ld ix,menu_text_3cr
dec a
jr z,.fix_it
ld ix,menu_text_4sc
dec a
jr z,.fix_it
ret
.fix_it:
ld (ix+4),1
ld (ix+6),6
ld (ix+8),1
ret
reset_choices:
ld hl,menu_text
.loop:
ld a,(hl)
inc hl
cp #80
ret nc
cp a,16
jr z,.fix_ink
cp a,17
jr z,.fix_paper
cp a,19
jr z,.fix_bright
cp a,22
jr z,.skip_at
; skip special codes
cp a,16
jr c,.loop
cp a,22
jr nc,.loop
; skip arg
inc hl
jr .loop
.fix_ink:
ld (hl),7
inc hl
jr .loop
.fix_paper:
ld (hl),0
inc hl
jr .loop
.fix_bright:
ld (hl),0
inc hl
jr .loop
.skip_at:
inc hl
inc hl
jr .loop
;; special codes:
;; 16: ink
;; 17: paper
;; 18: flash
;; 19: bright
;; 20: inverse
;; 21: over
;; 22: at
menu_text:
menu_text_1kb:
defm 22,2,2, 17,0, 16,7, 19,0, "1. KEYBOARD"
menu_text_2kj:
defm 22,3,2, 17,0, 16,7, 19,0, "2. KEMPSTON"
menu_text_3cr:
defm 22,4,2, 17,0, 16,7, 19,0, "3. CURSOR "
menu_text_4sc:
defm 22,5,2, 17,0, 16,7, 19,0, "4. SINCLAIR"
defm 22,6,2, 17,0, 16,7, 19,0, "5. REDEFINE"
menu_text_xkk:
defx 22,10,2, 17,0, 16,7, 19,0, "X. ALLOW KEYBOARD+KEMPSTON"
; so "attr normalizer" won't touch it
menu_text_start:
defx 22,8,2, 17,0, 16,6, 19,0, "0. START TEST"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; print string (last char has bit 7 set)
printstr:
ld a,(hl)
and #7F
rst #10
ld a,(hl)
inc hl
and #80
jr z,printstr
ret
;; bit 0: kempston joystick is present
kempston_here: DEFB 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; test for kempston joystick
;; interrupts must be enabled
;; out:
;; a: 1 if kj is here or 0
;; f: z flag set: no kempston joystick
;; also sets `kempston_here`
TestKempstonJ:
; zero flag
xor a
ld (kempston_here),a
; wait for the interrupt to avoid floating bus issue
halt
in a,(#1F)
; #ff? nothing's here
inc a
ret z
; test for some invalid values
dec a
push bc
ld c,a
and #E0
jr nz,.noj
ld a,c
and #03
cp #03
jr z,.noj ; left & right pressed simultaneously. ???
ld a,c
and #0C
cp #0C
jr z,.noj ; up & down pressed simultaneously. ???
ld a,1
ld (kempston_here),a
pop bc
ret
.noj:
xor a
pop bc
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; scanner starts here
;;
; table of all ports (keyboard and kempston)
chan_port_table:
DEFW #F7FE
DEFW #FBFE
DEFW #FDFE
DEFW #FEFE
DEFW #EFFE
DEFW #DFFE
DEFW #BFFE
DEFW #7FFE
DEFW #001F
; various predefined keys
; left,right,up,down,fire
keystick_table_kb:
DEFB #29,#28,#08,#10,#38 ; "o","p","q","a","spc"
keystick_table_kempston:
DEFB #41,#40,#43,#42,#44 ; kempston joystick
keystick_table_cursor:
DEFB #04,#22,#23,#24,#20 ; "5","8","7","6","0" -- cursor joystick
keystick_table_sinclair:
DEFB #24,#23,#21,#22,#20 ; "6","7","9","8","0" -- sinclair joystick
keynames:
db "12345",0,0,0
db "QWERT",0,0,0
db "ASDFG",0,0,0
db 30,"ZXCV",0,0,0
db "09876",0,0,0
db "POIUY",0,0,0
db 13,"LKJH",0,0,0
db 32,31,"MNB"
; if you want to make your own (or create redefine keys)
; keyboard layout:
; #00-#04: 12345
; #08-#0C: qwert
; #10-#14: asdfg
; #18-#1C: Czxcv
; #20-#24: 09876
; #28-#2C: poiuy
; #30-#34: Elkjh
; #38-#3C: BSmnb
; #40-#44: kempston: right,left,down,up,fire
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; find pressed key
;; out:
;; a: key code or #ff
;; f: dead
;; carry: set if key was pressed
ReadAnyKey:
push hl,bc
ld hl,chan_port_table-1
ld bc,#0800
.nextrow:
inc hl
inc hl
ld a,(hl)
in a,(#fe)
cpl
and #1f
jr z,.nokey
dec c
.findx:
inc c
rra
jr nc,.findx
ld a,c
jr .quit
.nokey:
ld a,c
xor #08
bit 3,a
jr nz,.noinc
add a,#10
.noinc:
ld c,a
djnz .nextrow
ld a,#ff
or a
.quit:
pop bc,hl
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; find pressed key
;; out:
;; a: key code or #ff
;; f: dead
;; carry: set if key was pressed
ReadAnyKeyASCII:
call ReadAnyKey
ret nc
push hl
ld hl,keynames
add a,l
ld l,a
ld a,h
adc a,0
ld h,a
ld a,(hl)
pop hl
cp #ff ; guaranteed to set carry flag
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; read input using `keystick_table`
;; in:
;; HL: ptr to channel info (keystick_table)
;; out:
;; AF,DE,B: destroyed
;; HL: ptr to next channel info
;; A, C: state (LRUDF; F is #01)
;; Z is set if nothing's pressed
readStick:
ld bc,#0500 ; 5 "keys" per channel
.stick_loop:
ld a,(hl)
rra
rra
and #1E
ld e,a
ld d,#00
ld a,(hl)
inc hl
push hl
ld hl,chan_port_table
add hl,de
ld d,a
push bc
ld c,(hl)
inc hl
ld b,(hl)
in a,(c)
inc b
dec b
jr Z,.kempston
; inverse bits for keyboard reading
cpl
.kempston:
ld e,a
pop bc
pop hl
ld a,d
and #07
jr z,.stick_2
.stick_1:
rr e
dec a
jr nz,.stick_1
.stick_2:
rr e
rl c
djnz .stick_loop
ld a,c
or a
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; redefine keys
;;
txtSS: defx "SS"
txtCS: defx "CS"
txtSP: defx "SP"
txtRT: defx "RET"
txt_left:
defx 22,16,8, 17,0, 16,7, 19,0, "LEFT : "
txt_right:
defx 22,17,8, 17,0, 16,7, 19,0, "RIGHT: "
txt_up:
defx 22,18,8, 17,0, 16,7, 19,0, "UP : "
txt_down:
defx 22,19,8, 17,0, 16,7, 19,0, "DOWN : "
txt_fire:
defx 22,20,8, 17,0, 16,7, 19,0, "FIRE : "
txt_confirm:
defx 22,21,8, 17,1, 16,6, 19,1, "OK (Y/N)?"
clear_redefine_area:
; just clear the bottom screen part, why not
ld hl,scrattr8x8(0,8*2)
ld de,scrattr8x8(1,8*2)
ld bc,32*8-1
ld (hl),7
ldir
ld hl,scraddr8x8(0,8*2)
ld de,scraddr8x8(1,8*2)
ld bc,2047
ld (hl),0
ldir
ret
new_keys: defb 0,0,0,0,0
doRedefine:
call clear_redefine_area
; clear keys
ld hl,new_keys
ld de,new_keys+1
ld bc,4
ld (hl),0xff
ldir
; left
ld de,new_keys
ld hl,txt_left
call .read_key
; right
ld de,new_keys+1
ld hl,txt_right
call .read_key
; up
ld de,new_keys+2
ld hl,txt_up
call .read_key
; down
ld de,new_keys+3
ld hl,txt_down
call .read_key
; fire
ld de,new_keys+4
ld hl,txt_fire
call .read_key
; confirmation
ld hl,txt_confirm
call printstr
.wait_release_confirm:
call ReadAnyKey
jr c,.wait_release_confirm
.wait_yes_no:
call ReadAnyKeyASCII
jr nc,.wait_yes_no
cp 'N'
jr z,doRedefine
cp 'Y'
jr nz,.wait_release_confirm
; copy new keys
ld hl,new_keys
ld de,keystick_table_kb
ld bc,5
ldir
call clear_redefine_area
ret
.read_key:
push de
call printstr
.wait_release:
call ReadAnyKey
jr c,.wait_release
.wait_press:
call ReadAnyKey
jr nc,.wait_press
; check if we already have such key
ld hl,new_keys
ld b,5
.check_loop:
cp (hl)
jr z,.wait_release ; duplicate
inc hl
djnz .check_loop
; not a duplicate, store it
pop de
ld (de),a
; and print key name
ld hl,keynames
add a,l
ld l,a
ld a,h
adc a,0
ld h,a
ld a,(hl)
cp 33
jr nc,.name_char
ld hl,txtRT
cp 13
jr z,.nameok
ld hl,txtCS
cp 30
jr z,.nameok
ld hl,txtSS
cp 31
jr z,.nameok
ld hl,txtSP
;cp 32
;jr z,.nameok
.nameok:
call printstr
ret
.name_char:
rst #10
ret