Middle mouse button (scroll wheel) drag lock (toggle) in niri with libinput?

hey every! :nerd_face:

i have a bit of an odd one, this, um, VERY SILLY question, so much so that there are no results whatsoever anywhere on the entire internet (as most of my questions are), except this perchance?… anyway, my mouse is kinda old and broken, so…

i wanna have a “swipe” gesture (like in touch devices with two or three fingers) bound to my middle MOUSE button (aka BTN_MIDDLE (274)) WITHOUT external input remappers…

so, in niri, holding the Mod (Super) key AND the middle mouse button AND moving the mouse/cursor “swipes” the workspaces/windows/monitors around (which is something that ive learnt extremely late ROFL)… but i DONT wanna hold, i wanna toggle it, mate! :sob: ESPECIALLY because my mouse cursor can only go so far within the confines of my little monitor resolution!

did this in config.kdl, tried everything for nothing…

// bla

input {
  mouse {
    scroll-button-lock // THIS
    scroll-method "on-button-down" // default="two-finger"
    scroll-button 274 // in 'wev' AND 'libinput debug-events'
    // middle-emulation // whatever
  }
}

// haj

those thingies do this stuff:

scroll-method: when to generate scroll events instead of pointer motion events, can be no-scroll, two-finger, edge, or on-button-down. The default and supported methods vary depending on the device type.

I HOPE i understand this one correctly, that i am looking for on-button-down here, right? i want it to TOGGLE, yeah?

scroll-button: the button code used for the on-button-down scroll method. You can find it in libinput debug-events.

btw, services.libinput.enable does NOT install libinput (command)

okay, then, sure, lets see what it says…

left mouse button:

event18 POINTER_BUTTON BTN_LEFT (272) pressed, seat count: 1
event18 POINTER_BUTTON BTN_LEFT (272) released, seat count: 0

right mouse button:

event18 POINTER_BUTTON BTN_RIGHT (273) pressed, seat count: 1
event18 POINTER_BUTTON BTN_RIGHT (273) released, seat count: 0

middle mouse button:

event18 POINTER_BUTTON BTN_MIDDLE (274) pressed, seat count: 1
event18 POINTER_BUTTON BTN_MIDDLE (274) released, seat count: 0

…alright, and now lets try in wev:
left:

[15: wl_pointer] button: serial: 118743; time: 1135739; button: 272 (left), state: 1 (pressed)
[15: wl_pointer] button: serial: 118744; time: 1135869; button: 272 (left), state: 0 (released)

right:

[15: wl_pointer] button: serial: 118747; time: 1136782; button: 273 (right), state: 1 (pressed)
[15: wl_pointer] button: serial: 118748; time: 1136885; button: 273 (right), state: 0 (released)

middle:

[15: wl_pointer] button: serial: 118754; time: 1138012; button: 274 (middle), state: 1 (pressed)
[15: wl_pointer] button: serial: 118755; time: 1138191; button: 274 (middle), state: 0 (released)

see? all is well here… now, then…

scroll-button-lock: when enabled, the button does not need to be held down. Pressing once engages scrolling, pressing a second time disengages it, and double click acts as single click of the the underlying button.

THAT (above), is what i want.

so, the reason why im doing THAT is because niri has a helluva lot of HARDCODED keybindings, including a few for the mouse, so that swiping “feature” is completely UNBOUNDABLE! this “scroll locking” is completely ignored by niri (cursor “freezes” BUT doesnt “swipe” windows), but it does work in other (some) apps (content swiping). there is also a problem of it being NOT omnidirectional, so it “swipes” or “scrolls” ONLY either horizontally OR vertically, depending on mouse movement, which is expected, but i would prefer if it was “unlocked”, you know, as if the cursor’s X/Y relative position determined the swiping/scrolling speed or something (well, okay, as it is right now, it is absolute, which also works, but, you know, what if someone like me wants it to scroll/swipe continuously)…? oh, you know, like if you zoomed into an image on your phone and could just freely look around anywhere, or, again, just like in browsers (except those seem to be more random, i hate when it goes only one way, when there is literally text/content above it, man…). actually, hold on, EVEN BETTER: i also dont want the cursor to “freeze”, yeah. that is just annoying. it, uh, also should have been an option both for niri and libinput… right, so, anyway, uh…

edit: okay, it gets even weirder. apparently holding (left) shift button with the scroll lock toggled on does make it scroll horizontally in some apps, but i must STILL scroll vertically (i mean, as in literally move my mouse upwards or downwards, ugh!), which is unintuitive. MOREOVER, it doesnt work vice versa, so, if i am already scrolling horizontally, holding shift wont make it go vertical… so that is some freedom, in a sense, haha, to the overall degrees of freedom… but anyway, uh, nope, this “trick” doesnt work with niri, once again…

the hardcoded binding, btw, is on Mod+MouseMiddle which has no niri msg action associated with it that you can REBIND, only override, which is again, horrid. not a fan of that at all. there is also, apparently, no way of listing all the binds and their actions…

