Keyboard input routine BASIC

Basic and Machine Language

Moderator: Moderators

Post Reply
User avatar
Soloman
Vic 20 Amateur
Posts: 44
Joined: Fri Sep 22, 2023 1:46 am
Location: Bilthoven, Netherlan
Occupation: Data-analyst

Keyboard input routine BASIC

Post by Soloman »

Edit - Improvements in my post of January 1st.

So, I'm writing software for the unexpanded VIC-20 as a hobby (VICE emulator). I am used to the Commodore 64 and MBASIC (CP/m) where I have plenty of memory. For me it all started with MBASIC in CP/M in the early eighties. But writing programs for the VIC-20 with only 3583 bytes free is for me an attractive challenge. I'm learning 6502-assembler and the whole VIC-20-machine with all his chips-registers. Time by time I wil submit here my VIC-20-programs. To begin with, something simple and very basic, my Input-routine, to avoid the "cursed" INPUT-statement.

Excuse me when I make grammatical errors. English is not my native language (Dutch it is, Dutchmen/-women learn English at school).

Attached you find the program on a .d64-diskette. I couldn't find out how to make a .prg-file. Furthermore a listing of the subroutine. But my VICE refuses to make a viceprint.out-file. I did my settings for the printer, and I get normal reactions on OPEN 4,4 CMD 4 LIST PRINT#4 CLOSE 4, but the file isn't created. So I did a couple screenprints in a RTF-file (you can open this in WRITE or WORD).

I love to program "neat". With many REMS and thorough structural programming. But this subroutine is "crunched". I first developed it in MBASIC (32K free) with plenty of remarks. Then I converted it for the VIC20-unexpanded. I removed the REMs and spaces. A subroutine of something more than 500 byte is the result.

Using the subroutine in your program.
It starts at line 1700 and ends at 1990. I choose these lines, because I use a fixed program-"format": 10-90 Information (REMs), 100-990 Main - subroutines: 1000-1990 Init and input 2000-2990 working up the data 3000-3990 Output 4000-4990 DATA
So you call the subroutine by GOSUB 1700. But before you do that:

Parameter-variables to be filled:
B0% Maximum length of the field
B1% Type: 0=Alphanumeric, 1=Integer (No flow-type yet)

Then GOSUB. The subroutine outputs:
B0 Entered integer-field
B0$ Entered alphanumeric field
B9% Stop-flag. User wants to exit the program where the subroutine makes part of. 0=Flag down, user wants to continue, 1=Flag up, user wants to stop.

Variables used in the subroutine:
B2$ Key pressed
B2% ASCII-value key pressed
B2 Dummyvariable for garbage collection (must be done because every key added causes a new field in the memory)

