Skip to content

feat: Add Auto-Scroll feature (middle-click scrolling)#913

Open
RomFatal wants to merge 21 commits into
Caldis:masterfrom
RomFatal:Auto-Scroll
Open

feat: Add Auto-Scroll feature (middle-click scrolling)#913
RomFatal wants to merge 21 commits into
Caldis:masterfrom
RomFatal:Auto-Scroll

Conversation

@RomFatal
Copy link
Copy Markdown

@RomFatal RomFatal commented Apr 8, 2026

Summary

Adds an auto-scroll feature triggered by middle mouse button click, similar to the auto-scroll behavior found in Windows browsers. When the user middle-clicks in a scrollable area, the cursor changes to a scroll indicator and moving the mouse scrolls the content proportionally to distance from the origin point.

Behavior

  • Activate: Middle-click in a scrollable area
  • Scroll: Move mouse away from the origin point — speed scales with distance
  • Deactivate: Click any mouse button, or middle-click again
  • Smart detection: Does not activate when clicking on a link or button (uses cursor shape detection to identify pointer/hand cursor)
  • Browser-aware: Passes through middle-clicks in browser UI areas (tabs, toolbar) so browser tab behavior is preserved

Changes

New files

  • Mos/AutoScrollCore/AutoScrollCore.swift — core engine: activation, scroll loop, speed curve, drag threshold
  • Mos/AutoScrollCore/AutoScrollCursor.swift — cursor overlay management
  • Mos/AutoScrollCore/AutoScrollOverlay.swift — visual indicator overlay window
  • Mos/AutoScrollCore/AutoScrollUtils.swift — utility helpers
  • Mos/Windows/PreferencesWindow/AutoScrollView/PreferencesAutoScrollViewController.swift — preferences UI

Modified files

  • Mos/ButtonCore/ButtonCore.swift — handles middle mouse down/up/move events, routes to AutoScrollCore
  • Mos/ScrollCore/ScrollCore.swift — passthrough check for auto-scroll generated events (flagged with .maskAlternate)
  • Mos/Options/Options.swift — adds autoScroll options struct (enabled, sensitivity, dead zone, drag threshold, max speed, activation button, app exceptions, dark mode)
  • Mos/Utils/Constants.swift — adds OPTIONS_AUTOSCROLL_DEFAULT and PANEL_IDENTIFIER.autoScroll
  • Mos/Base.lproj/Main.storyboard — adds Auto-Scroll tab to Preferences window
  • Mos/Localizable.xcstrings — adds 13 new UI strings for auto-scroll preferences
  • Mos/mul.lproj/Main.xcstrings — adds Auto-Scroll tab title string

Preferences

All auto-scroll behavior is configurable in Preferences → Auto-Scroll:

Setting Default Description
Enable Auto-Scroll On Master toggle
Scroll Speed Sensitivity 1.0 Multiplier for scroll speed
Dead Zone 5 px Radius around origin where no scrolling occurs
Drag Threshold 20 px Movement needed after mousedown to distinguish drag vs click
Maximum Scroll Speed 30 Speed cap
Activation Button Middle (2) Which button triggers auto-scroll
White Background (dark mode) Off Overlay icon color for dark backgrounds

Notes

  • Requires Accessibility permissions (already required by Mos)
  • Uses @_silgen_name to call private CGS APIs for cursor shape detection (CGSGetGlobalCursorData) — this is used solely to detect whether the cursor is a pointing hand, to avoid hijacking link clicks
  • Auto-scroll events are marked with .maskAlternate flag so ScrollCore can identify and pass them through without re-processing
  • Compatible with macOS 10.13+