so, yeah, i DONT want it to “emulate” the actual mice’ scroll wheel event scrolling, i want it to basically AUTOSCROLL, smoothly, and/or GLOBALLY (for now until there is no other way?), until it is pressed again (or interrupted) to toggle off, just like in firefox-based browsers, where you can BOTH hold OR toggle it, right..? that is, again, if possible, WITHOUT input remappers, please… also yes, if this will work, i will have to disable the browsers’ autoscroll on the middle button, unless… it wont scroll the content there, that is, i havent tried that, actually

well, my misadventures continue then in libinput, which is basically the same story… except it doesnt work at all there? i believe im doing something wrong here..?

libinput says:

Option "ScrollMethod" "string"
Enables a scroll method. Permitted values are none, twofinger, edge, button. Not all devices support all options, if an option is unsupported, the default scroll option for this device is used.

which is…
input { mouse { scroll-method "on-button-down" } } in niri
or
services.libinput.mouse.scrollMethod = "button"; in nixos

Option "ScrollButton" "int"
Designates a button as scroll button. If the ScrollMethod is button and the button is logically down, x/y axis movement is converted into scroll events.

which is…
input { mouse { scroll-button 274 } } in niri
or
services.libinput.mouse.scrollButton = 274; in nixos

once again, 272 is left, 273 is right, 274 is middle (which follows the MOUSE1, MOUSE2, MOUSE3 mouse bindings respectively in games)

Option "ScrollButtonLock" "bool"
Enables or disables the scroll button lock. If enabled, the ScrollButton is considered logically down after the first click and remains down until the second click of that button. If disabled (the default), the ScrollButton button is considered logically down while held down and up once physically released.

which is…
input { mouse { scroll-button-lock } } in niri

Option "DragLockButtons" "L1 B1 L2 B2 ..."
Sets “drag lock buttons” that simulate a button logically down even when it has been physically released. To logically release a locked button, a second click of the same button is required.

If the option is a single button number, that button acts as the “meta” locking button for the next button number. See section BUTTON DRAG LOCK for details.

If the option is a list of button number pairs, the first number of each number pair is the lock button, the second number the logical button number to be locked. See section BUTTON DRAG LOCK for details.

For both meta and button pair configuration, the button numbers are device button numbers, i.e. the ButtonMapping applies after drag lock.

if i understand this one right, its just one button that i need to “lock”, right..? its just one button… nothing else, one button to “lock”, same button to “unlock”… shrimple as that… PLEASE

which is AGAIN (presumably)
input { mouse { scroll-button-lock } } in niri
or all together now in nixos (configuration.nix)…

  # bla

  services.libinput.enable = true; # default=false
  services.libinput.scrollMethod = "button";
  services.libinput.scrollButton = 274;
  services.libinput.mouse.additionalOptions = ''
    Option "ScrollButtonLock" "true"
    Option "DragLockButtons" "2"
  '';

  # haj

…yep, there are no dedicated options for this. guess its THAT obscure, huh, which is why i mentioned this being an odd one, yeah?

but do you notice that this "DragLockButtons" is different, yeah? i cant figure this one out, it makes no sense to me. in the link at the very top, there is a guy saying that "1", "2" and "3" are left, MIDDLE and right mouse buttons respectively, which is EXTREMELY confusing. so, then i found that it is following the “button mapping” in an ascending order starting from "1"… but i… tried that and… nothing..? its so over for me.

BUTTON MAPPING

X clients receive events with logical button numbers, where 1, 2, 3 are usually interpreted as left, middle, right and logical buttons 4, 5, 6, 7 are usually interpreted as scroll up, down, left, right. The fourth and fifth physical buttons on a device will thus send logical buttons 8 and 9. The ButtonMapping option adjusts the logical button mapping, it does not affect how a physical button is mapped to a logical button.

Traditionally, a device was set to left-handed button mode by applying a button mapping of “3 2 1 …” On systems using the libinput Xorg input driver it is recommended to use the LeftHanded option instead.

The libinput Xorg input driver does not use the button mapping after setup. Use XSetPointerMapping(3) to modify the button mapping at runtime.

no idea why they are talking about xorg here, how does libinput work on wayland, then..? what do "L1 B1 L2 B2 ..." buttons even represent, if 4, 5, 6, 7 logical buttons are presumably ACTUAL scroll wheel directional “ticks” (NOT what i need, again, thats a different kind of “scrolling”)? like, what is even happening right now..? are those press, drag/hold, release events, perhaps..?

edit: oh, btw, YES, the "1 2", "3 2", "1 3 2", etc. button numbers do seem to work (?), but its the same behaviour. niri is ignoring this, other apps dont.

so, yeah… IN SHORT, is this a niri issue (where middle mouse button scroll wheel lock WITH Mod+MouseMiddle doesnt work, MOUTHFUL!) or i messed up or… there is an easier way apart from “just using a keyboard ROFL”? i just dont wanna install an entire remapper which will run in the background JUST FOR ONE GESTURE, do you know what i mean? that would certainly be a bit of an overkill, right..?

