Skip to content

Conversation

@rob-smallshire
Copy link

@rob-smallshire rob-smallshire commented Oct 23, 2025

Fixes issue where Mac Caps Lock key did not affect the emulated BBC Micro's Caps Lock state or LED indicator, and also goes to some lengths to ensure the states remain synchronized even when the BeebEm is not in focus.

Key changes:

  1. Fixed Alt key mapping bug

    • Was incorrectly mapped to VK_CAPITAL (Caps Lock)
    • Now correctly mapped to VK_MENU (Windows Alt key code)
  2. Implemented Caps Lock handler with 50 ms pulse

    • Sends DOWN+UP pulse when Mac Caps Lock toggles
    • 50 ms delay = 40 ms Windows default + 25% safety margin
  3. Added state synchronization

    • On startup: Syncs after BBC LED initialization detected which indicates the point in BBC MOS initialization after which Caps Lock state changes will be recognized
    • On focus gain: Re-syncs when window becomes active
    • Prevents desync when Caps Lock changed while app unfocused
    • Dynamic resynchronisation in Logical keyboard mapping mode. If Acorn MOS updates the Caps Lock state in the emulated machine (most commonly this happens on Break), BeebEm detects this and resynchronises Acorn MOS Caps Lock state with macOS state.

Testing note: macOS debounces Caps Lock key events internally to prevent accidental engagement of Caps Lock. Very rapid presses are filtered by macOS itself, and won't reach BeebEm. The physical LED on the macOS Caps Lock reflects the debounced state.

Implementation notes:

  • BBC Caps Lock at keyboard matrix row 4, column 0
  • IC32 bit 6 controls BBC keyboard Caps Lock LED (active-low)
  • BBC MOS toggles Caps Lock state on key DOWN only
  • Uses GCD dispatch_after for async key-up event after delay

Fixes issue where Mac Caps Lock key did not affect the emulated BBC
Micro's Caps Lock state or LED indicator, and also goes to some lengths
to ensure the states remain synchronized even when the BeebEm is not
in focus.

Key changes:

1. Fixed Alt key mapping bug
   - Was incorrectly mapped to VK_CAPITAL (Caps Lock)
   - Now correctly mapped to VK_MENU (Windows Alt key code)

2. Implemented Caps Lock handler with 50 ms pulse
   - Sends DOWN+UP pulse when Mac Caps Lock toggles
   - 50 ms delay = 40 ms Windows default + 25% safety margin

3. Added state synchronization
   - On startup: Syncs after BBC LED initialization detected which
     indicates the point in BBC MOS initialization after which
     Caps Lock state changes will be recognized
   - On focus gain: Re-syncs when window becomes active
   - Prevents desync when Caps Lock changed while app unfocused

Testing note:

    macOS debounces Caps Lock key events internally to prevent
    accidental engagement of Caps Lock. Very rapid presses are
    filtered by macOS itself, and won't reach BeebEm. The physical
    LED on the macOS Caps Lock reflects the debounced state.

Implementation notes:
- BBC Caps Lock at keyboard matrix row 4, column 0
- IC32 bit 6 controls BBC keyboard Caps Lock LED (active-low)
- BBC MOS toggles Caps Lock state on key DOWN only
- Uses GCD dispatch_after for async key-up event after delay
Detection and correction of Caps Lock desynchronization
between Mac and BBC Micro when in Logical keyboard mapping mode.

Problem: Acorn MOS has control of the Caps Lock key, which can
cause it to become desynchronized with the host Mac Caps Lock
state. Notably on reset (Break) Acorn MOS resets the Caps Lock state.

Solution: Continuously monitor BBC Caps Lock LED state and automatically
re-sync with Mac state when divergence is detected, using debouncing and
rate limiting to prevent sync loops.

Key features:

1. Legitimate state tracking
   - Tracks expected BBC state based on user keypresses
   - Distinguishes user actions from programmatic LED changes
   - Detects when BBC state diverges from legitimate state

2. Debounced detection (100ms)
   - Waits for BBC LED state to stabilize before syncing
   - Prevents false triggers from brief LED transitions. This is
     important because Acorn MOS uses the Caps Locks LEDs to signal the
     waiting state when using the pager.
   - Ensures LED change is intentional, not transient

3. Rate limiting (500ms)
   - Prevents rapid sync attempts that could cause loops
   - Gives BBC program time to respond to sync
   - Reduces overhead from continuous monitoring

4. Mode-specific behavior
   - Only active in Logical keyboard mode
   - User/Default modes unaffected
   - Respects keyboard mapping configuration

5. Notification-based tracking
   - C++ bridge notifies Swift when user presses Caps Lock
   - Updates legitimate state on genuine user actions
   - Enables detection of programmatic LED changes

Implementation details:
- beeb_getKeyboardMappingMode(): Query current mapping mode from C++
- swift_userDidPressCapsLock(): Bridge function for user keypress events
- checkCapsLockDebounce(): 10Hz polling in main update loop
- State machine tracks: legitimate, pending, and actual LED states

Note:
- macOS performs its own debouncing of the physical Mac Caps Lock so
  very short presses of Caps Lock aren't communicated to BeebEm anyway

Manual testing considerations:
- Verify no sync loops or excessive syncing occurs
- Confirm normal user Caps Lock behavior unchanged
- Check mode switching disables/enables auto-sync correctly
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant