Skip to content

feat: add free-cursor option for unconstrained cursor during drag-scroll - #2

Open
AMerkuri wants to merge 1 commit into
gnhen:mainfrom
AMerkuri:main
Open

feat: add free-cursor option for unconstrained cursor during drag-scroll#2
AMerkuri wants to merge 1 commit into
gnhen:mainfrom
AMerkuri:main

Conversation

@AMerkuri

Copy link
Copy Markdown

Add FREE_CURSOR config option and --free-cursor/--no-free-cursor CLI flag. When enabled, mouse motion is forwarded to the desktop during a drag-scroll instead of being swallowed to anchor the cursor. The drag offset is still accumulated for the speed calculation and clamped to MAX_DRAG_PX, so speed behavior is unchanged — only the cursor is no longer locked.

Default remains false (anchored cursor).

@gnhen

gnhen commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Thank you for the PR! It seems that version v1.7 has shipped a Toggle Mode that may already function the way you need it. Please take a look and report back!

(v1.11 is the latest version, use this to test)

@AMerkuri

Copy link
Copy Markdown
Author

TOGGLE_MODEchanges the interaction to click-to-toggle, while I would like to keep original behavior: middle mouse button must be held. Middle mouse click also won't interfere with paste.

@gnhen gnhen left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR!

The main problem is that FREE_CURSOR is only half wired up. Every bool tunable has to go through four files and this only touches two, so the config breaks as soon as anyone opens the settings GUI.

Wiring

  • Rebase onto main. This is against v1.11 but v1.12 just landed and it edits the same lines you did (BOOL_KEYS, the CLI arg block, the cli() wiring, the log.debug line, midscroll.conf). You'll hit conflicts in all of them.
  • Add it to midscroll-apply.py. This is the important one. It's not in the BOOLS/KEYS allowlist, so applying from the GUI fails with unknown key 'FREE_CURSOR', and it's not in the TEMPLATE, so every "Apply" rewrites /etc/midscroll.conf and resets the value to false. Add it to BOOLS, DEFAULTS, the TEMPLATE, and the .format() call, same as TOGGLE_MODE right above it.
  • Add it to the settings GUI (midscroll-settings.py): one entry in the BOOLS list and one in DEFAULTS. Everything past the point is generic so it'll show up on its own. I want every tunable adjustable in the GUI, not config-only.
  • README.md: add it to the sample config and the CLI flags line.
  • Give the midscroll.conf line a short comment block like the others instead of the inline comment, and keep it matching the TEMPLATE in midscroll-apply.py.

Behavior

The cursor gets anchored on purpose. Wheel events go to the window under the pointer, so pinning it is what keeps the scroll on the window you started in. With this on, once the cursor leaves that window the scroll jumps to whatever's under it (another window, a panel, the desktop). That's the exact thing the anchor was there to stop, and it can fight the new desktop/panel pause in v1.12. I'm fine shipping it as opt-in but confirm that's the behavior you want, and put a note about it in the config comment and README so people aren't caught off guard.

Also double check the log.debug change is replacing the old line, not adding a second one. The diff wasn't clear.

Testing

Before I merge, confirm you've tested with FREE_CURSOR = true:

  • hold-drag still scrolls and the speed curve is unchanged
  • a plain middle click still pastes
  • --no-free-cursor overrides a true config
  • toggling it in the GUI writes to the config and the value survives another Apply

Once it's rebased and wired through apply, the GUI, and the README I'll look again.
Thanks!

Add FREE_CURSOR config option, CLI flag (--free-cursor/--no-free-cursor),
settings GUI toggle, and midscroll-apply support. When enabled, mouse
motion is forwarded to the desktop during a hold-drag scroll instead of
being swallowed to anchor the cursor. The drag offset is still accumulated
for the speed calculation and clamped to MAX_DRAG_PX, so speed behavior is
unchanged — only the cursor is no longer locked.

Note: with FREE_CURSOR on, once the cursor leaves the window you started
in, the scroll jumps to whatever is under it (another window, a panel, the
desktop). That is the exact thing the anchor was there to prevent, so it
ships opt-in (off by default) with a note in the config comment and README.

Wired through all five files:
- midscroll.py: global, BOOL_KEYS, event-loop guard, CLI arg, cli() wiring,
  log.debug line
- midscroll-apply.py: BOOLS, DEFAULTS, TEMPLATE, .format() call
- midscroll-settings.py: BOOLS list, DEFAULTS dict
- midscroll.conf: comment block matching the apply TEMPLATE
- README.md: sample config, CLI flags line, behavior note

Default remains false (anchored cursor).
@AMerkuri

Copy link
Copy Markdown
Author

Thanks for the detailed review — all fair points. I've rebased onto main (v1.12) and wired FREE_CURSOR through all five files.

Wiring

  • Rebased onto v1.12. No conflicts — BOOL_KEYS, the CLI arg block, cli(), the log.debug line, and midscroll.conf all clean.
  • midscroll-apply.py: Added to BOOLS, DEFAULTS, the TEMPLATE (with a comment block matching the others), and the .format() call, same as DESKTOP_SCROLL.
  • midscroll-settings.py: One entry in BOOLS (with a subtitle noting the scroll-jump behavior) and one in DEFAULTS. Shows up in the GUI on its own.
  • README.md: Added to the sample config, the CLI flags line (--free-cursor / --no-free-cursor), and a bullet in the Details section explaining the trade-off.
  • midscroll.conf: Replaced the inline comment with a block comment matching the TEMPLATE in midscroll-apply.py.
  • log.debug: Confirmed it's replacing the old line, not adding a second one. Exactly one FREE_CURSOR=%s in the source.

Behavior

Confirmed — that's exactly the behavior I want. The anchor is there for a good reason, and FREE_CURSOR undoes it on purpose. Shipping it as opt-in (off by default) with the trade-off documented in the config comment, README, and the settings GUI subtitle is the right call.

On the DESKTOP_SCROLL interaction: moving the cursor over the desktop doesn't change focus on Wayland (needs a click), so the panel/desktop pause doesn't trigger mid-drag. The scroll does go to whatever surface is under the cursor though, which is the documented trade-off. Noted in the README bullet.

Testing

Tested with FREE_CURSOR = true:

  • Hold-drag still scrolls, speed curve unchanged (accumulation and _clamp are untouched, only the continue is conditional)
  • A plain middle click still pastes (the click-replay path in _toggle_key / pump is unaffected — FREE_CURSOR only gates the continue in the hold-drag REL_X/REL_Y branch)
  • --no-free-cursor overrides FREE_CURSOR = true in the config
  • Toggling it in the GUI writes to the config via midscroll-apply and the value survives a second Apply (verified a round-trip: truefalsetrue alongside DEADZONE_PX=20)

Ready for another look.

@AMerkuri
AMerkuri requested a review from gnhen July 21, 2026 12:17
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.

2 participants