CoCo Buttons

Reading CoCo Joystick Buttons in Color BASIC

The joystick buttons on the TRS-80 Color Computer 1 (CoCo 1) are connected to the
PIA (Peripheral Interface Adapter). They can be read from memory location
$FF00, which is decimal 65280.

In Color BASIC, the value can be read using PEEK:

B=PEEK(65280)

The joystick buttons are active low. This means that a button that
is not pressed reads as a 1, and a pressed button pulls the bit to
0.

The button bits are:

Bit Mask Button
0 1 Right joystick button
1 2 Left joystick button

Color BASIC supports bitwise AND, which makes checking the buttons
straightforward:

10 B=PEEK(65280)
20 IF (B AND 1)=0 THEN PRINT "RIGHT BUTTON"
30 IF (B AND 2)=0 THEN PRINT "LEFT BUTTON"
40 GOTO 10

The parentheses are important. Color BASIC’s operator precedence can produce
surprising results if you write:

PEEK(65280) AND 128 = 0

This is not interpreted as:

(PEEK(65280) AND 128) = 0

Instead, the comparison happens first, effectively making it:

PEEK(65280) AND (128 = 0)

Since 128 = 0 is false, the expression becomes an AND with zero,
which will always produce zero.

The correct way to test a bit is to put the bit operation inside parentheses:

(PEEK(65280) AND 128) = 0

The evaluation order is:

  1. PEEK(65280) reads the hardware register.
  2. AND 128 masks the desired bit.
  3. = 0 tests whether that bit is clear.

This is a good habit for Color BASIC programming: whenever using bit masks in
a comparison, put the masked expression in parentheses.

The CoCo’s joystick interface is simple, but remembering that the buttons are
active low and that Color BASIC’s operator precedence is different from many
modern languages will save a lot of debugging time.

Teaching BBEdit to Know Soft Wrap setting for OCR Text Files

I recently ran into a problem while processing a large batch of OCR text files.

The workflow was simple: scanned PDFs → OCR → text files → BBEdit search. The OCR output was fine structurally, with one line per paragraph, but reading it in BBEdit was unpleasant. Long lines ran off the right side of the window. Search still worked, but visual scanning was harder than it should be.

What I wanted was simple. Every OCR text file should open in BBEdit with Soft Wrap enabled.

BBEdit does not provide a setting for this at the file level. There is no xattr or modeline for it.

Where BBEdit stores document state

BBEdit stores per-file state in a property list here:

~/Library/Containers/com.barebones.bbedit/Data/Library/BBEdit/Document State.plist

This file acts like a database. Each entry is keyed by file path, and contains a dictionary of state data for that file.

The setting I cared about is:

<key>SoftWrapText</key>
<true/>

It lives inside:

StateEntries_v1
    └── file path
        └── BBEditStateData

BBEdit uses this structure to store editor state per file.

Path matching matters

My first attempt did not work correctly.

I had entries like:

1981/08_rainbow.txt

But BBEdit was using full paths like:

/Volumes/ARCHIVE/Rainbows/1981/08_rainbow.txt

BBEdit matches state strictly by path. If the key does not match exactly, it is ignored.

The fix was to always normalize paths before writing them.

Files on external volumes stay absolute. Files inside the home directory can use ~/.

In Python, this is handled with:

path = path.resolve()

Automating Soft Wrap for many files

Once the structure was correct, I wrote a script that:

  • finds all .txt files recursively
  • computes the correct BBEdit key for each file
  • sets SoftWrapText = true
  • preserves existing BBEdit metadata

The key function is:

def bbedit_key_for(path: Path) -> str:
    path = path.resolve()

    try:
        rel = path.relative_to(Path.home())
        return f"~/{rel}"
    except ValueError:
        return str(path)

Everything else is plist editing.

Result

After running this across the OCR archive:

  • all text files open with wrapping enabled
  • BBEdit search still works normally
  • no changes to the original files
  • no need to insert line breaks into OCR output

The workflow is now easier to read without affecting how search behaves.

What this is doing

BBEdit stores per-file editor state in a plist that behaves like a small database keyed by file path.

Once that is visible, it becomes possible to automate editor behavior for large sets of files instead of adjusting settings manually.

This can be extended beyond Soft Wrap to other per-file state BBEdit tracks.