Repository: Caldis/Mos
Stars: 19783
CLAUDE.md
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
IMPORTANT
This Project's macoOS Deployment Target 10.13+, so every API should be compatible with it.
Project Overview
Mos is a macOS utility application that provides smooth scrolling for mouse wheels, making them behave more like trackpads. Built with Swift and Xcode, it's a menu bar application that intercepts and modifies scroll events in real-time.
Build System & Development Commands
Building the Application
- Primary IDE: Xcode (requires Xcode 9.0+, Swift 4.0+)
- Project File:
Mos.xcodeproj- Build Target: macOS application bundle
Dependencies
- Charts: Data visualization for the monitor window
- LoginServiceKit: Auto-launch functionality
- Dependencies are managed via Swift Package Manager (SPM)
Creating Distribution Package
cd dmg/
Requires create-dmg tool: https://github.com/create-dmg/create-dmg
Requires Mos.app in dmg/ directory (copy from build output)
./create-dmg.commandThe script automatically:
- Reads version from Info.plist
- Creates DMG with custom background and icon
- Generates versioned DMG filename (Mos.X.X.X.dmg)
- Includes application and Applications folder link
Running and Development
First-time setup:
1. Open the project
open Mos.xcodeproj2. Xcode will automatically resolve SPM dependencies (Charts, LoginServiceKit)
3. Wait for package resolution to complete (shown in top status bar)
4. Build and run (⌘+R)
Runtime requirements:
- App requires Accessibility permissions to intercept events
- On first launch, grant permissions in System Preferences → Security & Privacy → Accessibility
- Use the Monitor window during development to visualize scroll events in real-time
Architecture Overview
Minimum macOS version: 10.13, all API should be compatible with it
Core Components
ScrollCore Engine (Mos/ScrollCore/):
- ScrollCore.swift: Main scrolling interception and processing engine
- ScrollPoster.swift: Smooth scroll event posting using CVDisplayLink
- Interpolator.swift: Smooth scrolling interpolation algorithms
- ScrollEvent.swift: Event data structures
- ScrollFilter.swift: Event filtering and processing logic
ButtonCore System (Mos/ButtonCore/):
- ButtonCore.swift: Core mouse button event interception and processing
- ButtonFilter.swift: Event filtering logic for button actions
- ButtonUtils.swift: Button binding configuration utilities
- ShortcutExecutor.swift: System shortcut execution engine
Key Recording System (Mos/Keys/):
- KeyRecorder.swift: Event recording orchestrator with timeout protection
- KeyPopover.swift: Popover UI component for displaying recording status
- KeyPreview.swift: Visual preview of recorded key combinations
- KeyCode.swift: Comprehensive keyboard and mouse button code mappings
- SystemShortcut.swift: System shortcut definitions and management
Manager Pattern (Mos/Managers/):
- WindowManager: Controls window lifecycle and presentation
- StatusItemManager: Menu bar status item and menu management
- ShortcutManager: Global shortcut registration and management
Configuration System (Mos/Options/):
- Options.swift: Centralized configuration using UserDefaults
- Application.swift: Per-application settings and exception handling
Window Architecture
The app uses multiple specialized windows:
IntroductionWindow: First-time setup and permission requests
PreferencesWindow: Complex tabbed preferences with multiple view controllers:
- GeneralView: Basic scrolling settings
- ScrollingView: Advanced scrolling configuration options
- ButtonsView: Mouse button recording and action binding
- ApplicationView: Per-application exception rules
- AboutView: Application information and credits
- UpdateView: Update checking and management
MonitorWindow: Real-time scroll event visualization using Charts framework
WelcomeWindow: User onboarding experience
Each window follows the WindowController + ViewController pattern.
Key Technical Details
Event Interception: Uses Interceptor utility (wraps CGEventTap) for low-level event capture
- ScrollCore: Captures scroll wheel events (scrollWheel)
- ButtonCore: Captures mouse button events (leftMouseDown, rightMouseDown, otherMouseDown) and key events
Smooth Scrolling: CVDisplayLink-based event posting for 60fps smoothness via ScrollPoster
Event Recording: KeyRecorder orchestrates event capture with timeout protection and visual feedback
Permissions: Requires accessibility permissions (LSUIElement=true for menu bar app)
Localization: Supports 11 languages + English with dual .xcstrings system
Per-App Settings: Application class enables different scroll behaviors per application
Singleton Pattern: Core systems (ScrollCore, ButtonCore, Options, managers) use singleton pattern
File Structure Patterns
Managers: Singleton pattern for system integration (WindowManager, StatusItemManager, ShortcutManager)
Windows: WindowController + ViewController pairs, each in separate subdirectories
ScrollCore: Core scrolling logic and algorithms (ScrollCore, ScrollPoster, Interpolator, ScrollFilter)
ButtonCore: Mouse button event handling and shortcut execution
Keys: Key/mouse event recording system (KeyRecorder, KeyPopover, KeyPreview, KeyCode, SystemShortcut)
Utils: Utility classes (Interceptor for CGEventTap, EventMonitor, Logger, Constants)
Extension: Swift extensions for CGEvent and other system types
Options: Configuration management (Options, Application)
Components: Reusable UI components (PrimaryButton)
Development Guidelines
Adding New Features
1. Follow the manager pattern for system integration
2. Use WindowController + ViewController for new windows
3. Add configuration options to
Options.swift4. Consider per-app exceptions via
Application class5. For button-related features, extend
ButtonCore system and use KeyRecorder for event capture6. UI components should support both Light and Dark mode with dynamic color adaptation
7. Use
Interceptor utility (in Utils/) to wrap CGEventTap for event interception8. Follow localization patterns - all strings must be localizable
Modifying Scroll Behavior
- Core logic is in
ScrollCore/ScrollCore.swift- Interpolation algorithms in
ScrollCore/Interpolator.swift - Event filtering in
ScrollCore/ScrollFilter.swiftUI Changes
- Storyboard files are localized - modify Base.lproj first
- Follow existing popover patterns for menu bar UI
- Monitor window uses Charts framework for visualization
Testing
- Test with various mouse types and scroll behaviors
- Verify accessibility permissions are properly requested
- Test per-application exception system
- Use Monitor window to verify scroll event processing
Common Development Issues
Build fails with SPM errors:
Clear SPM cache and DerivedData
rm -rf ~/Library/Developer/Xcode/DerivedData
Re-resolve packages in Xcode: File → Packages → Reset Package Caches
Scrolling not working at runtime:
- Check Accessibility permissions in System Preferences → Security & Privacy → Accessibility
- Verify ScrollCore.shared.start() is called after permissions granted
- Use Monitor window to verify events are being captured
Button bindings not triggering:
- Open Monitor window to see if events are being captured
- Check ButtonCore.shared.start() is called
- Verify key codes in KeyCode.swift match expected values
UI not updating after preference changes:
- Options are stored in UserDefaults - verify Options.shared singleton is being used
- Check if NotificationCenter observers are properly registered
- Preferences window uses bindings - verify @objc dynamic on properties
Localization
The app supports 12 languages using Xcode's String Catalog system (.xcstrings).
Two separate localization files:
- Mos/Localizable.xcstrings - Code strings via NSLocalizedString()
- Mos/mul.lproj/Main.xcstrings - Auto-generated from Storyboard (never merge these)
Key requirements:
- Use NSLocalizedString() (not String(localized:)) for macOS 10.13 compatibility
- Follow macOS official terminology (e.g., "偏好设置" not "设置")
- Preserve modifier key symbols: ⌘⌥⌃⇧
- Never translate: "Mos", person names, brand names
For detailed translation guidelines, see LOCALIZATION.md
Important Considerations
Accessibility: App requires accessibility permissions to intercept events
System Integration: Menu bar app behavior, auto-launch functionality
Performance: Real-time event processing at system level
Localization: All UI strings must be localized following the guidelines above
Distribution: Cannot be uploaded to App Store per license restrictions
README.md
<p align="center">
<a href="http://mos.caldis.me/">
<img width="320" src="https://github.com/Caldis/Mos/blob/master/dmg/dmg-icon.png?raw=true">
</a>
</p>
Mos
一个用于在MacOS上平滑你的鼠标滚动效果的小工具, 让你的滚轮爽如触控板。
中文 | English |
Русский |
Indonesia
主页
http://mos.caldis.me/
特性
- 平滑你的鼠标滚动体验, 并可自定义加速度与曲线, 也可按滚动方向分别处理
- 支持分离触控板/鼠标事件, 可按垂直/水平方向分别设置平滑与反向
- 支持自订鼠标快捷键, 绑定各种系统快捷键
- 支持按应用处理不同的配置策略
下载及安装
Homebrew安装
Mos可通过Homebrew来安装:
$ brew install --cask mos@beta应用将被安装至 /Applications/Mos.app。
若有新版本,可用以下命令升级:
$ brew update
$ brew upgrade mos@beta重新启动应用即可。
手动安装
帮助
- Wiki
鸣谢
- Charts
- iconfont.cn
- LoginServiceKit
- Smoothscroll-for-websites
贡献
如果您觉得 Mos 的本地化做的有任何不妥之处, 欢迎您提交任何关于文本修改的意见, 您可以通过提交 Github Issue 的方式告诉我们, 如果您善于编码, 我们非常欢迎您提交一个 PR !
我们欢迎任何形式的贡献,有任何建议或意见您可以给我们 提问。
## LICENSE
Copyright (c) 2017 Caldis rights reserved.
And you can not upload it to the App Store.