AGAIN, YES, this is easily fixed IF niri actually allowed me to rebind the scroll wheel’s HARDCODED action itself, which is the swiping gesture, remember? at that point i wouldnt mind it being ONLY used for the niri itself, and not other apps (globally, that is)… i dunno, with some other random modifier key, right..? BUT, um, it doesnt explain why then it only works partially, and Mod key is completely ignored, as i said? a little sus, this, cos it could be a misconfiguration on my end or… straight up just a libinput limitation or something? ah, jeez, i hope i phrased that alright, cos its hard to put all this into words, oh well… im gonna test some more now!

cheers!!1 LOL sorry for these wallz of text, i only realise it now! :stuck_out_tongue:

edit: unrelated (?), but these are the only (?) mentions of Mod+MouseMiddle (dys)function i found so far after mindlessly scrolling through niri’s issues…

edit: oh, actually, hold on, theres a bit more, also unrelated, cos i am apparently the ONLY crazy one wanting mouse gestures, which is, in retrospect, something that i would have never wanted or needed like… a couple months ago? yeah, but anyway, it appears that this (HARDCODED) gesture is is mostly useful for… ANYTHING, BUT MOUSE? right, i mean, fair, but… they could have at least NOT hardcoded stuff in, you know..?

oh, thats copilot in the pr’s. ok.

mmmm love me some HARDCODE. none of that softcode, man, im on that proper ENGRAVECODE, bro

i mean some are valid, right, like the console and the poweroff ones. or are they?

sorry, im just rambling at this point. i do be yapping

so anyway, i have come to a conclusion that its IMPOSSIBLE to have this gesture WITHOUT some sort of a multi-finger touch device. trackpoints, trackballs? i have them, no, same thing, same buttons, same inputs as the mouse, obviously…

yapping…

OH, also, i keep forgetting, UGH! so, to clarify, i want this “smooth scrolling/swiping gesture thingie” that-i-can-un/re/bind-on-any-key to be used ANYWHERE and NOT limited to the “overview” mode, okay, because as someone who prefers no animations, this swiping gesture is the ONLY one that i like :nerd_face:

i mean, this is how i originally IMAGINED niri to BE. a literally infinite scrolling workspace, like a CANVAS, right, like in one of those painting tools or… or even like this crazy idea (x11, bleh) of an infinite environment, right. well, my expectations of niri so far are… 50%50, to say the least, its like that one time when i didnt get the candy i wanted for halloween and i was very sad. so, i was confused at first why are columns HORIZONTAL and workspaces VERTICAL… still confused, but its alright. my personal problem? false advertisement. hate ads, btw. i THOUGHT that by “infinitely scrolling” i will get… grid-like workspace(s) (for optimisation, right?) where windows are not defined by the monitor’s resolution. and they SORT OF are already, but i thought i could go in ANY direction, as in… SCROLLING, in the USUAL sense means UP or DOWN, right, and i could also hold SHIFT to then go horizontally, like EVERYWHERE else? thats what i thought! AND, moreover, i thought that i could have the option of ACTUAL scrolling with the SCROLL WHEEL (can do this), or the smooth/incremental DRAG/SWIPE gesture (cant do this), right??? just like with the window dragging when you reach the “trigger”/edge of the screen, it scrolls smoothly, right? OR! or! even better: JUST put your mouse to the edge of the screen to “scroll” (with or without an additional modifier!). thought thats an option, but no. but OKAY, okay, relax, i CANT go up or down, FINE, those would be different workspaces, then, BUT! problem number two: WINDOW FOCUSING. so, i wanna be able to do that with ANY device. a mouse, a keyboard, touch, joy, etc. what i get instead is… cursor-focusing that can be EASILY overshot, because every single window is the same width, so that BY the time i focus another window, the same cursor is literally just a few pixels away from OVERSHOOTING and focusing ANOTHER window, which is extremely annoying. this is EASILY fixed by warping the MOUSE CURSOR, but there is no such feature… IN A SCROLLING DESKTOP! unless you use keyboard bindings, that is, but thats NOT SCROLLING! okay? that is SWITCHING! that i can do… in any wm??? jeez. OKAY, then, if mouse focusing isnt working for me, then… OH! would you look at this, a conveniently HARDCODED mouse binding that SCROLLS (smoothly so, very nice) WINDOWS AND/OR WORKSPACES in ANY DIRECTION! sorry, lots of uppercases. ahem… cant bind it, mate. no. oh well. fucking hell. so, again, its RAW. i thought speedrunners are good at implementing/executing ideas… sheesh, cant even scroll in a scrolling envo. tell you what, the Mod+WheelScrollUp/Mod+WheelScrollDown do seem to warp the mouse, at least, but… that is NOT SCROLLING, it just ISNT, okay… @#$%, man, UGH!

oh, im yapping again :roll_eyes: SORRY