;NuInput 2.1, December 2011 ;by Ivan X, ivan@ivanx.com, http://appleii.ivanx.com ;NuInput was introduced at KansasFest 2010, http://www.kansasfest.org/ ;License terms: WTFPL (http://sam.zoy.org/wtfpl/) with the following ; exception: somewhere in your program or documentation, include the ; phrase "NuInput by Ivan Drucker" or equivalent language, e.g.: ; 63999 REM includes NuInput by Ivan Drucker ; To the person reading this source code: ; Under the hood, NuInput 2.1 has two design goals: ; - complete relocatability (can be run from any memory address) ; - as many features as possible in as few bytes as possible, with a maximum of 512 ; NuInput assembles using a heavily modified version of the 6502asm.com ; assembler, which should have been included with this source file. ; You can also get it from http://appleii.ivanx.com, or email ivan@ivanx.com ;Usage: ;calling NUINPUT from a running program is equivalent to INPUT ST$ ;see NUINPUT.README for full explanation. ;optional before calling: ;maxLen is maximum entry length (default is 255 if no ST$ defined) ;nuFlag set appropriately (default is 0 if no ST$ defined) ;KL$ is list of permitted keys (if omitted, all are allowed) ;DE$ is default entry string ;KC$ is list of ctrl chars for submit ( [ for ESC ) ;ST$ contains entry, $08 contains submit key, $09 contains cursor pos ;nuFlag: ; bit 7: prohibit break (control-C) ; bit 6: single key entry (like Applesoft GET; no output or wrap) ; bit 5: convert lowercase to uppercase ; bit 4: destructive (erasing) backspace ; bit 3: ESC clears text if present ; bit 2: CR prevented for entry (if KC$ is not empty) ; bit 1: CR rejects blank entry ; bit 0: KL$ is case sensitive ;nuFlag bits 4/3/2/1, DE$, and maxLen are ignored if bit 6 is set ;see NUINPUT.README for full help ;varFlag states (bits 7 and 6, others are irrelevant) ;11 -- auto-RS to end of entry -- happens after submit ;01 -- auto-DEL (destructive) to targetCursorPos -- happens after auto-RS ;10 -- filling default entry (DE$) -- happens before readKey ;00 -- normal (user key input) ;from getKeyLoop onward: ;X is the key being processed (always between #01 and #7F) ;Y is usually the current cursor position (zero-based), and can be restored from cursorPos ;NuInput version number versionNumber: 09 ;00001001 ;version 2.1 (scheme: bb-2.bbb.bbb+1) ;Applesoft ROM calls LET: DA46 ; Applesoft LET command, used for ST$=ST$+"" PTRGET: DFE3 ; variable search and create, returns in A/Y and VARPNT, X=0 if just created ERRDIR: E306 ; checks for direct, produces error if so (not used; incompatibile with BASIC.SYSTEM) CONTROL.C.TYPED:D863 ; ctrl-C handler ;machine ROM calls RDKEY: FD0C ; Monitor key input routine COUT: FDED ; Monitor character output routine SAVE_PC: FF54 ; puts stack pos in X, TXS/PLA/PLA can get PC ;input/variable related Applesoft vectors VARPNT: 83 ; 83/84 pointer to length of variable found by PTRGET TXTPTR: B8 ; B8/B9 pointer to variable name for PTRGET to find IN: 0200 ; monitor input buffer, used here for ST$ storage ;memory-related Applesoft vectors VARTAB: 69 ; 69/6A start of storage (and simple variable) space [LOMEM] ARYTAB: 6B ; 6B/6C start of array storage space (and end of simple variable space) STREND: 6D ; 6D/6E end of storage space (and array space) FRETOP: 6F ; 6F/70 dynamic string space start MEMSIZ: 73 ; 73/74 dynamic string space end [HIMEM] PRGEND: AF ; AF/B0 Applesoft program end ; "safe" zero page locations used by NuInput; believed not to be used by ; the Apple II ROM, Applesoft, DOS 3.3, or ProDOS, except where noted ; (these may interfere with other programs that uses these locations, however) zpListPtr: 06 ; 06/07 ;pointer to zpList (not used after scanVarLoop) stLenPtr: CE ; CE/CF ;pointer to ST$ length keyListPtr: EB ; EB/EC ;pointer to KL$ data start ctrlListPtr: ED ; ED/EE ;pointer to KC$ data start defEntryPtr: 08 ; 08/09 ;pointer to DE$ data start (not used after DE-fill is complete) origKey: 08 ;actual key typed by user in low-ASCII submitPos: 09 ;in getKeyLoop, cursor position (0-based) when submitted klLen: 1E ;length of KL$ kcLen: D7 ;length of KC$ deLen: EF ;length of DE$ (not used after DE-fill is complete) [must be highest zp loc] varFlag: E3 ;auto-RS, auto-DEL, DE-fill, normal entry state flags (bits 6 and 7) maxLen: FD ;maximum length of entry; set by calling program nuFlag: FE ;entry options, set by calling program typedKeysLen: 0F ;length of entry (and so maximum position of right-arrow) ; (normally TKN.CNTR, used during Applesoft PARSE.INPUT.LINE) cursorPos: 34 ;current cursor position (set at start of getKeyLoop) ; (normally YSAV, used during monitor cmd processing [$FF70]) targetCursorPos:4F ;cursor position before auto-right-space to end of line ; (normally RNDH, changes itself while waiting for keypress) ;available "safe" zp locations: FA-FC [though reserved if using CALL 250 from Slammer] ;ASCII character values ESC: 1B BS: 08 BS.HI: 88 RS: 15 DEL: 7F CR: 0D SPC: 20 SPC.HI: A0 CTRL.C: 03 CARET: 5E A.LOWER: 61 Z.LOWER: 7A * = 7FC0 ; ($8000 minus InstallLength) ; (so NuInput itself starts at $8000, after installer, ; but it's all relocatable so it doesn't really matter) ;======= NUINPUT.INSTALL ======= ;installs NuInput between program and variables ;NuInput is called with CALL 250 NuInputLength: ~512 InstallLength: ~64 A1L: 3C ;3C/3D ;NuInput start pointer A2L: 3E ;3E/3F ;NuInput end pointer A4L: 42 ;42/43 ;target address pointer [end of Applesoft program] CURLIN: 75 ;75 ;FF when in immediate mode, otherwise in deferred mode MOVE: FE2C ;monitor memory move routine BELL1: FBDD ;monitor speaker beep routine jumpToRoutine: FA ;FA/FB/FC ;so CALL 250 can execute NuInput installStart: JSR SAVE_PC ;put PC on stack so we know where NuInput is LDY CURLIN+1 ;CURLIN+1 is FF when in immediate mode INY BEQ exit_beep ;in immediate mode? if yes, beep and exit installSetup: ;we have to figure out where NuInput is first TXS ;move stack pointer down so we can pull off PC PLA ;get low byte of PC. (we're going to copy 513 bytes, CLC ; from NuInput start to NuInput start+$200) ADC #NuInputLength ;add high byte of NuInput Length STA VARTAB+1 ;store it in high byte of storage space start STA ARYTAB+1 ;store it in high byte of array space start STA STREND+1 ;store it in high byte of storage space end LDA #4C ;load a JMP... STA jumpToRoutine ;and put it in JumpToRoutine installMove: LDY #00 ;required before calling MOVE JMP MOVE ;initiate copy DCB 01 ;pads to 64 bytes, same as NuInput version # ;======= END NUINPUT.INSTALL ======= ;* = 8000 ;uncomment if assembling NuInput without installer ;=====NuInput Start ($8000)===== ;prohibit running in immediate mode start: LDX CURLIN+1 ;CURLIN+1 is FF when in immediate mode INX BNE saveTXTPTR ;in immediate mode? if no, continue exit_beep: JMP BELL1 ;yes, beep and exit ;============= varNameList: dcb "ST$KL$KC$DE$" ;vars searched/created by PTRGET stConcatStr: dcb "ST$",D0,"ST$",C8,22,22 ;ST$=ST$+"" (executed by LET) zpList: dcb = 1 gkl_route: BIT varFlag ;submitting entry? (auto-RS or auto-DEL happening?) BVS gkl_submit ;yes BPL gkl_readKey ;no. DE-fill mode? if no, go get a key as usual gkl_DEfill: ;[varflag: 10000000] LDA (defEntryPtr),Y ;get next byte in DE$ CPY deLen ;is that the last one? BCC gkl_DEfill_checkDEL ;no, so process as though key was typed ASL varFlag ;yes, done with DE-fill, so set normal varFlag [00000000] BEQ gkl_readKey ;BRA gkl_DEfill_checkDEL: CMP #= maxLen? getKeyLoop.BCS: BCS getKeyLoop.all.nzA ;yes, so get another character gkl_key_tooLong_end: gkl_key_checkKL: LDY varFlag BMI gkl_acceptKey.ALL.nzA ;filling default entry? if yes, skip keylist and convertCase LDY klLen BEQ gkl_key_checkKLloop_end ;is KL$ ""? if yes, don't check keylist gkl_key_checkKLloop: TXA ;put typed key in A so we can do indirect compare DEY BMI go.gkl_readKey.ALL.nzA ;end of KL$? if yes, get another key CMP (keyListPtr),Y ;no. is typed key in keyList? BEQ gkl_key_checkKLloop_end ;yes, continue LDA nuFlag ;no. case sensitive KL$? ROR ;nuFlag bit 0 -> C BCS gkl_key_checkKLloop ;yes, check next char in keyList TXA ;no, put typed key in A again CMP #