The camera in a strategy game slides in one direction forever. A menu scrolls on its own. Your character strafes without you touching anything. You unplug your controller and it keeps happening. On Linux there's a specific, unglamorous cause that gets misdiagnosed as a game bug constantly: a device that is not a gamepad is being enumerated as one, and it's reporting its axes jammed at full deflection. Motherboard RGB controllers are the classic offender. Here's how to prove it in about two minutes, and the one-line udev rule that ends it.
USB devices describe themselves with an HID report descriptor — a list of the inputs and outputs they have. A gamepad declares absolute axes (a stick has a position, not a direction of travel). So does a mouse wheel, a graphics tablet, a VR tracker, a fan controller reporting RPM, and — the one that bites people — a lot of motherboard RGB/LED controllers, which pipe their channel values through the same generic HID plumbing.
Linux doesn't judge intent. The kernel's joydev driver attaches to anything that looks
joystick-shaped and creates a /dev/input/js* node. udev then tags the device
ID_INPUT_JOYSTICK=1. From that point on, every game library that asks "what gamepads are
attached?" — SDL, Unity's libudev backend, Unreal, Steam Input — is told about your light controller.
That alone would be harmless if the device reported neutral values. It usually doesn't. An LED controller
has no reason to centre anything, so its "axes" sit wherever its firmware leaves them, which is frequently
the numeric extreme. A game reading a stick pegged at -32767 does exactly what you'd expect
if you were holding a real stick all the way over: it moves, forever.
Unity makes this especially likely, because its default input mappings feed joystick axes straight into
the same Horizontal/Vertical axes as your keyboard. You don't have to have
configured a controller. You don't have to own a controller.
List every input device the kernel knows about and look at what carries a js handler:
cat /proc/bus/input/devices
You're hunting for a stanza whose Name is obviously not a game controller but which has a
js* handler and an ABS= line. A real example from an ASRock board:
I: Bus=0003 Vendor=26ce Product=01a2 Version=0110
N: Name="ASRock LED Controller"
H: Handlers=kbd event2 js0
B: ABS=100000301ff
An RGB controller with twelve absolute axes and a joystick node. For a quick shortlist:
ls -l /dev/input/js* /dev/input/by-id/*joystick* 2>/dev/null
If the only js0 on your machine belongs to something that lights up your case, you've found
it. Confirm what udev is advertising:
udevadm info /dev/input/event2 | grep -E 'ID_INPUT|ID_VENDOR_ID|ID_MODEL'
Don't stop at "it's enumerated." Read what it's actually reporting, because that's the difference between a harmless phantom device and the thing ruining your game. The joystick API helpfully dumps the full current state the moment you open the node, so a few seconds of reading is enough:
python3 - <<'PY'
import struct, os, time
f = os.open("/dev/input/js0", os.O_RDONLY | os.O_NONBLOCK)
fmt, axes = "IhBB", {}
sz = struct.calcsize(fmt)
t0 = time.time()
while time.time() - t0 < 3:
try:
data = os.read(f, sz)
except BlockingIOError:
time.sleep(0.02); continue
if not data or len(data) < sz: continue
_, val, typ, num = struct.unpack(fmt, data)
if typ & 0x02: axes[num] = val
os.close(f)
for n, v in sorted(axes.items()):
print(f"axis {n}: {v}{' <-- OFF-CENTRE' if v else ''}")
PY
A device that is genuinely idle reports 0 across the board. The ASRock controller above
reported ten of its twelve axes pinned at -32767 — hard against the stop, on
every single one. That is a game being told you are shoving a stick into the corner and holding it there.
evtest does the same job interactively if you'd rather watch events scroll by; it needs root
and a device number.
Using libudev for joystick management and Importing game controller configs
in the game's Player.log (usually under
~/.config/unity3d/<Company>/<Game>/). That confirms the game is enumerating
joysticks at all, which is the link between "a phantom device exists" and "my camera won't stop moving."
The fix is to stop udev advertising the device as a joystick. Every consumer — SDL, Unity, Steam Input — discovers gamepads by that tag, so removing it makes the device invisible to games while leaving it completely functional for whatever it actually does.
Create /etc/udev/rules.d/99-not-a-joystick.rules, substituting your own vendor and product
IDs from step 1:
SUBSYSTEM=="input", ATTRS{idVendor}=="26ce", ATTRS{idProduct}=="01a2", \
ENV{ID_INPUT_JOYSTICK}="", ENV{ID_INPUT}=""
Reload and re-apply without rebooting:
sudo udevadm control --reload-rules
sudo udevadm trigger --subsystem-match=input
Verify the tag is gone:
udevadm info /dev/input/event2 | grep ID_INPUT # should print nothing
/dev/input/js0 node may still exist — that's fine. It's created by the
kernel's joydev driver based on the device's capabilities, and a udev rule doesn't change what
the hardware claims to be. What the rule changes is discovery: SDL and Unity enumerate tagged
devices, so an untagged one never gets opened. If you want the node gone as well you'd have to unbind or
blacklist joydev, which also kills your real controllers — not worth it. Judge success by the
missing ID_INPUT_JOYSTICK tag and by the game behaving, not by the node disappearing.
This does not affect RGB control. Lighting software talks to the device over USB HID directly (that's how OpenRGB works); the input-subsystem tag is a separate concern entirely.
If you're on Bazzite, Silverblue, Aurora or another rpm-ostree system, this needs no special handling —
/etc is writable and persists across updates, so drop the rule in
/etc/udev/rules.d/ exactly as above. No layered packages, no
rpm-ostree, no reboot.
SDL_GAMECONTROLLER_IGNORE_DEVICES=0x26ce/0x01a2 as a
launch option. Handy for a one-off, but it only works for games that discover pads through SDL — Unity's
own libudev backend ignores SDL environment variables entirely, which is exactly the case where you most
need the fix. The udev rule covers everything.Be honest with the evidence before you go rule-writing. Two checks:
The reason this one is worth knowing is that it's invisible from inside the game and survives every obvious troubleshooting step. You can reinstall, verify files, swap drivers, and unplug every peripheral you own, and a light controller bolted to your motherboard will keep quietly holding the stick down.