How to read the keyboard and joystick at the same time

The place for codemasters or beginners to talk about programming any language for the Spectrum.
Post Reply
User avatar
Morkin
Bugaboo
Posts: 3251
Joined: Mon Nov 13, 2017 8:50 am
Location: Bristol, UK

Re: How to read the keyboard and joystick at the same time

Post by Morkin »

I'm actually quite intrigued now about whether any (original, e.g. 80s) games let you use, and switch between, keyboard or Kempston controls in the middle of a game.
My Speccy site: thirdharmoniser.com
Patrik Rak
Microbot
Posts: 112
Joined: Mon Apr 13, 2020 3:07 pm

Re: How to read the keyboard and joystick at the same time

Post by Patrik Rak »

Bubu wrote: Thu Jan 20, 2022 4:54 pm The thing is that I don't want the gamer have to choose his/her device method.
Check what Zynaps does - it automatically switches to whichever joystick you use. It can even toggle between cursor and sinclair joystick depending on if you press 5 or 9, respectively.

Patrik
highrise
Manic Miner
Posts: 296
Joined: Fri Mar 20, 2020 11:29 pm

Re: How to read the keyboard and joystick at the same time

Post by highrise »

Asteroids RX and Snowed Under both have the ability to detect the kempston joystick. The player can use either at any time. Manic Miner also does this I believe.

The solution is actually quite simple. You set a single byte for your inputs. Each bit represents a different input. I usually start with bit 0 as right, bit 1 as left and so on. This is because it matches the Kempston inputs as well.

So then you check the keybooard and the joystick and set your bits according to the inputs. This way there's no doubling up. Then in the game you just read that byte instead of the keyboard or the joystick.

You can run this code to detect the kempston joystick and set a byte so it only has to be run once at game start. The rest I'm sure you can figure out :)

;see if kempston is connected

checkforkempston:
ld bc,31
xor a
ld (kempstonconnected),a ; reset
checkforkempstonloop:
in e,(c)
or e
djnz checkforkempstonloop
and $20
ret nz
ld a,1
ld (kempstonconnected),a
ret

kempstonconnected defb 0
User avatar
Bubu
Manic Miner
Posts: 542
Joined: Fri Apr 02, 2021 8:24 pm
Location: Spain

Re: How to read the keyboard and joystick at the same time

Post by Bubu »

;see if kempston is connected

checkforkempston:
ld bc,31
xor a
ld (kempstonconnected),a ; reset
checkforkempstonloop:
in e,(c) ; <--------------shouldn't it be in A, (c) ???
or e ; <------------------or e is for what???
djnz checkforkempstonloop ; <-------------do you loop 256 times??? (as b starts with 0)
and $20 ; <---------------shouldn't it be and $1F ???
ret nz ; <-------------shouldn't it be ret z ???
ld a,1
ld (kempstonconnected),a
ret

kempstonconnected defb 0
If something works, don't touch it !!!! at all !!!
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2640
Joined: Mon Nov 13, 2017 3:16 pm

Re: How to read the keyboard and joystick at the same time

Post by Ast A. Moore »

This is how I do it in Yankee:

Code: Select all

	halt			;ensure the floating bus returns 255 if no KJ IF connected
	xor a			;test port 0x1f, not 0xFF1F
	in a,(31)		;read Kempston joystick port
	inc a			;if all bits are high, then no Kempston joystick is present
	ld (kji+1),a		;set KJI flag (0 if no KJ found; anything else otherwise)
	ret nz			;and go on disabling the menu item
(kji is stored as part of self-modifying code (LD A,0); hence the +1.)
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
User avatar
Bubu
Manic Miner
Posts: 542
Joined: Fri Apr 02, 2021 8:24 pm
Location: Spain

Re: How to read the keyboard and joystick at the same time

Post by Bubu »

Ast A. Moore, if no kempston is attached, then is the read value 0x00 or 0xFF?
Another thing, the Kempston address is XX31, isn't it? So I think it doesn't matter the high byte of the port, so "xor a" wouldn't be necessary.
If something works, don't touch it !!!! at all !!!
highrise
Manic Miner
Posts: 296
Joined: Fri Mar 20, 2020 11:29 pm

Re: How to read the keyboard and joystick at the same time

Post by highrise »

The code I posted checks the port for all combinations to ensure that the joystick is definitely connected. It uses e instead of a so that the result will not be zero if anything except zero is encountered on all reads. You only need to run it once when the game loads, because the flag is then set. We should assume that the player is not moving the joystick or pressing a button just as the game has loaded, which I think is not likely. Feel free to run the code yourself to understand how it works ;)
User avatar
Bedazzle
Manic Miner
Posts: 303
Joined: Sun Mar 24, 2019 9:03 am

Re: How to read the keyboard and joystick at the same time

Post by Bedazzle »

Sol_HSA wrote: Thu Jan 20, 2022 1:22 pm Wasn't kempston also inverted compared to the keyboard? (active high/active low)
Yes.
Sol_HSA wrote: Thu Jan 20, 2022 1:22 pm What happens if you read from kempston when there is no kempston?
What happens, if there is modern Spectrum, which supports joystick with additional buttons, mapped to bits 7 and 6. :)
User avatar
Bedazzle
Manic Miner
Posts: 303
Joined: Sun Mar 24, 2019 9:03 am

Re: How to read the keyboard and joystick at the same time

Post by Bedazzle »

Bubu wrote: Thu Jan 20, 2022 10:12 pm Ast A. Moore, if no kempston is attached, then is the read value 0x00 or 0xFF?
On some devices random byte is read if there is no kempston.
One of ways detecting kempston is to read port in a loop, then check if there are impossible combinations for joystick - for example, "up" and "down" simultaneously, or "left" + "right". If one of combinations is present, then there definitely is no kempston interface.
User avatar
RMartins
Manic Miner
Posts: 776
Joined: Thu Nov 16, 2017 3:26 pm

Re: How to read the keyboard and joystick at the same time

Post by RMartins »

My code for handling several joysticks and Keyboard from Extruder is free to use.

Reading and acting on the inputs should always be 2 different things.

All these functions return in register A the input in the same format as Kempston (1 when active) , for every Joystick or keyboard setup, so the control code, will only need to check the 5 supported inputs: LEFT, RIGHT, UP, DOWN and FIRE.

Code: Select all

; Same definition as KEMPSTON
CTRL_FIRE	EQU #10	;	Bit4 = FIRE1		returns 1 when ACTIVE, 0 otherwise
CTRL_UP		EQU #08	;	Bit3 = UP			returns 1 when ACTIVE, 0 otherwise
CTRL_DOWN	EQU #04	;	Bit2 = DOWN			returns 1 when ACTIVE, 0 otherwise
CTRL_LEFT	EQU #02	;	Bit1 = LEFT			returns 1 when ACTIVE, 0 otherwise
CTRL_RIGHT	EQU #01	;	Bit0 = RIGHT		returns 1 when ACTIVE, 0 otherwise
There is a function readKeyboard, that reads the 8 bytes to cover the entire keyboard, only once, and then the Keyboard_driver, can choose what specific keys to look at. This function can be called outside of Keyboard_driver, and comment the call int the beginning of the function, if there are several things requiring the keyboard input, since we only need to read that once every frame.


It's always better, to make the code work in layers, separated by interfaces (with specific data structures).

NOTE: I have not used Kempston detection code, I make the user decide using the keyboard, somewhere before play.
However, if any detection code is run, it should be run in the beginning only to enable/disable the use of the Kempston_driver.
User avatar
RMartins
Manic Miner
Posts: 776
Joined: Thu Nov 16, 2017 3:26 pm

Re: How to read the keyboard and joystick at the same time

Post by RMartins »

Bedazzle wrote: Sun Jan 23, 2022 8:27 am
Bubu wrote: Thu Jan 20, 2022 10:12 pm Ast A. Moore, if no kempston is attached, then is the read value 0x00 or 0xFF?
On some devices random byte is read if there is no kempston.
...
Any ZX will read "garbage", if the reading is done just after the ULA read the pixel and attribute data to render the display.
This is what is known as floating bus, so you want to avoid that.

So you should always read during the top border timing (easier to sync to using interrupt) or bottom border area, to get consistent results.
Dr beep
Manic Miner
Posts: 375
Joined: Mon Oct 01, 2018 8:53 pm

Re: How to read the keyboard and joystick at the same time

Post by Dr beep »

Code: Select all

?   * TORNADO *                                                 
           ORG  50000                                           
           DUMP 50000                                           
                                                                
           LD   C,255             ; preset for test or keyboard 
           XOR  A                                               
           IN   A,(31)            ; read kempston               
           CP   C                 ; test used                   
           JR   NZ,kempused       ; kempston used               
                                                                
; Now we read the keyboard                                      
; fuplr = ZQAOP                                                 
                                                                
           LD   B,5               ; 5 keys fudlr                
           LD   HL,keytab         ; the table with keys to check
bloop      LD   A,(HL)            ; get in port                 
           INC  HL                                              
           IN   A,(254)                                         
           AND  (HL)              ; test against key            
           JR   Z,key                                           
           SCF                    ; signal key NOT pressed      
key        RL   C                 ; shift bit a position        
           INC  HL                ; goto next in                
           DJNZ bloop             ; do all keys                 
           LD   A,C               ; result to A                 
                                                                
; here A holds ---fudlr where a 0 is key used                   
kempused   NOP                    ; your move routine comes here
           RET                                                  
                                                                
keytab     DEFB %11111110         ; SH-V                        
           DEFB %00000010         ; position Z                  
                                                                
           DEFB %11111011         ; Q-T                         
           DEFB %00000001         ; pos Q                       
                                                                
           DEFB %11111101         ; A-G                         
           DEFB %00000001         ; pos A                       
                                                                
           DEFB %11011111         ; Y-P                         
           DEFB %00000010         ; pos O                       
                                                                
           DEFB %11011111         ; Y-P                         
           DEFB %00000001         ; pos P                       

User avatar
ketmar
Manic Miner
Posts: 613
Joined: Tue Jun 16, 2020 5:25 pm
Location: Ukraine

Re: How to read the keyboard and joystick at the same time

Post by ketmar »

just for fun, dug up some of my old code, and thrown together into the small demo.

what's inside:
* universal "read stick" routine, that works both with keyboard, and with kempston
* the routine is using scan tables, and keys can be redefined (demo includes "redefine keys" option)
* you can read more than one "stick" with different tables (demo allows to read both keyboard and kempston)
* .tap to test, and asm source code
* public domain

also, put the code under the spoiler, so it won't disappear with a file hosting in the future.
Spoiler

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
Post Reply