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
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
Qt Platform Abstractions: https://doc.qt.io/qt-5/qpa.html
ADR-001: Event interception uses adapter
ADR-003: Button detection with platform awareness