ADR-004: Platform Differences

Status

Accepted

Context

Mouse button handling differs across Windows, macOS, and Linux:

  • Button codes: Qt button enums are consistent, but underlying values may differ

  • Modifier keys: Meta vs. Ctrl key conventions (especially macOS)

  • Extra buttons: Forward/back button availability and codes

  • Scroll events: Horizontal scroll, precision scrolling (macOS)

  • Device detection: How to enumerate connected mice

Decision

Create a PlatformAdapter abstraction that normalizes platform differences:

class PlatformAdapter(ABC):
    @abstractmethod
    def normalize_button(self, qt_button: int) -> str:
        """Convert Qt button code to canonical button ID."""
        pass

    @abstractmethod
    def normalize_modifiers(self, qt_modifiers: int) -> set[str]:
        """Convert Qt modifiers to canonical modifier set."""
        pass

    @staticmethod
    def get_instance() -> "PlatformAdapter":
        if sys.platform == "win32":
            return WindowsAdapter()
        elif sys.platform == "darwin":
            return MacOSAdapter()
        else:
            return LinuxAdapter()

Platform-Specific Implementations

WindowsAdapter:

  • Standard Qt button codes

  • Forward/back buttons at codes 8, 16

  • No special handling needed for most cases

MacOSAdapter:

  • Swap Ctrl/Meta for consistency with Windows/Linux conventions

  • Handle precision scroll wheel events

  • Forward/back may require special handling

LinuxAdapter:

  • Standard Qt button codes

  • Optional evdev integration for additional buttons

  • Handle X11 vs Wayland differences if needed

Canonical Button IDs

All platforms map to these canonical IDs:

  • left, right, middle

  • back, forward

  • extra1, extra2, etc. (for additional buttons)

  • scroll_up, scroll_down, scroll_left, scroll_right

Consequences

Positive

  • Single abstraction hides platform complexity

  • Presets are portable across platforms

  • Easy to add new platform support

  • Business logic doesn’t need platform checks

  • Clear separation of concerns

Negative

  • Requires testing on all platforms

  • Some edge cases may not be normalized perfectly

  • Additional abstraction layer adds complexity

Neutral

  • Canonical IDs must be documented and stable

  • Platform detection happens at startup

References