How to read the keyboard and joystick at the same time
Re: How to read the keyboard and joystick at the same time
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
-
- Microbot
- Posts: 112
- Joined: Mon Apr 13, 2020 3:07 pm
Re: How to read the keyboard and joystick at the same time
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
Re: How to read the keyboard and joystick at the same time
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
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
Re: How to read the keyboard and joystick at the same time
;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
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 !!!
- 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
This is how I do it in Yankee:
(kji is stored as part of self-modifying code (LD A,0); hence the +1.)
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
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.
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.
Re: How to read the keyboard and joystick at the same time
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.
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 !!!
Re: How to read the keyboard and joystick at the same time
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
Re: How to read the keyboard and joystick at the same time
Yes.
What happens, if there is modern Spectrum, which supports joystick with additional buttons, mapped to bits 7 and 6.
Re: How to read the keyboard and joystick at the same time
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.
Re: How to read the keyboard and joystick at the same time
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.
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.
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
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.
Re: How to read the keyboard and joystick at the same time
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.
Re: How to read the keyboard and joystick at the same time
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
Re: How to read the keyboard and joystick at the same time
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.
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