ydotool is an alternative to xdotool that works on both X11 and Wayland

A settings window for a Stream Deck that shows the syntax for a button press in the centre. There is a text box where the command can be entered and show here is the text: ydotool key 56:1 106:1 106:0 56:0

I’m still in the process of fully migrating to Wayland from X11 on Linux, as there are still a few niggly things that don’t work 100%. At least Wayland is now stable for me on Manjaro Plasma desktop. But one challenge was getting keystrokes and mouse actions to work on Wayland, as all my shortcut keys on my Stream Deck are set up using the great xdotool which does all that, as well as window functions.

So ydotool does do the keystrokes and mouse actions quite well (using the identical syntax on Wayland and X11) but there are some caveats unfortunately:
* It does not do any window functions like resize, move, bring into focus, or therefore, directing actions straight into a background window. And worse, even wmctrl misses some windows on Wayland – it recognised the Zoom Meeting window but not Kdenlive, but I need to test it out more thoroughly.
* It has an unintuitive syntax as everything is keycodes such as 28:1 to press and 28:0 to release instead of xdotool’s alt+g for example.
* The instructions to install are “messy” with it installing as a user service when it should be a systemwide service. It may be that the documentation is a bit out of sync.

The reason ydotool works the same across Wayland, X11 and even other desktops (You can use it on anything as long as it accepts keyboard/mouse/whatever input. For example, X11, text console, “RetroArch OS”, fbdev apps (fbterm/mplayer/SDL1/LittleVGL/Qt Embedded), etc.), is that it uses the uinput framework of Linux kernel to emulate an input device, unlike xdotool which directs all its output only to the X server (it would have to be rewritten for Wayland to work there). I do have XWayland installed, so this is showing that keystrokes from xdotool appear in my terminal window, but not for example in application windows such as Kdenlive and others. So yes, maybe xdotool and / or XWayland get improved to handle xdotool properly still…

But for those who are interested in trying ydotool I’m going to just expand on the syntax as well as installation issues a bit as I spent hours finding the info, and this will at least give you some quick context, and save you some time:


As I said it must be a systemwide service (ignore what it’s help says) so any systemctl commands must be run with sudo. I installed it from the AUR on Majaro, but I gather the compiling also installs it’s systemd service config file in /usr/lib/systemd/user/ instead of /usr/lib/systemd/system/ so these are the steps I followed to get installation right:
1. I moved the service file it made (/usr/lib/systemd/user/ydotool.service to /usr/lib/systemd/system/.
2. I edited the service file with sudo nano /usr/lib/systemd/system/ydotool.service and changed the ExecStart line as per insert below. Note that the 1000 refers to the usual default user on Linux so in my case this was correct. If in doubt, run whoami | xargs id -u to check your user number. This change is needed so that it creates the socket where ydotool expects to find it, and also that the socket is owned and readable by the non-root user.

# /usr/lib/systemd/system/ydotool.service
Description=Starts ydotoold service

ExecStartPre=/bin/sleep 30
ExecStart=/usr/bin/ydotoold --socket-path="/run/user/1000/.ydotool_socket" --socket-own="1000:1000"
ExecReload=/usr/bin/kill -HUP $MAINPID


The key thing now is to enable and start that service systemwide, so the following needs to be executed:

sudo systemctl daemon-reload
sudo systemctl enable ydotool.service
sudo systemctl start ydotool.service
sudo systemctl status ydotool.service

A last step was to also set the environment variable in the .bashrc file in the users home directory. I just added this line export YDOTOOL_SOCKET="/run/user/1000/.ydotool_socket".

Personally, I really think the ydotool installation should just be fixed for all of this. It relates mainly to it being installed as a user service instead of a systemwide service…


It looks a bit intimidating, but you only set this up once if you have the hang of it, it is pretty easy to do, but you do need to open the following file to view, so you know which are the correct keycodes to use on your computer.

The other thing to remember is you execute key presses, and then release in the reverse order. So for example where I may want to send an Alt+Right with xdotool I would just execute: xdotool key Alt_L+Right it will be ydotool key 56:1 106:1 106:0 56:0 for ydotool. The 56:1 means press the Alt key and the 56:0 means release the Alt key.

For something like Alt and Right Arrow xdotool would be xdotool key Alt_L+Right whilst ydotool would be ydotool key 56:1 106:1 106:0 56:0.

But if you want to paste whole strings of text, for a mail signature for example, it is quite similar to xdotool using the type command, so this is an example of how you would insert Best Wishes, and newline, and Name Surname for both:
* xdotool is: xdotool type "Best Wishes" && xdotool key Return && xdotool type "Name Surname"
* ydotool is: ydotool type "Best Wishes" && ydotool key 28:1 28:0 && ydotool type "Name Surname"

I see that ydotool is apparently being rewritten in JavaScript later in 2024 so maybe lots of the current issues will be sorted out soon. More info at their project at https://github.com/ReimuNotMoe/ydotool.

EDIT: I still had an issue after rebooting, and it seemed that the ydotool systemd service was not changing to preset enabled (despite the enable command). So I did two things and not too sure which made it work, but it is now working fine after reboots:
* Added enable ytool.service in /usr/lib/systemd/system-preset/90-systemd.preset file.
* In the service file above, I changed the default.target with multi-user.target. The latter is supposedly for system-wide service.

I also added the prestart sleep delay in the service config file because I noticed the systemd service started if I ran it manually after login, but not when booting. That delay seemed to allow for the same thing and sorted out the socket file not found issue.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.