Tsukiko-chan

moon-gorgeous-gamepad-remapper

moon-gorgeous-gamepad-remapper is a lightweight Linux CLI tool that intercepts input events from a physical gamepad and remaps them through user-defined Lua scripts before forwarding them to a virtual controller. This can fix issues like swapped buttons or inverted axes when using controllers your games do not support well.

Many PC games today expect a Microsoft-style controller and do not work well with older devices you may still have lying around. Some do not even let you remap keys. There are already programs that fill the gap, like Input Remapper and MoltenGamepad. I wanted something CLI-only that would allow event transformations to be defined entirely as a script file in some imperative language, not some custom format.

Lua fits this role perfectly and gives you full control over event processing by letting you manipulate raw evdev events. No need to change the utility itself when a script changes: they are interpreted on the fly at load time.

Basic knowledge of Linux evdev event representation is needed: you can read more at the Linux kernel documentation.

It also has a mascot, Tsukiko-chan, whom you can see in the image above. She resembles a certain moon-related fighter for justice who performs a special move named similarly to this tool. I found it appropriate for a tool that revolves around Lua scripting (Lua meaning Moon in Portuguese) written by an avid anime consumer.

Overview

The tool sits between your physical controller and the games:

Physical gamepad ──▶ moon-gorgeous-gamepad-remapper
  ──▶ Virtual gamepad ──▶ Games

It reads raw evdev events via libevdev, passes them through a Lua transformation script, and writes the remapped events to a virtual device created via uinput.

Quick start

moon-gorgeous-gamepad-remapper \
  --source "name:My Controller" \
  --virtual "My Virtual Controller" \
  --transformation builtin:sixaxis

This grabs the physical controller named “My Controller”, creates a virtual XBox-compatible controller, and applies the built-in sixaxis profile to remap it. Controller names can be viewed using the evtest tool.

Command-line options

Built-in profiles

The following profiles ship with the tool and can be referenced as builtin:<name>:

Security model

Privilege requirements

moon-gorgeous-gamepad-remapper needs elevated privileges for three operations:

  1. Opening /dev/input device nodes — reading from a physical controller requires read access to /dev/input/event*. The source device is grabbed exclusively with libevdev_grab(), which also requires write access.

  2. Creating virtual devices via /dev/uinput — the virtual gamepad is created through the uinput kernel interface, which requires write access to /dev/uinput.

  3. Hiding source device nodes — some games will stop on the first controller they find and the virtual controller is likely numbered higher than the source one. The option --block-source renames the source by hiding it (/dev/input/.eventX) hoping that games will skip over it. Many do. The original name is restored on exit, unless the program crashes.

How privileges are managed

We try to be flexible in how we manage elevated privileges, by following this procedure when dropping privileges:

  1. if the real UID (GID) differs from the effective UID (GID), the effective one is set to the real one;
  2. then, if the real UID not root, we drop all capabilities.

This allows for several ways to run the program:

The Arch Linux MAKEPKG provided with the sources installs the program with CAP_DAC_OVERRIDE enabled.

Lua script execution

Lua scripts run after privilege drop. They cannot access device nodes or perform privileged operations. The standard Lua libraries (math, string, table, etc.) are available, plus the mggr.common module provided by the tool.

Lua profiles

See the Lua profiles guide for details on how to write custom transformation scripts.

Latency

Tests on my system report an average of 67 microseconds required to fully process a frame, measured from the time the input frame is complete to the moment the last event of the transformed frame is sent out.

Building

Dependencies

Please remember that Lua releases differing by minor number (5.3 vs 5.4) are not compatible. You should really build against Lua 5.3.

Build

cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local .
cmake --build build

Install

cmake --install build
# Optional but recommended
# setcap cap_dac_override=ep /usr/local/bin/moon-gorgeous-gamepad-remapper

Packaging

An Arch Linux AUR PKGBUILD is provided under packaging/aur/.

License

MIT