PowerA Nintendo Switch Wired controller buttons mapped incorrectly

My PowerA NSW Nano Wired controller is the main one I’ll be troubleshooting, though I have another PowerA NSW Wired controller (not nano) exhibiting the same issues. My 8bitdo ultimate NSW controller is working fine.

When I test the mapping of my controller (either using the built-in system tools or Hardware Tester , it shows that my mapping is wrong for the PowerA controller. There are several issues, but here is an excerpt of the mapping:

A: B17
B: B1
X: B3
Y: B0
Left bumper: B2

This is all without Steam running (though rpm Steam is installed).

No worries, Steam has a controller “Setup Device Inputs” feature for just such an occasion. I use that to set up the device inputs, and then the controller works perfectly…in Steam. In any Steam game, even one where I explicitly force Steam Input, Steam is still using the original (incorrect) mapping.

So I figure there are two issues, and if either of them got resolved I’d be good to go. 1. The Linux driver incorrectly maps the controller buttons for this hardware. 2. Steam incorrectly doesn’t apply the setup device inputs in game. Since this is the Fedora forum I think solving issue #1 is my best bet, but if someone happens to know a quick and easy solution for issue #2 that would be okay too.

Is there a way for me to get a correct driver? I’m on Fedora 42 KDE. I’ve replicated this issue on two different Fedora 42 KDE computers. I’ve tested the controller on Windows and it registers correctly.

Running: udevadm info --query=all --attribute-walk --name=/dev/input/js0 tells me the device is named /devices/pci0000:00/0000:00:01.2/0000:01:00.0/usb1/1-3/1-3:1.0/0003:20D6:A718.0009/input/input25/js0 in the off chance that’s helpful.

You don’t need a different driver, you need to remap the controller.

You can use input-remapper which is available in the Fedora repos or another remapper.

Joysticks / gamepads are handled by SDL2 / SDL3 (f42+) and f42 still installs SDL3-3.2.16. SDL3-3.2.18 and SDL3-3.2.20 have some important fixes for Nintendo Switch controllers. I guess this may already be resolved by upgrading SDL3. If you’ve installed Steam as rpm then this is important.

try to upgrade SDL3 and restart the appl (Steam etc)

sudo dnf upgrage https://download.copr.fedorainfracloud.org/results/anotheruser/SDL3/fedora-42-x86_64/09642114-SDL3/SDL3-3.2.24-1.fc42.x86_64.rpm \
https://download.copr.fedorainfracloud.org/results/anotheruser/SDL3/fedora-42-i386/09642114-SDL3/SDL3-3.2.24-1.fc42.i686.rpm \
https://download.copr.fedorainfracloud.org/results/anotheruser/SDL3/fedora-42-x86_64/09642114-SDL3/SDL3-devel-3.2.24-1.fc42.x86_64.rpm

If that fixes the wrong mappings, then please open a bug report on bugzilla.redhat.com for Fedora / SDL3 and request an update of SDL3 for F42.

to revert run either
dnf history undo last or dnf distro-sync SDL3\*

1 Like

I’ve now upgraded SDL3, but I don’t notice any mapping changes even after restarting the computer. Thanks for the idea though!

I’ve started using input-remapper to remap inputs. I have some concerns about how it will interact with Steam Input, but I haven’t tested much yet. (Other family members use other controllers reliant on Steam Input, most prominently the Steam Controller.) I will finish an input-remapper mapping and test it out though, I’ll also test some other SDL3-related potential fixes I found. I’ll report back with what does or doesn’t work once I’ve had time to test. Thank you!

1 Like

This is the only place in the SDL source identifying this controller as a SwitchInputOnlyController

$ grep 0xa718  src/joystick/controller_list.h  
	{ MAKE_CONTROLLER_ID( 0x20d6, 0xa718 ), k_eControllerType_SwitchInputOnlyController, NULL },  // PowerA Nintendo Switch Nano Wired Controller

The SDL source has a testcontroller.c you could compile and run.

You can also check whether there is an entry in the GameControlerDB. Probably not, because it’s a standard Switch mapping?

Some controllers might allow switching the input mode (dinput or xinput) by holding a button combo while USB-connected; I had a couple that changed how triggers and analog sticks mapped when doing that.

I’m just about ready to call it quits, though it would be a shame since this is my daughter’s favorite controller. Maybe Nintendo Switch controllers weren’t meant to be hacked into other devices after all :sweat_smile: Honestly I’d think there’s something wrong with my Linux or with my controller, if it weren’t that I can replicate on two different Fedora 42 installs and with two different PowerA Nintendo Switch controllers. Or maybe I just don’t know what I’m doing :face_with_peeking_eye:

I tried input-remapper, but it didn’t seem to play nice with Steam Input, creating multiple virtual controllers that Steam wasn’t totally sure what to do with. I tried turning off Steam Input just for testing, and it still wasn’t working on the games I was testing. Maybe I just wasn’t mapping things right? I also tried editing the SDL inputs in config.vdf in the Steam installation’s config files, but that didn’t seem to do anything.

I’ve compiled that and I can get that reading more or less the right buttons by creating a new mapping, and I can “set mapping as environment variable” with sudo so that it should work universally, but it still doesn’t work right in any games I test, and Hardware Tester still shows bizarre results like A mapping to b17. Like Steam, the remapper can map things right, but it can’t seem to get games to actually use it.

I don’t think there’s one. The closest is
03000000d620000013a7000011010000 vs my
03000000d620000018a7000011010000, the one in the database being described PowerA Nintendo Switch Controller, and that one shows reasonable mappings like A button being b1. Mine seems somehow not standard by mapping the A button to b17.

I’m pretty certain this controller doesn’t have that option and was designed to only be used with the Nintendo Switch. Thanks for the idea though!

check the SDL include file SDL_hints.h

/**
 * A variable that lets you manually hint extra gamecontroller db entries.
 *
 * The variable should be newline delimited rows of gamecontroller config
 * data, see SDL_gamecontroller.h
 *
 * This hint must be set before calling SDL_Init(SDL_INIT_GAMECONTROLLER) You
 * can update mappings after the system is initialized with
 * SDL_GameControllerMappingForGUID() and SDL_GameControllerAddMapping()
 */
#define SDL_HINT_GAMECONTROLLERCONFIG "SDL_GAMECONTROLLERCONFIG"

/**
 * A variable that lets you provide a file with extra gamecontroller db
 * entries.
 *
 * The file should contain lines of gamecontroller config data, see
 * SDL_gamecontroller.h
 *
 * This hint must be set before calling SDL_Init(SDL_INIT_GAMECONTROLLER) You
 * can update mappings after the system is initialized with
 * SDL_GameControllerMappingForGUID() and SDL_GameControllerAddMapping()
 */
#define SDL_HINT_GAMECONTROLLERCONFIG_FILE "SDL_GAMECONTROLLERCONFIG_FILE"

this means you have two options:

  1. export SDL_GAMECONTROLLERCONFIG=“<the custom mapping>”
  2. create a file with the mapping(s) you want to use e.g. ~/.config/gamecontrollerdb.txt
    and export SDL_GAMECONTROLLERCONFIG_FILE=“/path/to/gamecontrollerdb.txt”

test this with the testcontroller program. It should pick up your custom config automatically, or test with a native linux sdl game like supertuxcard.

This should work for all linux sdl games/programs.

You’ll need to set the same env variable in windows compatibility layer like wine. If you use the gamecontrollerdbfile, then make this file also available in wine.

I think you’ll also need to set the env variable for flatpak apps/games with flatpak override

hardware tester: a browser will probably show only the real mapping.

1 Like

This actually helps a lot. I realized I was relying too much on that browser tool. I kind of started from scratch looking at this again and realized I’d misrepresented some things and made some mistakes. At this point I’ve turned off all remapping in Steam and all others.

I have two PowerA controllers: the nano and one that’s not nano. The nano is a718 (not listed in a lot of the databases) and my other is the a713 (seems to be listed in most of the databases). The not nano one works with no tinkering, contrary to what I’d thought based on the browser tool. So I really just need to set up the nano one to work identically. At this point the nano has a bad mapping in Steam, but the regular (a713) works fine. I opened up /lib/udev/rules.d/60-steam-input.rules (based on a post at Steam Controller known issues and platform-specific notes :: Steam Controller Technical Support/Troubleshooting) and found “# PowerA Wired Controller for Nintendo Switch.” They had an entry KERNEL==“hidraw*”, ATTRS{idVendor}==“20d6”, ATTRS{idProduct}==“a713”, MODE=“0660”, TAG+=“uaccess”, so I copied that line replacing the a713 with a718. With that, the nano starts working in Steam even without me explicitly remapping anything. It even works in Steam games about 50% to 75% of the time—it randomly seems to cut the proper mapping in and out while I’m playing. It’s so weird that the whole control scheme switches inconsistently, not sure what’s going on there.

I also realized I was wrong when I said I’d compiled testcontroller.c, somehow I’d confused that with the old generalarcade one at SDL2 Gamepad Tool by General Arcade . I cloned the SDL repository and am following the README-cmake.md and README-linux.md, but I’m still struggling with getting the cmake build tool to work properly. When I follow the instructions as-is, initially it couldn’t find a build tool, and now after tinkering it says my /usr/bin/gcc is unable to build a simple test program. I’ll keep tinkering with this when I can find the time.

1 Like

Have you installed gcc and c development tools?

Yes, following the README-linux.md, I did a

sudo dnf install gcc git-core make cmake
alsa-lib-devel fribidi-devel pulseaudio-libs-devel pipewire-devel
libX11-devel libXext-devel libXrandr-devel libXcursor-devel libXfixes-devel
libXi-devel libXScrnSaver-devel dbus-devel ibus-devel
systemd-devel mesa-libGL-devel libxkbcommon-devel mesa-libGLES-devel
mesa-libEGL-devel vulkan-devel wayland-devel wayland-protocols-devel
libdrm-devel mesa-libgbm-devel libusb1-devel libdecor-devel
pipewire-jack-audio-connection-kit-devel liburing-devel

You need gcc and gcc-c++ and a bunch of other build dependencies.
See BuildRequires: in the SDL3 spec file found on src.fedoraproject.org

Toolbx is a nice and simple tool to setup a development environment, where you can install all required *-devel rpms w/o modifying the host system. $HOME is shared

toolbox enter
   mkdir ~/src && cd ~/src
   git clone https://src.fedoraproject.org/rpms/SDL3.git  SDL3-fedora -b f42
#  this will checkout  version 3.2.20   use -b release-3.2.x  for latest  3.2 branch or any other release tag 
   git clone https://github.com/libsdl-org/SDL.git -b release-3.2.20  --single-branch --shallow-since=2025-05-01  

  sudo dnf builddep --setopt=install_weak_deps=false SDL3-fedora/SDL3.spec  
  mkdir SDL3-builddir && cd SDL3-builddir
  cmake ../SDL -DSDL_TESTS=ON
  make -j 
exit   

test programs are in ~/src/SDL3-builddir/tests

1 Like

Thanks! That worked, I’m not sure I would have been able to figure out the build process without your post.

So now I actually have that testcontroller.c built and running. It immediately has the correct controls without any configuration. I’ve gone with the export SDL_GAMECONTROLLERCONFIG_FILE="/home/alexioxela/.conf
ig/gamecontrollerdb.txt" route. I exclusively game through Steam, so I couldn’t immediately test this with a native Linux game launched without Steam. I started researching applying this SDL file for Steam and/or Wine/Proton it seemed like there may not be an easy fix that applied for everything, especially with SteamInput running. I ended up trying a different route that seems like it has success so far. I’ll post about that in a separate post momentarily. Thanks to everyone who helped me in this thread! I think I would have given up on this problem without you all helping me think through it.

I’ll mark the next post as a solution in a couple days unless someone has an easy, less heavy-handed solution that works as well. I’m definitely satisfied with this solution though.

Though additional research, a ton of testing/tinkering, and a bit of generative AI to help with implementation, I have a solution that seems to be working for now, though it’s a bit heavy-handed. (On the point of AI implementation, I read through the code to make sure it was reasonable, but I can’t say I 100% understand every detail, use at your own risk.) Here’s my whole process in case it’s helpful for others that have controllers Steam doesn’t support out-of-the-box.

First, my config didn’t work in Steam. I fixed this by editing /lib/udev/rules.d/60-steam-input.rules, copying the line of a similar config and modifying it by adding my idVendor and idProduct. In my case I have idVendor “20d6” and idProduct “a718”, so I added the line KERNEL==“hidraw*”, ATTRS{idVendor}==“20d6”, ATTRS{idProduct}==“a718”, MODE=“0660”, TAG+=“uaccess”. NOTE: It probably would have been more appropriate to add this new line in a new file at /etc/udev/rules.d/; I would recommend doing that if you’re following this procedure.
Now my config does work in Steam, but it only works in Steam games half the time. If I run sudo dmesg | grep -i 20d6, I get the output:

[ 1010.510402] usb 1-3: New USB device found, idVendor=20d6, idProduct=a718, bcdDevice= 1.14
[ 1010.527272] input: PowerA NSW Nano Wired controller as /devices/pci0000:00/0000:00:01.2/0000:01:00.0/usb1/1-3/1-3:1.0/0003:20D6:A718.0008/input/input24
[ 1010.527458] hid-generic 0003:20D6:A718.0008: input,hidraw7: USB HID v1.11 Gamepad [PowerA NSW Nano Wired controller] on usb-0000:01:00.0-3/input0

That line “hid-generic 0003:20D6:A718.0008: input,hidraw7”; I think the input and the hidraw7 are fighting each other for control. (this is also one way to get the idVendor and idProduct, that “20D6:A718” output.) I don’t know why Steam can’t disable the “input” in a reasonable way like it seems to for controllers in its list, but we can disable it ourselves. In my case, my controller is a PowerA NSW Nano Wired controller. I have files /dev/input/by-id/usb-PowerA_NSW_Nano_Wired_controller-event-joystick and /dev/input/by-id/usb-PowerA_NSW_Nano_Wired_controller-joystick that symlink to /dev/input/event[arbitrary number] and /dev/input/js0. If I sudo rm [files] all 4 of those files, then everything works perfectly (seemingly until I reboot). Important note: This is a heavy-handed approach that seems to make the controller not work at all unless you’re using Steam. This is fine for my use case. Now let’s just make it automatic. This is where AI wrote most of the code.

sudo nano /usr/local/bin/steam-powera-cleanup.sh

Populate the file as follows:

#!/usr/bin/env bash
# steam-powera-cleanup.sh — disable kernel input devices for PowerA NSW Nano Wired controller

set -euo pipefail

VENDOR="20d6"
PRODUCT="a718"

# Give the kernel a short moment to populate input nodes fully
sleep 1

found=0

# Remove any by-id symlinks referencing the controller
for idfile in /dev/input/by-id/*PowerA_NSW_Nano_Wired_controller*; do
  [ -e "$idfile" ] && rm -f "$idfile" && found=1
done

# Remove /dev/input/event* or js* that match this vendor/product
for node in /dev/input/event* /dev/input/js*; do
  if udevadm info -q property -n "$node" 2>/dev/null | grep -qi "${VENDOR}/${PRODUCT}"; then
    rm -f "$node"
    found=1
  fi
done

if [[ $found -eq 1 ]]; then
  logger -t "steam-powera-cleanup" "Removed PowerA input nodes (vid:pid ${VENDOR}:${PRODUCT})"
else
  logger -t "steam-powera-cleanup" "No PowerA controller nodes found"
fi

exit 0

Make it executable

sudo chmod +x /usr/local/bin/steam-powera-cleanup.sh

Create a service to handle executing the script on controller plugged in.

sudo nano /etc/systemd/system/steam-powera-cleanup.service

Populate with

[Unit]
Description=Remove kernel input devices for PowerA NSW Nano Wired controller
After=local-fs.target
ConditionPathExistsGlob=/dev/input/by-id/*PowerA_NSW_Nano_Wired_controller*

[Service]
Type=oneshot
ExecStart=/usr/local/bin/steam-powera-cleanup.sh

Now create the udev rule to call the service:

sudo nano /etc/udev/rules.d/99-steam-powera.rules

Populate it with

# When PowerA NSW Nano Wired controller is connected, run cleanup service

ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="20d6", ATTR{idProduct}=="a718", \
  TAG+="systemd", ENV{SYSTEMD_WANTS}="steam-powera-cleanup.service"

Create a service to handle executing the script on boot

sudo nano /etc/systemd/system/steam-powera-cleanup-boot.service

Populate with

[Unit]
Description=Run PowerA controller cleanup on boot if needed
After=local-fs.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/steam-powera-cleanup.sh

[Install]
WantedBy=multi-user.target

Then enable it all with sudo udevadm control --reload-rules, sudo systemctl daemon-reload, sudo systemctl start steam-powera-cleanup.service, and sudo systemctl enable steam-powera-cleanup-boot.service.
If things aren’t working at that point, try unplugging/replugging the controller and/or restarting the PC. You could check the /dev/input/ and /dev/input/by-id/ to see if things are being deleted as expected. Now the hidraw that SteamInput is using is still available, but the Inputs that are fighting for control are disabled. If you wish to use the controller without Steam again, you’d need to remove the udev rule and remove the services. In my case /dev/input/js0 doesn’t seem to have been deleted (probably due to imperfect code from the AI), but everything is working perfectly for me playing the Steam game I’ve been testing on. I’ll test on additional Steam games in the coming days to ensure all is good.

Thanks again to everyone for the help! I’ve learned a ton about how Linux handles controllers and such.