Explanation of the subroutine:
1750 Init
1760 Cursor
1770 Keypress
1780-1785 Ooops, a double! I see that now.
1790 Processing the RETURN-key
1800 Processing the BACKSPACE-key
1810 Processing the key pressed by user to put up the "Exit"-flag. Now it is the `-key, under the Esc-key of the PC. But you can choose any key you like.
1820 Determine if user is trying to type further than the length wished
1830 Keys 0-9, they are always ok.
1840 If integer, minus-sign is accepted, provided the cursor is on the position of the first character
1850 In case of integer, pressed-key-examination is ready, subroutine can continue with next key
1860 Keys A-Z, ok in case of alphanumeric (programpointer in case of integer already passed)
1870-1880 (1889). These are keys that are accepted. You can modify lines between 1870 and 1889 yourself like adding keys. But beware: If you write sequential files in your program, don't accept the , for file-variables, because the comma is a seperator in datafiles.
1890 Key-examination is ready, now goto next pressing key.
1900-1920 Backspace-key further processing.
1930 Add character to string
1940 Print character
1950 Goto next key press
1960 Terminating after Enter-key
1970 Garbage collection

Entering data with the subroutine while running the program:
In case of integer you can only input numbers and an initial minus sign. De routine doesn't care if you exceed 32767. That's why the outputfield is not an integer-variable.
You can only enter characters that are permitted in the subroutne. You cannot exceed the maximum length given in the subroutine.
Only Backspace works for the editing. The `-key immidiately ends the entering without showing the character. The programs knows that the `-key is pressed by the "Exit-flag", that is up. In your program you can take the action what you want.

Weak point is that you can break with the RUN/STOP key. You can anticipate that by putting POKE 808,100 in the initialisation of your program. But then SAVE and LIST are prohibited also. With POKE 808,112 everything goes to normal again.

Attached are the listing and the subroutine on disk. When you are interested of the CP/M Mbasic version (Commodore 128), just say it.
My next contribution will be "Programming text-adventure games on the unexpanded VIC-20". I am finishing my first adventure game for the VIC, it is a battle against bytes. :D
When the program is finished, you will read about it.

Kind greetings, Soloman
Attachments
DENIAL-VIC20-INPUT SHORT.zip
(1.1 MiB) Downloaded 31 times
Last edited by Soloman on Mon Jan 01, 2024 12:09 pm, edited 1 time in total.
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: Keyboard input routine for the unexpanded VIC-20 - BASIC

Post by Mike »

Welcome!
Soloman wrote:[...] I couldn't find out how to make a .prg-file. [...] my VICE refuses to make a viceprint.out-file.
Regarding these two issues, please check out these two posts of mine about VICE VDrive to access directories on the host PC (here and here, obviously the first post is about loading, but where you can load from you also can save to ...).

Here then is the result of the "printout", done as described in the second posting, which I also ran through my PETSCII -> ASCII converter to quote any control characters (well, there aren't any in this case, due to you using CHR$() instead):

Code: Select all

10 REM PRG-NAME
20 REM PRG-DESCR.
30 REM DATE
90 :
100 REM MAIN
110 CLR
150 B0%=1
160 B1%=0
170 GOSUB 1700
980 END
990 :
1700 REM INPUT
1750 B0$="":B9%=0
1760 PRINT CHR$(18)" "CHR$(146)CHR$(157);
1770 GET B2$:IF B2$=""THEN1770
1780 B2%=ASC(B2$)
1785 B2%=ASC(B2$)
1790 IFB2%=13THEN1960
1800 IFB2%=20ANDLEN(B0$)>0THEN1900
1810 IFB2%=39THENB9%=1:GOTO1960
1820 IFLEN(B0$)=B0%THEN1760
1830 IFB2%>47ANDB2%<58THEN1930
1840 IF B2$="-"ANDLEN(B0$)=0THEN1930
1850 IFB1%=1THEN1760
1860 IFB2%>64ANDB2%<91THEN1930
1870 IFB2$="."ORB2$="@"THEN1930
1880 IFB2$=" "ORB2$="-"THEN1930
1890 GOTO1760
1900 B0$=LEFT$(B0$,LEN(B0$)-1)
1910 PRINTCHR$(20);
1920 GOTO1760
1930 B0$=B0$+B2$
1940 PRINTB2$;
1950 GOTO1760
1960 PRINT" ";
1970 B0=FRE(0)
1980 RETURN
I packaged the *.prg file and the source *.txt for download (input-short.zip).

Turns out this is pretty much how I would implement such a routine, even if I'd probably choose to defer "type" checks to the caller. If in doubt, VAL() on a string input will always succeed: it returns the first part of whatever could be regarded as numeric input. If the first character is already invalid, VAL() gives zero as result. Probably more important is a length check, so the routine does not overrun an input field of the screen mask.
I love to program "neat". With many REMS and thorough structural programming.
That could be improved though, I count 11 GOTOs from line 1790 to line 1890 ... ;)

For a comparison, here is the chapter number input routine in a text browser that I wrote quite some time ago (together with orion70):

Code: Select all

18 NR$="":CN$=STR$(CN):POKEAD+190,ASC(MID$(CN$,2)):POKEAD+191,ASC(MID$(CN$,3)):GOTO24
19 F=0:GETA$:IFA$=""THEN19
20 IFA$>="0"ANDA$<="9"ANDLEN(NR$)<2THENNR$=NR$+A$:F=1
21 IFA$=CHR$(20)ANDLEN(NR$)>0THENNR$=LEFT$(NR$,LEN(NR$)-1):F=1
22 IFA$=CHR$(13)ANDNR$<>""THENNR=VAL(NR$):IFNR>0ANDNR<=CNTHENRETURN
23 IFF=0THEN19
24 DI$=LEFT$(NR$+"{<-} ",2):POKEAD+181,ASC(MID$(DI$,1)):POKEAD+182,ASC(MID$(DI$,2))
25 SYSS,AD+160,17:GOTO19
You see it's largely similar: line 18 actually writes the maximum accepted value into the prompt and then enters the loop at line 24. In line 19 the flag F is cleared to indicate "no valid character found" and then loops until a key is pressed. Line 20 adds numeric characters until the maximum length is reached (here, only 2 characters). Line 21 handles [DEL] and line 22 handles [RETURN] - if the entered number is outside the allowed range, [RETURN] is ignored. Line 23 prematurely loops when an invalid character was input (much akin to 'continue' in C). Line 24 prepares the modified output line; line 25 prints that line and loops.

I could have eliminated that (extra) implicit GOTO in line 23 with an over-length IF by reversing the condition and putting line 24 and the SYS in line 25 into the THEN clause.

The code actually runs in a soft 40 column mode, the "left arrow" character in line 24 is printed as "_" underscore.

A similar use of such a flag variable should eliminate most of the GOTOs in your routine.
User avatar
Soloman
Vic 20 Amateur
Posts: 44
Joined: Fri Sep 22, 2023 1:46 am
Location: Bilthoven, Netherlan
Occupation: Data-analyst

Re: Keyboard input routine for the unexpanded VIC-20 - BASIC

Post by Soloman »

Mike wrote:[...] please check out these two posts of mine about VICE VDrive to access directories on the host PC (here and here, obviously the first post is about loading, but where you can load from you also can save to ...). [...]
First of all: Thank you very much for explaining how to create a .prg-file. I will try that later. The printing: There was another setting that had to be done: Peripheral devices/General and then Enable virtual devices ON. It was turned off. Then it worked! It produces a bmp-file. Later I will try your solution to produce a code that can be embedded here.

For other readers who are having the same problem: Enable virtual devices ON, Printer settings: Enable IEC device ON, Emulation type: File system, Driver: MPS-803, Output mode: Graphics.
Further check out: Host Autostart: The autostard disk image pointed in my case to a non-existing disk. I browsed here for de floppy I work in. I don't know a wrong directory bothers, but just in case.
Also: Host-Current directory. You can browse for a directory you work in. In that directory VICE drops the printed files.

@Mike: Later on the day I will look to your coding and your remarks. But it will help me certainly!

(mod: full quote of immediately preceding post shortened)
Thank you mod. I will do that too in the future.

Edit on my post: For printing list: Choose Driver Raw, not MPS-803. And then you get the file: Vice.out. And that is an ASCII-file, you can open this one with notebook. You can copy and paste it in the forum with <code>.

And always handy to make these files and store them, in case of accidents (what once happened to me).

@Mike: The VAL()-function. I discovered that too during the writing of the subsroutine. But if you must test if an alphanumeric field is numeric, that will cost you code after execution of the subroutine. You must test each character in a for..next. I like a clean field better.

Yes, there are a lot of goto's, but structured programming costs memory. I make programs to keep score of sporting clubs and accounting for myself. So I have to calculate with variables.

Your code is pretty neat and compact. I see only numbers are allowed, the chapter number. As I have to types I have to code more. The first half of my routine checks on numbers, so after that the Integer-type can jump out.

I appreciate that you think along with this ever returning issue.
User avatar
Soloman
Vic 20 Amateur
Posts: 44
Joined: Fri Sep 22, 2023 1:46 am
Location: Bilthoven, Netherlan
Occupation: Data-analyst

Re: Keyboard input routine for the unexpanded VIC-20 - BASIC

Post by Soloman »

I improved the routine. I had to do this because I am working on a weather-program. Compute!'s Gazette published a "Weather prophet"-program in the eighties. Nice program, but it was for the 64 and about predicting. I don't want to predict, more statistical.

The improvements:
1. Numeric floating point added. Before you call the subroutine (GOSUB 1700), the type is B1%: 0=alphanumeric, 1=integer, 2=floating point (B0% is max length). When you choose floating point, you can use the decimal point, but only once in the field.
2. Making a numeric variable for the output: VAL() without IF. If the contents is alphanumeric, VAL() doesn't return an error, but a contents of zero (Like Mike said)
3. A double line removed
4. Added in the beginning: A scratch and replace the program on disk (to avoid the @replace-bug), with colour-init. B0% and B0$ are used. They are used further-on in the program but for something else. B0%: 0=don't save the program, skip this, 1=save (replace) the program on disk. B0$: the name of the program, max length 16

Code: Select all

10 REM PROGRAM
20 REM DESCRIPTION
30 REM DATE
90 :
100 REM MAIN
110 PRINT CHR$(147);
120 POKE 36879,8
130 PRINT CHR$(30);
140 LET B0%=1
150 LET B0$="INPUT-SHORT"
160 IF B0%=0 THEN 300
170 PRINT "SAVING."
180 OPEN 1,8,15
200 PRINT#1,"S0:"B0$
210 CLOSE 1
220 SAVE B0$,8
300 CLR
310 PRINT "FREE MEMORY:"FRE(0)
400 LET B0%=5
410 LET B1%=2
420 GOSUB 1700
980 END
990 :
1700 REM INPUT
1750 B0$="":B9%=0:B3%=0
1760 PRINT CHR$(18)" "CHR$(146)CHR$(157);
1770 GET B2$:IF B2$=""THEN1770
1780 B2%=ASC(B2$)
1790 IFB2%=13THEN1960
1800 IFB2%=20ANDLEN(B0$)>0THEN1900
1810 IFB2%=39THENB9%=1:GOTO1960
1820 IFLEN(B0$)=B0%THEN1760
1830 IFB2%>47ANDB2%<58THEN1930
1840 IF B2$="-"ANDLEN(B0$)=0THEN1930
1845 IFB1%=2ANDB2$="."ANDB3%=0THENB3%=1:GOTO1930
1850 IFB1%=1ORB1%=2THEN1760
1860 IFB2%>64ANDB2%<91THEN1930
1870 IFB2$="."ORB2$="@"THEN1930
1880 IFB2$=" "ORB2$="-"THEN1930
1890 GOTO1760
1900 IFRIGHT$(B0$,1)="."THENB3%=0
1905 B0$=LEFT$(B0$,LEN(B0$)-1)
1910 PRINTCHR$(20);
1920 GOTO1760
1930 B0$=B0$+B2$
1940 PRINTB2$;
1950 GOTO1760
1960 LET B0=VAL(B0$)
1965 PRINT" ";
1970 B2=FRE(0)
1980 RETURN
Attached you find the disk with this routine. Of course you can use the routine for all VIC-20's with all memory-extensions, because it's doing nothing with the screen memory.

I mentioned I was busy with a text-adventure for the unexpanded VIC. But I didn't have the time to finish it in time because of family-meetings. The problem is that it is a christmas-adventure. I will finish it and I will post it here in december 2024. It's a pilot how I can write an adventure with all the limits of 3583 bytes. So far, no problems. Long ago I wrote an adventure for the 64. Memory enough. It ended in 52 blocks on disk, that's 13K without running. So I had to tackle it dramatically: less places, less things, less puzzles, less functiongadgets (like DRAW MAP). But I think it's working out.
Attachments
VIC20-DENIAL.zip
Program: INPUT-SHORT.PRG
(1.09 KiB) Downloaded 28 times
Post Reply