Please do not post a support request without first reading and following the advice in https://retropie.org.uk/forum/topic/3/read-this-first

How to connect a Switch Pro Controller with analog stick without xboxdrv.



  • I have came up with another method to use a Nintendo Switch Pro Controller with Retropie that does not include using xboxdrv and does have working and calibrated analog sticks. This can be done before connecting the controller so that it auto sets the calibration when connecting the controller.

    Retropie 4.3 uses old old version of the joystick package. Manually install a newer version that provides evdev-joystick, this will become obsolete when the base OS packages get updated

    wget http://mirrordirector.raspbian.org/raspbian/pool/main/j/joystick/joystick_1.6.0-2_armhf.deb
    sudo dpkg -i joystick_1.6.0-2_armhf.deb

    A axis remapping fix for the joydev subsystem which seems to be needed for at least one part of the system that still uses the old joydev system. I could not configure the controller completely on a fresh install without this.

    sudo mkdir -p /var/lib/joystick
    sudo wget https://pastebin.com/raw/e7BdgdrH -O /var/lib/joystick/joystick.state

    Get the following rules and service files to calibrate the Switch Pro Controllers two analog sticks at connection time for the evdev system.

    sudo wget https://pastebin.com/raw/8QhypWfg -O /etc/udev/rules.d/99-nintendo-switch-pro-controller.rules
    sudo wget https://pastebin.com/raw/0yWX2Xiq -O /etc/systemd/system/nintendo-switch-pro-controller.service

    Now just connect the controller via Bluetooth. I have tested it and it has great calibration and allows me to run forward in N64 (tested Mario 64) and PS1 games (tested Spyro)



  • Fantastic job on this. I had a similar problem with a Wii Classic Controller Pro (the thing you jam in the bottom of a Wii Remote) and calibration. I had no idea what to do about it until I saw your Switch Pro Controller solution. I had calibrated with jscal, but not the newer evdev-joystick, so my characters were doing a lot of walking--funny thing, the games I was testing were also Super Mario 64 and Spyro the Dragon.

    Adapting your work to the Wii Remote/Classic Controller, my setup looks like this:

    /etc/udev/rules.d/99-nintendo-wiimote.rules

    KERNEL=="event*", ATTRS{name}=="Nintendo Wiimote", SYMLINK+="nintendo-wiimote", TAG+="systemd", ENV{SYSTEMD_WANTS}="nintendo-wiimote.service"
    KERNEL=="event*", ATTRS{name}=="Nintendo Wiimote", ACTION=="remove", RUN+="/bin/systemctl stop nintendo-wiimote"
    KERNEL=="uinput", MODE="0666"
    

    (The uinput mode 0666 comes from the Wiimote tutorial, not your work here. I suspect it of being a hacky solution but I don't know enough to do any better.)

    /etc/systemd/system/nintendo-wiimote.service

    [Unit]
    Description=Nintendo Wii Remote (Classic Controller) Axis Calibration 
    After=bluetooth.target
    
    [Service]
    ExecStartPre=/usr/bin/evdev-joystick --evdev /dev/nintendo-wiimote --minimum 6 --maximum 59 --axis 0
    ExecStartPre=/usr/bin/evdev-joystick --evdev /dev/nintendo-wiimote --minimum 6 --maximum 60 --axis 1
    ExecStartPre=/usr/bin/evdev-joystick --evdev /dev/nintendo-wiimote --minimum 2 --maximum 28 --axis 3
    ExecStart=/usr/bin/evdev-joystick --evdev /dev/nintendo-wiimote --minimum 1 --maximum 28 --axis 4 
    KillMode=process
    
    [Install]
    Alias=wiimote.service
    

    By the way, aren't these numbers hilariously pathetic? The right analog stick ranges from 1 to 28! Do not attempt precision gameplay with a Wii Classic Controller.

    Additional note: the Hori-produced "Battle Pad for Wii U" is internally just a Wii Classic Controller and will happily work on a Wii (or Raspberry Pi, if you're so inclined). At the time of release, reviewers were critical of its overly sensitive joysticks, but I think they actually had it backward. The Classic Controller is nominally 0-63 on the left stick and 0-31 on the right, but as you can see from my numbers above, it doesn't even manage that. Presumably, software was built with these garbage-range sticks in mind, relying on the assumption that users would never hit the actual analog peak values.

    The Hori pad, on the other hand, is a much better-made device. Fiddling around in evtest, I checked the range on its analog sticks, and I can reliably get the full 0-63 range on both axes of the left stick and the full 0-31 of the right. Basically, you shouldn't need to calibrate at all if you're using one of these Hori pads. The official Nintendo-branded ones are another story, though. Unfortunately, wminput can't or doesn't differentiate between a Hori Battle Pad and a Classic Controller/Pro (I believe they do send a different extension value, but wminput doesn't do anything with it, at least in the current tutorial, anyway), so if you plan on using the Battle Pad and a Classic Controller you'll have to do some more fiddling with calibration.



  • @vague-rant is nice to know my work also helped out another controller.



  • Hi shadowofdarkness,

    I've tested your method, and it worked almost perfect to me. I was able to remap the left stick with both axis properly, but had a problem with the right stick, where up, down, and left directios were correctly registered, but, when I try to set right direction, It doesn't recognize it.



  • @arziel Strange I have not had that issue on my system, I have also tested it by connecting my Pro Controller to another family members Retropie system and it also worked great.

    My /opt/retropie/configs/all/retroarch-joypads/Pro\ Controller.cfg file has the following for the right sticks values with r_x_plus_axis being the one you are having issues with.

    input_r_x_minus_axis = "-2"
    input_r_x_plus_axis = "+2"
    input_r_y_minus_axis = "-3"
    input_r_y_plus_axis = "+3"

    Edit I guess one thing to try is to make sure that the joydev system actually applied the joysticks state when the controller was connected.

    try running the following but make sure your controller is actually js0 and not a different number, if it is adjust the command. Then try configuring the controller again.

    jscal-restore /dev/input/js0



  • Hi again, I tried the jscal command and didn't work. Also checked the cfg file. In the cfg file the value input for r_x_plus is missing.

    The pro controller is the only controller I have.



  • @arziel Maybe just try manually fixing the cfg file in a text editor, and then just see how it actually works in game.

    As far as I can tell the joydev system is only used when configuring the controller, other then that the emulators use the evdev system which is separate.

    Fun fact about all the changes I made that are applied to the controller. The joystick.state is just a axis mapping fix to get past the configuration, I never actually fixed any calibration in it.

    The other service file is just for the other subsystem that calibrates them but I never had any axis mapping problems with it.



  • @shadowofdarkness well I have no idea where to continue. I've edited the cfg file adding the r_x_plus_axis line with no success, so I'll stay and live only with the left stick. At least, one is working now.



  • In controller.service:

    ExecStartPre=/usr/bin/evdev-joystick --evdev /dev/switch-pro-controller --minimum 4630 --maximum 59562 --axis 0
    ExecStartPre=/usr/bin/evdev-joystick --evdev /dev/switch-pro-controller --minimum 8492 --maximum 62531 --axis 1
    ExecStartPre=/usr/bin/evdev-joystick --evdev /dev/switch-pro-controller --minimum 8649 --maximum 62378 --axis 3
    ExecStart=/usr/bin/evdev-joystick --evdev /dev/switch-pro-controller --minimum 4000 --maximum 60305 --axis 4
    KillMode=process

    the fourth line says "ExecStart=/usr/bin/evdev-joystick", shouldn't be "ExecStartPre=/usr/bin/evdev-joystick"?



  • @arziel have you tried rebooting the system? Also that service is fine the fourth one is not supposed to have a pre



  • @shadowofdarkness I followed your instructions on this but my Pro Controller would not pair. The lights on the controller just kept flashing sequentially. I have two other bluetooth controllers paired (Mad Catz CTRLR and PS3, though only the former is working). But they were not connected at the time. Any help would be greatly appreciated



  • Hi

    Is this still the best method and is the first step still required with the latest version of Retropie?

    Thanks



  • Just updating this.

    The steps in this post still work.

    I just installed Retropie 4.6-rpi4 and the first step is no longer needed.

    wget http://mirrordirector.raspbian.org/raspbian/pool/main/j/joystick/joystick_1.6.0-2_armhf.deb
    sudo dpkg -i joystick_1.6.0-2_armhf.deb
    

    If you are installing a different version and want to check whether you need to run the first step or not you can check the version of joystick in your image by running the following command and scrolling through the list until you find the joystick library.

    sudo dpkg-query -l | less
    
    

    If your version of joystick is older than 1.6.0-2 and you need to update you will want to install 1.6.1-1 instead of 1.6.0-2. (1.6.0-2 is no longer available from that link)
    so use these commands instead of the commands above

    wget http://mirrordirector.raspbian.org/raspbian/pool/main/j/joystick/joystick_1.6.1-1_armhf.deb
    sudo dpkg -i joystick_1.6.1-1_armhf.deb
    


  • I have the same problem as reported by @Arziel . My right analog stick still refuses to register stick presses to the right in EmulationStation, although your method has fixed left analog up, left analog right, and right analog up, which gives me hope!

    How did you determine the minimum & maximums, e.g. --minimum 4630 --maximum 59562 --axis 0 values? Was this arbitrary?

    Perhaps individuals need to tweak values in the /etc/systemd/system/nintendo-switch-pro-controller.service file based on what we get when we run jstest? For example, when I test my controller using jstest /dev/input/js0 "Axis 4", right analog stick X-axis, reports a range of values between --30673 (full left) to 23965 (full right), and "Axis 5", right analog stick Y-axis, reports a range from -25743 (full up) to 31487 (full down).

    Unfortunately I'm just guessing; I don't know how any of the subsystems we're touching here really work.

    Side note: how tf do Chrome and Steam Link do it? On my Debian-based laptop I can connect the Switch Pro controller via the cable, and the blue home button right lights up and the Knight Rider mode stops, and https://html5gamepad.com/ detects all the buttons and analog sticks perfectly. I do have to add the udev rules here before connecting the controller though ... and as limited as I am in my knowledge I can see 'hidraw' in one and 'event*' in another.



  • @insx said in How to connect a Switch Pro Controller with analog stick without xboxdrv.:

    Is this still the best method ...

    Not anymore, in my opinion!!

    There is a new kernel driver in the pipeline for acceptance called hid-nintendo written by Daniel Ogorchock that worked beautifully for me. The current state of the module is in Daniel's fork of Linux, but until it's merged into the kernel tree use the dkms version provided by nicman23:

    Install it from source like so:

    git clone https://github.com/nicman23/dkms-hid-nintendo
    cd dkms-hid-nintendo
    
    sudo dkms add .
    sudo dkms build nintendo -v 1.0
    sudo dkms install nintendo -v 1.0
    

    Then pair your controller in the normal way, start EmulationStation and map buttons.

    EmulationStation didn't map everything perfectly for me and I ended up having to tweak my /home/pi/.emulationstation/es_input.cfg file to include this config stanza:

      <inputConfig type="joystick" deviceName="Nintendo Switch Pro Controller" deviceGUID="050000007e0500000920000001800000">
        <input name="up" type="hat" id="0" value="1"/>
        <input name="down" type="hat" id="0" value="4"/>
        <input name="left" type="hat" id="0" value="8"/>
        <input name="right" type="hat" id="0" value="2"/>
        <input name="b" type="button" id="0" value="1"/>
        <input name="a" type="button" id="1" value="1"/>
        <input name="x" type="button" id="2" value="1"/>
        <input name="y" type="button" id="3" value="1"/>
        <input name="leftshoulder" type="button" id="5" value="1"/>
        <input name="rightshoulder" type="button" id="6" value="1"/>
        <input name="lefttrigger" type="button" id="7" value="1"/>
        <input name="righttrigger" type="button" id="8" value="1"/>
        <input name="select" type="button" id="9" value="1"/>
        <input name="start" type="button" id="10" value="1"/>
        <input name="hotkeyenable" type="button" id="11" value="1" />
        <input name="leftthumb" type="button" id="12" value="1"/>
        <input name="rightthumb" type="button" id="13" value="1"/>
        <input name="leftanalogup" type="axis" id="1" value="-1"/>
        <input name="leftanalogdown" type="axis" id="1" value="1"/>
        <input name="leftanalogleft" type="axis" id="0" value="-1"/>
        <input name="leftanalogright" type="axis" id="0" value="1"/>
        <input name="rightanalogup" type="axis" id="3" value="-1"/>
        <input name="rightanalogdown" type="axis" id="3" value="1"/>
        <input name="rightanalogright" type="axis" id="2" value="1"/>
        <input name="rightanalogleft" type="axis" id="2" value="-1"/>
        <input name="pagedown" type="button" id="6" value="1"/>
        <input name="pageup" type="button" id="5" value="1"/>
      </inputConfig>
    

    And then modify /opt/retropie/configs/all/retroarch-joypads/"Nintendo Switch Pro Controller.cfg" like so:

    input_device = "Nintendo Switch Pro Controller"
    input_driver = "udev"
    input_a_btn = "1"
    input_b_btn = "0"
    input_y_btn = "3"
    input_x_btn = "2"
    input_up_btn = "h0up"
    input_down_btn = "h0down"
    input_left_btn = "h0left"
    input_right_btn = "h0right"
    input_l_btn = "5"
    input_r_btn = "6"
    input_l2_btn = "7"
    input_r2_btn = "8"
    input_select_btn = "9"
    input_start_btn = "10"
    input_enable_hotkey_btn = "11"
    input_l3_btn = "12"
    input_r3_btn = "13"
    input_l_y_plus_axis = "+1"
    input_l_y_minus_axis = "-1"
    input_l_x_minus_axis = "-0"
    input_l_x_plus_axis = "+0"
    input_r_y_plus_axis = "+3"
    input_r_y_minus_axis = "-3"
    input_r_x_minus_axis = "-2"
    input_r_x_plus_axis = "+2"
    input_save_state_btn = "6"
    input_menu_toggle_btn = "2"
    input_exit_emulator_btn = "10"
    input_load_state_btn = "5"
    input_reset_btn = "0"
    input_state_slot_increase_btn = "h0right"
    input_state_slot_decrease_btn = "h0left"
    

    hid-nintendo is still going through the process of acceptance into the Linux kernel, so it will be quite some time before this module is included in a Raspbian Raspberry Pi OS release.

    There is a known-issue where hid-nintendo clashes with Steam. Read more on the Arch Linux Wiki (including workarounds).



  • @wmarler

    THANK YOU SO MUCH!

    This is what made the controller finally work for me. I've tried jscal , I've tried evdev-joystick, and before I saw your post, I tried everything above. Nothing worked. This made the controller as it's supposed to on every system. I didn't even need to reconfigure like you have above. hid-nintendo just worked! I've been at this for days and I'm so happy lol.



Contributions to the project are always appreciated, so if you would like to support us with a donation you can do so here.

Hosting provided by Mythic-Beasts. See the Hosting Information page for more information.