See Also: part 1, part 2, part 3, part 4, part 5, part 6 and part 7 (and maybe more to come…)
Here is what I have learned so far…
When BASIC wants to output a character, it jumps to a ROM routine called CHROUT. This is one of a few documented ROM calls in Color BASIC. Here is how it is documented in the EDTASM+ manual:

I have used this ROM call in previous blog posts, showing how to output “HELLO WORLD” or whatever using assembly:

That small program makes the X register point to the first byte of the MSG data. It then loads that byte into register A and increments X. If A is 0 (the end of string marker), it branches to DONE. If not, it jumps to the subroutine pointed to at $A002 which outputs whatever is in A. It then goes back to do it again.
I wrote a two-part post about Color BASIC RAM hooks awhile ago. There I explored these extra spots where later BASIC ROMs (like Extended, DISK, and the CoCo 3 ROM) can patch in and make the original Color BASIC call new code first. That new code did things like add support for DISK devices or the (gone in CoCo 3) DLOAD command. I assume it is also used to patch in the CoCo 3’s high resolution 40/80 column text screens, as well.
The idea is before Color BASIC does its thing with the CHROUT routine, it will jump to “new code” and let it run first, and that code may then return back to let the normal code process. When disk devices were added as device #1 to device #15, this jump goes to code in Disk Extended BASIC which checks the incoming device number. If it is 1-15, new code is called that takes care of writing data to a disk file. If not, it returns back and Color BASIC handles the devices it knows about (device 0 for console, device -1 is the cassette, and device -2 if the serial/printer port).
For the task Erico was inquiring about, I thought I could patch in a new routine that would check for device 0 (writing to the screen) and then if it was, look for a special character that now means “transparent”. Instead of putting the character on the screen then moving the cursor position over by one, it would just move the cursor position and leave the screen alone.
Here is what I came up with in a quick and dirty hack:
* lwasm consmove.asm -fbasic -oconsmove.bas --map
* Convert any lowercase characters written to the
* screen (device #0) to uppercase.
DEVNUM equ $6f device number being used for I/O
CURPOS equ $88 location of cursor position in RAM
RVEC3 equ $167 console out RAM hook
org $3f00
init
lda RVEC3 get op code
sta savedrvec save it
ldx RVEC3+1 get address
stx savedrvec+1 save it
lda #$7e op code for JMP
sta RVEC3 store it in RAM hook
ldx #newcode address of new code
stx RVEC3+1 store it in RAM hook
rts done
newcode
* Do this only if DEVNUM is 0 (console)
tst DEVNUM is DEVNUM 0?
bne continue not device #0 (console)
* If here, device #0 (console)
cmpa #'r compare A to lowercase 'r'
bne continue if not, continue
leas 2,s remove PC from stack since we won't be returning there.
* Now this is the start of what Color BASIC ROM does for PUTCHR:
LA30A
pshs x,b,a
ldx CURPOS X points to current cursor position
leax 1,x increment X, skipping that location.
jmp $a344 jump back into Color BASIC ROM code.
continue
savedrvec rmb 3 call regular RAM hook
rts just in case...
end
The “init” code saves out whatever is in the console out RAM hook (three bytes, either “rts” if not being used, or “jmp abcd” to jump to new code). It then patches in a “jmp” to the new code in this program, then returns back. This installs the new code into the RAM hook.
Now when anything tries to print through CHROUT, BASIC first calls whatever the RAM hook points to. That will be the “newcode” here.
This new code first checks if the device is 0, indicating we are printing to the screen. If it is not, it branches to the “continue” spot where the original RAM hook jump was copied, allowing it to jump there and proceed as normal.
Next it checks to see if the character to print is a lowercase ‘r’ (I chose ‘r’ for “right”). If not, it returns.
Now things get weird. This is not a normal RAM hook because I can’t just “do stuff” then return to the original ROM code. That original code would still want to output whatever is in register A to the screen. To make mine work, I need to take over some of the functions of the ROM and then jump back into the normal ROM code so it can continue after I have done my thing.
In a normal RAM hook, BASIC would use a JSR (jump subroutine) to get there, then have that code return back. But for this hack to work, my new code has to jump directly back into Color BASIC. Because of this, there is a return address (where RTS will return to) on the stack that we won’t be using. Doing “leas 2,s” moves the stack pointer so it skips that. This allows me to jump directly out of this new code back into the ROM.
Now we have to do whatever code the ROM would have done before processing the character. I looked at the disassembly and see it pushes three registers to save them, then at the end it will pull them back off the stack to restore them.
So I do that in my code.
Next, all I need to do is increment the cursor position then jump back into the Color BASIC ROM just past where it would normally put the character on the screen. From there on, everything will be normal.
I may not have explained this very well, but I am sure someone can help me in the comments.
Patching BASIC with BASIC
Thanks to LWTools, here is a simple BASIC loader for this test code:
10 READ A,B
20 IF A=-1 THEN 70
30 FOR C = A TO B
40 READ D:POKE C,D
50 NEXT C
60 GOTO 10
70 END
80 DATA 16128,16170,182,1,103,183,63,43,190,1,104,191,63,44,134,126,183,1,103,142,63,24,191,1,104,57,13,111,38,15,129,114,38,11,50,98,52,22,158,136,48,1,126,163,68,16174,16174,57,-1,-1
If you load this into a CoCo or emulator, then RUN it, the code will be loaded at address &H3F00. Type “EXEC &H3F00” to install the new RAM hook and now any print of lowercase ‘r’ skips to the right without erasing anything.
10 CLS0
20 PRINT@0,"THISrrrrWILLrrrrWORK"
30 GOTO 30
That simple program will clear to a black screen, then you will see “THIS” then four blocks to the right “WILL” then four blocks past that “WORK”. Normally it would erase those blocks with spaces, but the lowercase ‘r’ now means “just skip to the right”.
It’s not perfect, but it does prove the concept.
More to come…

For bonus points, handle the case where it’s running on a Coco3 in Width 40/80. Without misbehaving on a Coco1/2. “Handle” can mean “don’t do transparent characters” or “make it work properly”. Hint: “make it work properly” will be harder than you expect – the SECB code for handling screen output is quite terrible.
How would one even tell? See if the RAM vector is the CC3 one?
The Coco3 additions do not use the RAM vectors. (There’s a technical reason for that related to backward compatibility and cartridges.)
You should be able to check the RESET vector at $FFFE. It will be $8C1B on the Coco3.
Now I have to dig into that book and see how they kept the Color, Extended and Disk stuff happy.
This is a neat exercise. Turned out easier than I would have expected!
I looked up the December 1984, and January-February 1985 Rainbows for an article on creating the 51 column screen. They did something similar to what I figured out which gives me hope. I have a larger project in mind and learning how to do this was an important first step. I will probably do a part 3 when I get back home and add more to it, and make it so the code can load anywhere, etc. Any guidance is appreciated!
Oh my. RAM hooks — particularly that one — are my lifeblood when hacking C/EC/DEC BASIC.
This is leading to the project I was referring to when I asked you about your high res text screens :-) I also found an unpublished assembly thing I wrote which patches UNCRUNCH so you can LIST and see embedded graphics characters in strings. That was mentioned in my Attract Screen article series years ago and I completely forgot about it!