I'm writing a text adventure in assembly for the Apple IIe (using Merlin). I'm also using ProDOS 8 v2.0.3. At some point, I have a subroutine to read user input from the keyboard using the GETLN1 call. It works as expected, except in cases where the user input coincides with a ProDOS command; for example, if the user types:


I get a "SYNTAX ERROR" message and my program exits back to the BASIC prompt. It seems that it tries to validate the syntax of the ProDOS command UNLOCK (and DOOR is obviously not a valid parameter). If I type some other commands (e.g. OPEN) I have similar results.

The GETLN subroutine was meant to just read user input to the keyboard buffer and return to the caller. But it seems to be also checking if the input matches a ProDOS command, and attempting to validate its syntax. I don't want that behavior, I just want to read a line of user input from the keyboard.

Here's a snippet from my code:

GETLN1          equ $FD6F
InputString     jsr GETLN1
                lda #$E5        ; DEBUG
                jsr PRBYTE      ; OUTPUT

Note: if I type a ProDOS command string like UNLOCK or OPEN, my program exits before printing the debug output above. If I type anything else, it prints the debug output and proceeds as expected.

Does anyone know what is going on and how can I work around this problem?

  • 2
    You could call SETVID ($fe93) and SETKBD ($fe89) to disable the BASIC.SYSTEM I/O hooks. Be polite and reconnect them after (call $be00).
    – fadden
    Jan 2, 2023 at 15:59
  • Worked like a charm. Thank you! Jan 2, 2023 at 16:08
  • 1
    @fadden That sounds like the answer, put it down there instead ;) Jan 2, 2023 at 18:33
  • It might be useful to write GETLN1 used thruout the question, as GETLN is a different entry point ($FD6A).
    – Raffzahn
    Jan 2, 2023 at 22:38
  • 1
    @TacianoDreckmannPerez Resetting video/keyboard to ROM default will disable any redirection - like used by 80 column cards, serial console or other add on in-/output methods.
    – Raffzahn
    Jan 2, 2023 at 23:40

2 Answers 2


There are two basic approaches:

  1. Disable the I/O hooks. This removes the operating system from the equation.
  2. Write your own line input routine, using the keyboard I/O addresses ($c000 / $c010).

Disabling the I/O hooks is the easiest way to solve your current problem. Just call SETVID ($fe93) and SETKBD ($fe89). When running under ProDOS's BASIC.SYSTEM, be sure to re-enable them by calling $03d0 (which calls $be00) when you're done. If you're not running under BASIC.SYSTEM, i.e. you're a SYS program, you won't have this problem.

Writing your own input routine is fairly straightforward, and you probably don't want all of the ESC-key handling that the monitor does for you anyway. Adventure games usually just need a simple cursor with backspace handling.

For example, the Scott Adams Adventure engine just gathers characters by polling KBD ($c000), and checks for backspace (Ctrl+H) and return (Ctrl+M). Characters are erased when backing up, so it doesn't need to worry about forward-arrow handling. It uses the monitor's text position routines (BASCALC at $fbc1) and writes directly to the text page, which would get complicated if you wanted to use 80 columns.

  • 1
    Good answer - especially mentioning to just write your own simple routine. Still, I'd suggest to go via KEYIN to keep compatibility with all models and in-/output variants one my find out in the wild. After all, emulators only show some idealized machine, not the multitude of hacks real Apple II attracted.
    – Raffzahn
    Jan 3, 2023 at 5:06
  • @fadden is there a difference calling $be00 and $03d0 on the way out? Jan 3, 2023 at 10:43
  • 1
    @TacianoDreckmannPerez: $03d0 is the DOS warmstart entry vector. 3D0G is an easy-to-remember way to get out of the monitor and reconnect DOS. It serves the same purpose with ProDOS and BASIC.SYSTEM (it's a JMP to $be00). I don't think it matters which you call unless some other bit of software needs to alter the vector, but I don't know of anything that does that.
    – fadden
    Jan 3, 2023 at 16:03

Some aspects of the Apple II's I/O system are pretty clever. Others, not so much. IMHO, the worst aspect is the way I/O cards use one entry point for everything, meaning that it's not possible to distinguish between "prepare the system to interact with floppy disks" (i.e. boot from a floppy) versus "start sending output to the floppy disk I/O handler". Further, Integer BASIC lacks any means by which DOS can add additional commands, and Apple opted not to use Applesoft's ampersand-hook feature for that purpose. Instead, the various versions of Apple DOS inspect all lines of input which are typed, try to ascertain whether they are being typed at the BASIC input prompt; if they are, they then check to see whether they are commands, and if so, they process them.

To be sure, being able to type LOAD WOOZLE may be more convenient than having to use something like &REM LOAD WOOZLE", or--for ROM-based versions of integer BASIC--something like CALL 768:REM SAVE WOOZLE, but the intercepted I/O approach to command handling is rather a nuisance in every other way. Depending upon the nature of your application, it may be best to reset the vectors to the ROM-based character I/O routines and set them back to DOS when needed, call ROM-based routines directly, use your own character input routines based on the I/O strobes, tweak some of the addresses used by the BASIC interpreter so DOS or ProDOS would think an INPUT command was being executed, or boot without BASIC.SYSTEM (which I think is where interactive commands get processed).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .