Auto Scroll feature

I wanted the auto-scroll feature replicated in Safari without using a separate app (it works OOB in Firefox). Auto-scroll can be described as clicking and holding MMB once, then move the cursor above or below the click point to scroll continuously, with scrolling speed based on distance from that point.

It works quite well and doesn’t interfere with a normal MMB click. See screenshots for how I configured it.

auto-scroll.bttpreset (8.3 KB)

Floating menu for auto-scroll.bttpreset (38.1 KB)

Code
If you’d rather configure it yourself, here are the steps:

For MMB down, run Real JavaScript action:

async function autoscrollDownHandler() {
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

await set_number_variable({
variable_name: 'autoscroll_abort',
to: 0
});

const anchorY = Number(await get_number_variable({
variable_name: 'mouse_position_y'
})) || 0;

const deadzone = 12;
const tickMs = 8;
const smoothing = 0.20;
const maxStep = 34;

let filteredDy = 0;
let fractionalCarry = 0;

while (true) {
const abortNow = Number(await get_number_variable({
variable_name: 'autoscroll_abort'
})) || 0;

if (abortNow) break;

const currentY = Number(await get_number_variable({
  variable_name: 'mouse_position_y'
})) || 0;

const rawDy = currentY - anchorY;
filteredDy = filteredDy + (rawDy - filteredDy) * smoothing;

const distance = Math.abs(filteredDy);

if (distance > deadzone) {
  const effective = distance - deadzone;
  let step = 0;

  if (effective <= 30) {
    step = effective * 0.06;
  } else if (effective <= 90) {
    step = 1.8 + (effective - 30) * 0.14;
  } else {
    step = 10.2 + (effective - 90) * 0.28;
  }

  step = Math.min(step, maxStep);

  const signedStepFloat = filteredDy < 0 ? -step : step;

  fractionalCarry += signedStepFloat;
  const signedStepInt = fractionalCarry > 0
    ? Math.floor(fractionalCarry)
    : Math.ceil(fractionalCarry);

  fractionalCarry -= signedStepInt;

  if (signedStepInt !== 0) {
    await trigger_action({
      json: JSON.stringify({
        BTTPredefinedActionType: 272,
        BTTPredefinedActionName: "Send Scroll Event",
        BTTScrollBy: `{0,${signedStepInt}}`
      }),
      wait_for_reply: false
    });
  }
} else {
  filteredDy *= 0.75;
}

await sleep(tickMs);

}

return "done";
}

For MMB up, Run Real Javascript action:

async function autoscrollUpHandler() {
await set_number_variable({
variable_name: 'autoscroll_abort',
to: 1
});

await set_string_variable({
variable_name: 'autoscroll_debug',
to: 'stopped'
});

return "done";
}

Feel free to tweak the consts to your liking.

For the floating menu (purely cosmetic), simply create an empty one and only show an auto-scroll-icon.

Screenshots:

this is great, however I would probably recommend to use the newer "Start Smooth Scroll" and "Stop Smooth Scroll" actions. Similar to what is done here:

Thanks! I initially considered that and actually tried re-purposing it, but could only get it working for constant-speed scrolling. Here, the scrolling speed must be able to vary based on cursor’s vertical distance to original clicking point.

ah that makes sense!

It might make also sense for me to add a native auto scroll feature that internally uses the smooth scrolling code, that would probably make it a bit nicer.

I added a basic auto-scroll action in 6.264 based on BTT's scroll modifier. It seems to work pretty well only one problem: the scroll events are sent to the content behind the mouse cursor, not behind the auto-scroll indicator. It might be possible to fix this but it will require some modifications to the smooth scroll modifier.

any instructions how to use this auto-scrolling having MX Master 3S?

you can assign the auto scroll action to any mouse button e.g. to the middle mouse button