linux-autoscroll
linux-autoscroll copied to clipboard
Can your script be adapted for Wayland, as well as current X11?
Hello
I use KDE Plasma 5 for my ArchLinux's DE. Mostly atm i still login with X11 desktop sessions, but as the KDE Devs' ongoing Wayland improvements continue, more & more i am instead trialling Plasma Wayland sessions. Afaik your script atm is exclusively for X11. Do you think it might be possible to expand/modify it for use also in Wayland sessions please?
Hi! As far as I know, the library I use for listening and sending mouse events doesn't support Wayland (https://github.com/moses-palmer/pynput/issues/331). The problem is that there are no good alternatives to pynput. Initially I wanted to use mouse but it seems like it doesn't generate scroll events properly.
i'm running it on Xwayland without any issues (DE is Gnome)
Xwayland
Yes i know; also in KDE Plasma it still works fine in apps if they run in Xwayland mode... but that's not what i want. When i login to Plasma Wayland, i want to run my apps in full-Wayland mode. However, as i said in my OP, the script is inactive in Wayland apps.
This post is simply to cross-reference this nice news contained in one of my other Issues, given it is absolutely relevant to this Issue.
The great pity of all this is that, as we canvassed before in a different Issue, this python script does not work in Plasma Wayland.
I'm trying to make the script compatible with Wayland. The version without the icon is already complete.
Originally posted by @TWolczanski in https://github.com/TWolczanski/linux-autoscroll/issues/8#issuecomment-1053739416
That's exciting news!
The version without the icon is already complete
I assume that version is still only local to you, because the latest version you gave me yesterday in my other Issue, is still not working for me in Plasma Wayland here [except for individual apps running as Xwayland apps, which i don't count, as the whole point of me using a Wayland session is to be able to run all my apps in full-wayland mode].
I keenly look forward to your next push version.
@guigirl42
I assume that version is still only local to you
That's right, I haven't pushed it to GitHub yet.
Please check if this code works on your Plasma Wayland (it's the no-icon version I mentioned):
from evdev import InputDevice, list_devices, UInput, ecodes as e
from threading import Event, Thread
from time import sleep
class Autoscroll:
def __init__(self):
# modify this to adjust the speed of scrolling
self.DELAY = 5
# modify this to change the button used for entering the scroll mode
self.BUTTON_START = e.BTN_MIDDLE
# modify this to change the button used for exiting the scroll mode
self.BUTTON_STOP = e.BTN_MIDDLE
# modify this to change the size (in px) of the area below and above the starting point where scrolling is paused
self.DEAD_AREA = 30
self.scroll_mode = Event()
def on_move(self, dy):
if self.scroll_mode.is_set():
self.delta += dy
if abs(self.delta) <= self.DEAD_AREA:
self.direction = 0
elif self.delta < 0:
self.direction = 1
elif self.delta > 0:
self.direction = -1
if abs(self.delta) <= self.DEAD_AREA + self.DELAY * 2:
self.interval = 0.5
else:
self.interval = self.DELAY / (abs(self.delta) - self.DEAD_AREA)
def on_click(self, button, pressed):
if button == self.BUTTON_START and pressed and not self.scroll_mode.is_set():
self.delta = 0
self.direction = 0
self.interval = 0.5
self.scroll_mode.set()
elif button == self.BUTTON_STOP and pressed and self.scroll_mode.is_set():
self.scroll_mode.clear()
def find_mouse(self):
mouse = None
paths = list_devices()
count_max = 0
for path in paths:
device = InputDevice(path)
cap = device.capabilities()
events = cap.keys()
if 1 in events and 2 in events:
if 1 in cap[2] and 8 in cap[2]:
count = sum(cap[1])
if count > count_max:
count_max = count
if mouse is not None:
mouse.close()
mouse = device
continue
device.close()
if mouse is None:
raise OSError("No mouse found")
return mouse
def listen(self):
for event in self.mouse.read_loop():
if event.type == e.EV_KEY:
button = event.code
pressed = (event.value == 1)
if button == e.BTN_RIGHT:
self.time_to_quit = True
self.delta = 0
self.direction = 0
self.interval = 0
self.scroll_mode.set()
break
self.on_click(button, pressed)
elif event.type == e.EV_REL and event.code == e.REL_Y:
dy = event.value
self.on_move(dy)
def start(self):
self.mouse = self.find_mouse()
self.ui = UInput.from_device(self.mouse)
self.time_to_quit = False
self.listener = Thread(target=self.listen)
self.listener.start()
while not self.time_to_quit:
self.scroll_mode.wait()
sleep(self.interval)
# scroll
self.ui.write(e.EV_REL, e.REL_WHEEL, self.direction)
self.ui.syn()
self.mouse.close()
self.ui.close()
autoscroll = Autoscroll()
autoscroll.start()
You don't have to install any new libraries (evdev is automatically installed when you install pynput). I would like you to test the script in the terminal - I made sure that when you kill it by right click, the device files are properly closed. Note that BUTTON_START
and BUTTON_STOP
have different values now. For the left click you should use e.BTN_LEFT
and for the right click e.BTN_RIGHT
.
I've tested this script on Xorg and it works fine (even better than the current no-icon version). As it uses uinput, it should work on Wayland too (I'm waiting for your feedback though). The problem is how to implement the version with the icon - on Wayland it's not possible to get the absolute mouse pointer position (at least not without hacking).
Hi. Thanks for your ongoing efforts here.
No joy i'm afraid; it throws errors & exits. My only edits to your latest paste were to change the stop line to self.BUTTON_STOP = e.BTN_LEFT
, & to insert #!/home/guigirl/linux-autoscroll/.autoscroll/bin/python3
at the top as usual. However, both times that i tried to run it:
guigirl@archlinuxTower[~/linux-autoscroll] 13:27:05 Tue Mar 01 $> ./autoscroll_no_icon.py
Traceback (most recent call last):
File "/home/guigirl/linux-autoscroll/./autoscroll_no_icon.py", line 103, in <module>
autoscroll.start()
File "/home/guigirl/linux-autoscroll/./autoscroll_no_icon.py", line 86, in start
self.mouse = self.find_mouse()
File "/home/guigirl/linux-autoscroll/./autoscroll_no_icon.py", line 65, in find_mouse
raise OSError("No mouse found")
OSError: No mouse found
guigirl@archlinuxTower[~/linux-autoscroll] 13:27:12 Tue Mar 01 $>
I forgot to mention that the script needs to be run with sudo
. Otherwise it won't have access to /dev/input
and the "No mouse found" error will be raised.
Yes, running in terminal as sudo indeed does work. However, now i'm confused how to translate this to my autostart settings, because how can i sudo-run there? Furthermore, no insult intended, but i'm not sure that i want to have to permanently run a script with elevated privileges. Am i misunderstanding?
how to translate this to my autostart settings, because how can i sudo-run there?
It's likely that you can't. However, there are other ways to run a script as root at startup.
i'm not sure that i want to have to permanently run a script with elevated privileges
As there is no way other than reading raw device events (uinput) to make the script compatible with Wayland, it'll have to be run with elevated privileges. Alternatively, you could add yourself to the input
group, but I don't know if this is safe. I'll try to find a better solution when I have time.
OK. Unfortunately i find myself now losing enthusiasm at this unexpected, albeit possibly unavoidable, new direction. For now i think i'll just sit on the sidelines & watch for any possible future non-sudo breakthroughs.
Many thanks for your hard work.
Dear @TWolczanski -- i have [IMO] some wonderful news for you, albeit it might actually make you sad [because of all the hard work with your nice project here].
Today, in the Vivaldi [browser] forum, i discovered that, apparently buried deep inside the chromium code for some years, is the capability to invoke MMB-Autoscroll natively in chromium-based Linux browsers. 😮
Our forum discussions lead to this -- https://medium.com/@1nikolas/linux-enable-middle-mouse-button-scrolling-on-chrome-ium-and-electron-apps-discord-etc-ab2d0a213505. Here's the magic [simply append this chromium commandline switch to all your chromium-based browser launchers]:
--enable-blink-features=MiddleClickAutoscroll
After testing it, i posted this confirmation in the forum:
I am most happy to report that, as well as this switch working beautifully in my Arch KDE X11 session [which was active for all my earlier posts above], atm i am logged into my Arch KDE Wayland session, in which this switch continues to work perfectly [my Vivaldi is herein running as a full-wayland app via my already-present other switch
--ozone-platform-hint=auto
]. 👍
Anyway, i thought you might like to know about this information. Best wishes!
Hi @guigirl42, thanks for the exciting news! I'll however continue using the script despite its low speed jerkiness as I've just got used to my current config and I also don't want to limit myself to the browser.
Speaking of low speed jerkiness, I've recently found this article: https://www.phoronix.com/scan.php?page=news_item&px=xf86-input-libinput-1.2
It's possible that a slight modification to the script I posted in this issue can result in a smooth autoscroll experience at low speed, provided that your libinput version is at least 1.19 and your xf86-input-libinput version is at least 1.2. Unfortunately, these requirements aren't met on my machine. I successfully installed the newest version of libinput, but failed to build xf86-input-libinput. The modification I'm talking about is replacing self.ui.write(e.EV_REL, e.REL_WHEEL, self.direction)
with self.ui.write(e.EV_REL, e.REL_WHEEL_HI_RES, self.direction * 16)
(the multiplier in the third argument doesn't need to be 16).