Toshy v23.08: Mac-like per-app keyboard shortcuts for Linux

I just managed to make my project (Toshy) install and work on OpenMandriva ROME 2023.8, and I’m not sure where else to put an announcement about it. The project uses a keymapper to translate keyboard shortcuts, so that most shortcuts in most applications work the same way you would expect them to work in macOS, while using an Apple keyboard. So it makes moving between macOS and Linux much less irritating.

It’s usable on most Linux desktop environments in an X11/Xorg session, and Wayland+KDE or Wayland+GNOME, but no other Linux desktops will work in a Wayland session yet.

Toshy branched off from an existing project called Kinto, by Ben Reaves (On GitHub at rbreaves/kinto), which also has a Windows version, but Toshy is only for Linux. It adds some new features and a different installer philosophy that helped make it possible to get it working in Wayland environments, and installable on more Linux distributions. Most of the top 50 distros on the DistroWatch list are compatible now.

Anyone interested can find it here:

GitHub - RedBearAK/toshy: Keymapper config to make Linux work like a 'Tosh! (Or:

Submit issues on the GitHub repo.

It would be nice to get some sort of response to this, but I’m not really expecting any. I’m putting this here just in case there is a Mac user or two among the OpenMandriva crowd who might find it useful.

1 Like

Welcome to OpenMandriva and our forum. This forum is for users of OpenMandriva Linux operating systems.

We are a small group. All the contributors and developers here are unpaid volunteers.

You are welcome to talk to our developers at OpenMandriva Chat.

The first thing when a new user has an issue is to look in the documentation for OMLx. OpenMandriva wiki and Forum Resources guide.

If you don’t find what you are looking for try an Internet search (googling). One can find out a lot from documentation or forum posts at other Linux distros. If user finds something written for another distro but you have some doubt ask at OpenMandriva Chat.

For serious technical issues and package/feature requests please file a bug report here.

Looks useful for people who (unlike myself) have to work with Macs – Is there anything we need to pay special attention to while packaging it? (e.g. which files should go into subpackages to avoid dragging in unneeded dependencies, are there any non-obvious dependencies, …)?

1 Like

Ah, the packaging question. No one has ever asked me about that yet, that I can recall. In its current state I’m not sure how well it qualifies as something to be packaged in a typical repo. I’ll describe how it works. This may be much more info than anyone will ever care about.

The project Toshy evolved from was a custom-install sort of situation, with a systemd service unit that ran the keymapper command via sudo (yes, as root). Because that was how xkeysnail (the actual keymapper) was supposed to be run. At least, that was one way it could be run, so that the process would have access to the necessary /dev/uinput device for input/output. And Kinto used xhost as part of the command to open up the X server so that the root process could do its thing.

My project uses a fork of the keymapper called keyszer, which kind of deprecated the run-as-root stuff and promoted a few options such as using a udev rules file to make sure the process has access to the device it needs. That’s what I’ve gone with. So my installer makes sure your user is in the input group, and then installs the appropriate udev rules file depending on whether the system supports ACL permissions or just standard Unix permissions. This of course requires the user to reboot, which is prompted by the installer.

The Toshy installer is completely written from scratch in Python, with a philosophy of “let’s keep as much as possible inside the user’s home instead of messing with the system”. So it literally installs pretty much everything in places like ~/.config/toshy, including the Python venv it uses to keep itself from messing with system Python packages, and helps it work on systems with really old Python, by using a newer Python interpreter if possible when creating the virtual environment.

Technically there are a couple of “apps” that come with the keymapper config that does all the work, but they are just Python scripts also, and are installed alongside the config file in ~/.config/toshy. Because I couldn’t figure out how to do a real Python package for them and install them elsewhere while keeping them working. (Path issues.) One creates an indicator tray icon with menu (works in all the DEs that still support an indicator tray), and the other is a simple GUI preferences app using tkinter. They have the ability to load and save shared settings to an sqlite3 file living in the same folder as the config file, which also watches that file and loads settings from it.

The desktop entry files that add the “apps” to the menu are also installed in the user’s home folder location, so nothing will appear in any other user’s menu unless they also run the installer. And the desktop files point at scripts that only exist in the user’s home. So there is a lot of isolation going on between users. Kind of like a Flatpak installed from a “user” repo instead of systemd-wide.

Because of the manual nature of installing, I’ve added the ability to kind of do upgrades in-place while saving some user-customized sections of the config file, which itself is also a Python module that does quite a lot of complicated stuff. Every time the installer is run, it saves a backup of the config files and then creates a whole new folder for itself with a new venv (the old venv is discarded since it tends to be a few dozen MB in size).

I should probably note that you can actually use Toshy without all the Mac shortcut stuff, by giving the installer the option “–barebones-config”. This is a recent addition. In this case it becomes just a way to install the keyszer keymapper with tools that will make it easy to auto-start, with a collection of terminal management commands, the tray icon with menu, and the GUI window.

I just got finished making the tray icon menu and GUI app automatically simplify themselves when the “barebones” config is in use, so the irrelevant options that only apply to the full config file disappear. You can then do as much or as little as you want with the keymapper’s abilities, starting from a config file that does nothing (besides a simple example keymap that adds a couple of currency symbols to the keyboard).

This is meaningful not just for the management commands (stop/start, enable/disable, verbose debugging output, logging) that make it easier to install and set up the keymapper, but also because Toshy is using a custom development branch of the keymapper, where I was able to add support for the two Wayland environments that currently work (Wayland+GNOME and Wayland+KDE). The mainline keymapper, just like its predecessor, only supports X11/Xorg sessions at this time. I did my testing on OpenMandriva in a Wayland+KDE session, and Wayland+GNOME should work on OpenMandriva just as well as it does on all other distros. (Wayland+GNOME requires a shell extension that you have to install yourself.)

The keymapper has a function that processes strings and Unicode characters, so it can do some kind of advanced output despite just being a simple “virtual keyboard” device. Some of that depends on the environment. Unicode character entry in particular requires ibus, or possibly fcitx (unconfirmed).

The main motivator behind the project was to make sure those who like macOS shortcuts could have access to something like Kinto on additional distros and in at least the primary Wayland environments. Kinto also messed with the sudoers file, which caused it to be incompatible with some distros like antiX. Toshy doesn’t have any need of running anything as root, so it works on antiX. I made sure of that.

One of the most awkward things about the original project is that the keymapper, uses evdev to “grab” the /dev/uinput device, and only one process can do that at a time. So in the original project if you logged out or switched users, the keymapper would continue to affect the keyboard in another user account, or even the login screen. This made it largely incompatible with a multi-user system, or at least weird.

It was a royal pain, but I was finally able to find an obscure bit of info exposed by loginctl (part of systemd) that allowed me to use a separate systemd user service to stop the keymapper service whenever the “session” became inactive. It’s complicated and somewhat delicate, but it works in testing, preventing the keymapper from interfering with another user account. But, it only works if at least the background account is running the keymapper with the systemd user services. Manual usage, which is required on systems that don’t use systemd or while debugging the config, will still prevent another user from trying to run their own keymapper that uses the same /dev/uinput device.

I’ve been meaning to look into whether Toshy could be packaged in a Flatpak, but with all of the groups, permissions and the device it needs, I’m not sure if it is a “Flatpak-able” project. I assume that those would might also be a concern when trying to package it in other ways.

One thing specific to how it installs on OpenMandriva was that I unfortunately had to add task-devel to the package list, so that dbus-python would successfully install (via pip) in the venv. I have always had the most trouble with that Python package, figuring out which native packages will allow it to build/install without an error. In this case I could not pinpoint exactly which of the packages in task-devel actually allowed the install to succeed, but without the whole thing I kept getting errors from the meson build process like “gcc cannot compile programs” during that stage of the install process.

I say “unfortunately” only because that OpenMandriva meta-package downloads around 230MB of additional packages, and the usual list of native dependencies for Toshy only downloads 55-110MB of new packages in total.

Below is the package list I ended up with for getting it working on OpenMandriva. It may have one or two redundancies, but I got tired of resetting the VM to double-check whether each one was absolutely necessary on its own and not automatically installed as a dependency of something else on the list. I did remove gcc from the list since that’s part of task-devel.

["git", "cairo-devel", "dbus-daemon", "dbus-devel",
"gobject-introspection-devel", "lib64ayatana-appindicator3_1",
"lib64ayatana-appindicator3-gir0.1", "lib64cairo-gobject2",
"lib64python-devel", "lib64systemd-devel", "libnotify",
"python-dbus-devel", "python-dbus", "python-ensurepip",
"python3-pip", "task-devel", "tkinter", "xset", "zenity"],

I’ll be amazed if anyone wades through all that junk to read this sentence. :sun_with_face: