Skip to content
 
 

Repository files navigation

Sys-con

Connect any USB controller to your Nintendo Switch !

Support any controller: PC controllers, Wheels, Dualshock 3, Dualshock 4, Dualsense (PS5), XBOX, XBOX360, XBOXONE, Wii, SInput, ...

Description

Sys-con is a Nintendo Switch module that adds support for all HID and XID joysticks and gamepads to the Nintendo Switch. Only USB connection is supported (For Bluetooth connection prefer to use ndeadly's MissionControl)

Installation

Download the latest zip from the releases page. Extract it to your SD card root folder and boot/reboot your switch.

Configuration

sys-con comes with a configuration folder located in /config/sys-con/. It contains configuration for controllers (Button mappings, sticks configuration, triggers configuration, deadzones...).

The configuration is loaded in the following way:

  • The [global] section is only loaded once, when the switch boots, so if you want to apply a setting, you have to reboot the switch.
  • Other sections are for controller configuration, they are loaded each time you plug a controller, so if you want to apply a setting you will have to unplug and then replug your controller to apply it.

When a new controller is plugged, the configuration is loaded in below order

  1. First it load the [default] section
  2. Then it will load the [VID-PID] section
  3. If [VID-PID] contains a [profile], it will load the [profile] then load [VID-PID].

In other words, the loading order is: [Default] [Profile] [VID-PID]. If you want to override a setting for only 1 controller, it's adviced to change the configuration in [VID-PID] in order to not impact others controllers

Mode

The mode= key of the [global] section selects how controllers are published to the console:

  • hiddbg: virtual controllers are attached through hiddbg (HDLS).
  • mitm (set in the shipped config.ini): sys-con intercepts the hid service and feeds each game a fake HID shared memory. Required for rumble.
  • disabled: sys-con starts, writes its log, then exits without creating any controller.

A config.ini without a mode= key, with an unknown value, or missing altogether falls back to hiddbg.

Logs

In case of issue, you can look at the logs in /config/sys-con/log.txt (On your SDCard). The logs are automatically created with a log level equal to Info. For more verbose logs, edit /config/sys-con/config.ini and set:

[global]
log_level=0

Reboot the Nintendo Switch. Note: Verbose logging introduces significant input lag. Use it only for debugging.

Features

  • HID joystick/gamepad/wheels supported (PC Controller compatible)
  • PS and XBOXs controllers supported
  • Custom key mapping using VID/PID and profile.
  • Automatically add new controllers (Try to determine the best driver)
  • Configurable deadzone
  • Configurable polling timeout (polling_timeout_ms)
  • Configurable controller color (color_body, color_buttons, color_leftgrip, color_rightgrip) using #RRGGBB or #RRGGBBAA
  • Network controller over UDP, for scripted input during testing (off by default)
  • Rumble (mode=mitm only; hiddbg gives no vibration back)
  • Motion controls (for drivers that report it: Switch Pro, SInput, Steam Controller 2026, network controller)
  • HID keyboard / mouse support

Supported controller

  • All PC Controllers
  • All Playstation Controllers
  • All Xbox Controllers
  • Steam Controllers
  • SInput gamepads (Hand Held Legend ProGCC / GC Ultimate, Void Gaming, ...)
  • Wheels

A complete list of tested controller is available here

Configure a controller

When a new controller is connected, sys-con tries to determine the best profile for this new controller. In most cases the dpad and joystick will work fine, the buttons may not be mapped correctly by default (and in rare cases the right stick may be reversed or not working). If this is the case, you will need to map the buttons yourself using the procedure below:

Method 1: Configure Directly on the Switch (Recommended)

  1. Connect your controller to the Nintendo Switch.

  2. Open the input test menu: On the Switch, go to:
    Settings → Controllers & Sensors → Test Input Devices

  3. Test each button.** Press every button on the controller and write down or memorize how the Switch reports each input.
    Your goal here is to understand the correct mapping for your specific controller.

  4. Edit your sys-con configuration.** On the SD card, open:

    /config/sys-con/config.ini
    

    Locate the section corresponding to your controller’s VID-PID, which looks like:

    [vid-pid]
    

    This section is usually added automatically when sys-con detects an unknown controller.
    Most of the time, it will be at the bottom of the file.

Tips for Faster Iteration

The config.ini file is reloaded every time you plug in a controller.
To speed up testing:

  1. Install vgedit on your Switch:
    https://github.com/vgmoose/vgedit/releases
  2. Unplug the controller
  3. Edit config.ini directly from the Switch using vgedit
  4. Re-plug the controller to reload the config
  5. Test your changes immediately

This allows very quick trial-and-error cycles.

Typical configuration

[0810-0001]
B=1
A=2
Y=3
X=4
L=5
R=6
ZL=7
ZR=8
minus=9
plus=10
home=11
capture=12
rstick_left=-Rz
rstick_right=+Rz
rstick_up=+Z
rstick_down=-Z

Where ButtonName (A, B, Y, X ...) need to be assign to a ButtonID (1,2,3,4,5 ...) Now, according to what you found in step 2, you need to match ButtonName with ButtonID. For example, if you found that 'B' is reversed with 'A', just swap the ButtonID:

B=2
A=1

Method 2 (From a windows PC)

Note: Button mapping can differ between windows and the switch

  1. Connect your controller to your PC
  2. Go to 'Control Panel' > 'Device Manager' and find your USB device under 'Human Interface Devices'.
  3. Double click on the device or right click and select Properties.
  4. Go to the 'Details' tab and select 'Hardware IDs' to view its PID and VID. The PID/VID should look like "HID\VID_0810&PID_0001&...", which becomes: [0810-0001].
  5. Open "joy.cpl" (either from Win+R or directly from the Start menu).
  6. Select your controller and click on "Properties"
  7. Here you should see a panel with ButtonID (1, 2, 3 ...), press the button and make a note of them (which button is assigned to which ID).
  8. Now edit /config/sys-con/config.ini on your switch sdcard and edit your controller's vid-pid section:
[0810-0001]
B=3
A=2
Y=4
X=1
L=7
R=8
ZL=5
ZR=6
minus=9
plus=10
home=11
capture=12
rstick_left=-Z
rstick_right=+Z
rstick_up=+Rz
rstick_down=-Rz

Where ButtonID (1,2,3,4, ...) is the key ID noted in step 7. Note: Depending to the controller, this windows procedure might not works. If the mapping is incorrect, switch to Method 1

Button mapping

The following is the complete list of mappable buttons for the Switch controller:

lstick_left=
lstick_right=
lstick_up=
lstick_down=
rstick_left=
rstick_right=
rstick_up=
rstick_down=
B=
A=
Y=
X=
L=
R=
ZL=
ZR=
minus=
plus=
lstick_click=
rstick_click=
dpad_up=
dpad_down=
dpad_left=
dpad_right=
capture=
home=
simulate_<BUTTON>=

Possible Values:

  • 1 to 31: Represent the Button ID of the controller
  • X, -X, Y, -Y, Z, -Z, Rz, -Rz, Rx, -Rx, Ry, -Ry, Slider, -Slider, Dial, -Dial, Brake, -Brake, Accelerator, -Accelerator: Represents the analog inputs (e.g., joystick, slider).
  • None (or 0): Unmapped.
  • 32 to 35: Represents the hat switch (D-Pad) directions:
    • 32 — dpad_up
    • 33 — dpad_down
    • 34 — dpad_left
    • 35 — dpad_right

Deadzone & Factor configuration

You can adjust the deadzone and factor for each analog input to fine-tune the controller response.

  • Deadzone: Defines a region around the neutral position of an analog stick where inputs are ignored, preventing unintended movements.
  • Factor: Adjusts the input scaling, allowing for compensation if the controller isn't reaching its full range of motion.
deadzone_x=20
deadzone_y=20
deadzone_z=20
deadzone_rz=20
deadzone_rx=5
deadzone_ry=5
deadzone_slider=20
deadzone_dial=20
deadzone_brake=20
deadzone_accelerator=20

factor_x=100
factor_y=100
factor_z=100
factor_rz=100
factor_rx=100
factor_ry=100
factor_slider=100
factor_dial=100
factor_brake=100
factor_accelerator=100

All these values are in percentages

  • Typical deadzone range: 0% to 30%
  • Typical Factor range: 100% to 150%

Home & Capture shortcuts

By default, the HOME and CAPTURE can be triggered by pressing Minus + DPAD_DOWN and Minus + DPAD_UP, respectively. Minus button is often mapped to the select button.

Simulating buttons

You can simulate buttons by combining multiple button presses. For example:

simulate_L=minus+plus
simulate_A=L+R
simulate_rstick_click=ZL

This configuration allows you to trigger specific buttons using combinations of other buttons, offering more flexibility in custom mappings.

Rumble on a controller without a dedicated driver

Controllers sys-con has a driver for (xbox, xbox360, xbox360w, xboxone, dualshock3, switch, wii — the Wii U GameCube adapter —, sinput and steam2026) rumble on their own. Any other pad is handled as a generic HID device, and for those you can describe the rumble report yourself with vibration=:

[054c-09cc] ;DualShock 4 v2
vibration=05 01 00 00 RR LL 00*26

The value is the output report written out in hex, with the amplitudes left as placeholders:

Placeholder Meaning
LL low frequency (heavy) motor, one byte
RR high frequency (light) motor, one byte
LLLL / RRRR two bytes, most significant first
llll / rrrr two bytes, least significant first
00*26 repeats the byte before it, 26 bytes in total

Spaces are ignored, everything else is sent as written, and the report goes to the controller's output endpoint. A report cannot be longer than 64 bytes, and anything that is not a hex pair, a placeholder or a repeat is refused with an error in the log. Capture a rumble report from the PC driver with Wireshark (see doc/WiresharkCapture.md) to find the bytes for a pad that is not in config.ini yet.

Rumble is only delivered to the pad in mode=mitm.

Network controller (for testing)

sys-con can present a controller that is driven from a PC over the network instead of by hardware, so input can be scripted without anything plugged in. It is disabled by default.

Edit /config/sys-con/config.ini:

[global]
network_controller=1
network_controller_port=56789

Reboot the Nintendo Switch, then from a PC on the same network:

python tools/networkpad.py --host <switch-ip> tap A
python tools/networkpad.py --host <switch-ip> --hold 1 stick left 0 1
python tools/networkpad.py --host <switch-ip> buttons      # list the button names

The pad appears on the console when the first packet arrives, and holds whatever state it was last sent — so a button stays pressed until something releases it. tools/networkpad.py is also importable if you would rather script it:

from networkpad import NetworkPad
with NetworkPad("192.168.1.42") as pad:
    pad.tap("A")
    pad.stick("left", 0.0, 1.0, hold=0.5)

Its button mapping lives in the [network] profile in config.ini and can be remapped like any other controller. That profile (with driver=network) and the [ffff-0001] section pointing at it (profile=network) are both required: the network pad is never auto-added, and without them sys-con logs NetworkPad: config.ini has no [network] profile - network controller disabled and creates no pad. If you are upgrading with your own config.ini, copy both sections from the new one.

This opens a UDP port that anyone on your network can send button presses to. There is no authentication. Leave network_controller=0 unless you are actively testing.

Troubleshooting

For common issues a troubleshooting guide is available: Troubleshooting

Contribution

All contributions are welcome, you can be a simple user or developer, if you did some mapping work in the config.ini or if you have any feedback, feel free to share it in Discussions or submit a Pull request

Building (For developers)

Don't download the project as ZIP as it will not copy submodules properly, prefer a git clone: git clone --recurse-submodules -j8 https://github.com/o0Zz/sys-con.git

Updating an existing clone? The submodules moved from lib/ to external/. After pulling, run git submodule sync --recursive && git submodule update --init --recursive, and delete any stale build/ directory — a CMake cache from before the move still points at the old paths and fails with a confusing "not found" error. A leftover empty lib/ directory can be removed by hand.

Like all other switch projects, you will need devkitA64 set up on your system.

Setup your environment on windows:

Full procedure here: https://devkitpro.org/wiki/devkitPro_pacman

  1. Add these variables to your environement system
DEVKITPRO=/opt/devkitpro
DEVKITARM=/opt/devkitpro/devkitARM
DEVKITPPC=/opt/devkitpro/devkitPPC
  1. Download and install msys64: https://www.msys2.org/#installation
  2. Open msys and type:
pacman-key --recv BC26F752D25B92CE272E0F44F7FD5492264BB9D0 --keyserver keyserver.ubuntu.com
pacman-key --lsign BC26F752D25B92CE272E0F44F7FD5492264BB9D0
wget https://pkg.devkitpro.org/devkitpro-keyring.pkg.tar.xz
pacman -U devkitpro-keyring.pkg.tar.xz
echo "[dkp-libs]" >> /etc/pacman.conf
echo "Server = https://pkg.devkitpro.org/packages" >> /etc/pacman.conf
echo "[dkp-windows]" >> /etc/pacman.conf
echo "Server = https://pkg.devkitpro.org/packages/windows/$arch/" >> /etc/pacman.conf
pacman -Syu
pacman -S switch-dev

Install extra dependencies for sys-con

Open MSYS2 console from devkitA64 and type below commands:

pacman -S make
pacman -S git
pacman -S switch-libjpeg-turbo
pacman -S zip
pacman -S diffutils
make -C external/libnx install

Build the project with Visual Studio Code

You need to select msys as default terminal in VSCode:

CTRL+SHIFT+P
Select "Terminal: Select default profile"
Select "msys2"

Then build:

CTRL+SHIFT+P
Select "Tasks: Run tasks"
Select "Build Release"

Build the project directly from MSYS

Open MSYS console, move to the project root directory and use one of the following commands:

  • make -j8: Build the project
  • make clean: Cleans the project files (but not the dependencies).
  • make mrproper: Cleans the project files and the dependencies.
  • make dist: Clean, build and package sys-con into a zip (Similar to github release packages)
  • make distclean: Same as make dist, but also cleans the dependencies first

Output folder will be there: out/ For an in-depth explanation of how sys-con works, see doc/ARCHITECTURE.md.

Debug the application

In order to debug the applicaiton, you can directly refer to the logs available there: /config/sys-con/log.txt.

Credits

  • Texita For contributions to controller testing and mappings.
  • gingerphoenix10 For implementing the Steam controller driver.

Support

If you want to support this work

ko-fi

About

Nintendo Switch sysmodule that allows support for third-party controllers (XBox, PSX, PC, Wii, ...)

Topics

Resources

Stars

217 stars

Watchers

10 watching

Forks

Releases

Packages

Contributors

Languages