Introduces a new auto-scroll feature activated by middle mouse button, including core logic, custom cursor, and utility classes. Updates the preferences window and storyboard to add an auto-scroll settings tab with controls for sensitivity, dead zone, drag threshold, max speed, and activation button. Updates Options and Constants to persist auto-scroll settings. ButtonCore is updated to handle auto-scroll events and integrate with the new feature.
Replaces the custom cursor with a fixed overlay icon at the activation point for auto-scroll. Introduces AutoScrollOverlay to display the icon, updates coordinate conversions for correct placement, and improves the visual design of the overlay and cursor. Also adds a dark mode option for auto-scroll icons in Constants.
Introduces a 'dark mode' toggle for the auto-scroll overlay icon, allowing users to enable a white background for better visibility in dark environments. Updates the overlay rendering logic, user preferences, and preferences UI to support this new option.
Adjusted the auto-scroll acceleration formula for a smoother, more natural speed curve based on distance. Improved Preferences UI layout with tighter spacing, shorter info text, and removed usage instructions. The reset button now explicitly resets each auto-scroll option to its default value instead of using a default struct.
AutoScrollCore now marks generated scroll events with the maskAlternate flag. ScrollCore detects this flag and bypasses further processing for these events, ensuring auto scroll events are not smoothed or altered.
Introduces logic to detect whether the middle button click occurs within a scrollable area and not in browser UI regions. Auto-scroll is now only activated if the click is outside browser UI (such as toolbars or tab bars) and on content that supports scrolling, improving user experience and preventing unintended activation.
Refactors and hardens auto-scroll logic to more reliably detect browser UI areas and block/allow events accordingly, preventing Chrome's native auto-scroll from triggering in blocked regions. Adds extensive debug logging, improves coordinate conversions, and ensures overlay positioning is accurate. Updates localization files with new auto-scroll settings strings and UI labels. Also changes event tap placement to head for more reliable event interception.
Refines logic to allow middle mouse button events to pass through in browser tab and bookmark areas, preventing interference with browser UI interactions. Updates event consumption behavior in AutoScrollCore and ButtonCore, and expands the preferences window and related UI elements in Main.storyboard for better layout. Also updates project settings to require macOS 11.0 and Xcode 14.3 or later.
Reduced the top UI block height from 250px to 130px in browser windows to more accurately reflect the actual UI area and avoid unnecessarily blocking scroll events outside the UI.
Replaced usage of NSScreen.main with NSScreen.screens.first to ensure coordinate conversions use the primary screen rather than the currently focused screen. Updated related log messages and comments for clarity.
AutoScrollCore now allows link clicks to pass through in browsers by not consuming events for AXLink roles, especially in strict mode. Removed AXLink from the general non-scrollable UI element list and improved logging. In Options, increased the default dragThreshold for auto-scroll from 10.0 to 20.0. Also removed a debug log from ButtonCore.
Replaces accessibility-based link detection with system cursor analysis to reliably detect clickable elements (like links) in browsers, especially Chromium-based ones where accessibility APIs are limited. Adds low-level cursor inspection in ButtonCore to block auto-scroll when the pointing hand cursor is active, ensuring correct behavior over links and buttons. Refactors and removes obsolete accessibility link detection logic from AutoScrollCore, and enhances event handling to use the new cursor-based approach.
# Conflicts:
#	.gitignore
#	Mos.xcodeproj/project.pbxproj
#	Mos.xcodeproj/xcshareddata/xcschemes/Debug.xcscheme
#	Mos.xcodeproj/xcshareddata/xcschemes/Profile.xcscheme
#	Mos/Base.lproj/Main.storyboard
#	Mos/ButtonCore/ButtonCore.swift
#	Mos/Localizable.xcstrings
#	Mos/ScrollCore/ScrollCore.swift
#	Mos/Utils/Constants.swift
Remove trailing spaces and tidy up blank lines/indentation across AutoScrollCore.swift and ButtonCore.swift. Purely cosmetic formatting changes to improve readability (whitespace, blank-line normalization, minor comment spacing) with no functional or behavioral changes.
@RomFatal RomFatal changed the title Add Auto-Scroll feature (middle-click scrolling) feat: Add Auto-Scroll feature (middle-click scrolling) Apr 18, 2026
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