Joycon2Android
1.3.0 · GitHub
More about this app
Connects Nintendo Switch 2 Joy-Con controllers over BLE and exposes them as system-wide virtual gamepads via a Shizuku UHID relay.
Joycon2Android
Use Nintendo Switch 2 Joy-Con 2 and Pro Controllers on Android — as gamepads in any app, and with motion in emulators.
Android can't pair these controllers from its Bluetooth settings, because they use their own BLE protocol rather than standard HID. Joycon2Android connects to them itself and presents each player as an ordinary gamepad.
Features
- Joy-Con 2 and Switch 2 Pro Controller — connect several at once, GL/GR paddles included.
- Up to 8 players — each with a sideways Joy-Con, a pair, or a Pro Controller.
- A gamepad per player — every app sees one standard controller per player, so multiplayer just works.
- Motion for emulators — a DSU (cemuhook) server streams gyro, accelerometer, buttons and sticks for players 1–4.
- One-tap emulator setup — writes controller and motion bindings for Eden and Dolphin.
- Custom button mapping — choose which button drives which emulator button, per console.
- Live readout of buttons, sticks, motion and battery, with each card in the controller's real shell colour.
Setup guide
What you need
- Android 7.0 (API 24) or newer, with Bluetooth LE
- Joy-Con 2 or a Switch 2 Pro Controller
- Shizuku, for the virtual gamepad and emulator auto setup — DSU motion works without it
Important
Press SYNC every time you connect. Only a Switch 2 can wake a controller back up from a button press (why).
1. Install
- Download the APK from the latest release and install it. Allow Nearby devices when asked.
- Install Shizuku from Google Play
or GitHub, and start it:
- Wireless debugging (no root, recommended): Developer options → Wireless debugging, then pair from Shizuku's notification.
- ADB:
adb shell sh /storage/emulated/0/Android/data/moe.shizuku.privileged.api/start.sh - Root: tap Start.
2. Connect
- Hold SYNC on the controller and tap Scan.
- Assign each controller to a player — from the app, or with the Switch combos: L on one Joy-Con and R on another for a pair, SL + SR for a sideways Joy-Con, L + R on a Pro Controller.
3. Turn on the virtual gamepad
Turn on Virtual Gamepad and grant Shizuku permission the first time. Each player appears to every
app as its own controller, Joy-Con Virtual Gamepad <N>. The app stays connected in the background
while its notification is showing.
4. Motion for emulators (optional)
A gamepad has no motion channel, so for gyro aiming turn on DSU Motion Server. Emulators on the
same device connect to 127.0.0.1:26760.
- Players 1–4 get motion. A pair streams from its right Joy-Con, and its left one too when a slot is free.
- Rest each controller for ~2 s at the start; the gyro recalibrates whenever it's still.
Tip
DSU and the virtual gamepad are independent. With both on, an emulator sees each controller twice — map from one, and turn the gamepad off while mapping DSU inputs so detection doesn't grab it.
Settings
The gear at the top right opens the settings panel:
- Layout — detailed controller graphics or compact rows.
- Faster controller updates — Joy-Cons send input about twice as often, for smoother motion and quicker buttons, at a battery cost. Applies while the virtual gamepad or DSU is on.
- Ignore this device's motion in Eden (on by default, needs Shizuku) — stops Eden mixing this device's gyro into Player 1. Lifted when the virtual gamepad and DSU are both off.
5. Set up your emulator
Both cards have Emulator auto setup: pick an emulator and tap Set up. The app offers to start the emulator afterwards — it only reads its config when it starts.
| Card | Emulators | What it writes |
|---|---|---|
| Virtual Gamepad | Eden, Eden Nightly, Dolphin (GameCube) | buttons and sticks |
| DSU Motion Server | Eden, Eden Nightly, Dolphin (Wii) | buttons, sticks and motion |
The gamepad button beside Set up opens the mapping editor, with a card per connected player — tap one to open its bindings. A single Joy-Con is set up as a Pro Controller held sideways, so every button works in every game (why). A target can take several sources — tick as many as you like, and any of them fires it.
- Layouts. Each player picks a layout to start from, which resets their changes. The card reads Custom once you change a binding, and the layout's name again if you change it back.
- Saving. The save icon beside the name keeps your mapping as a layout for any player holding the same body. It dims when the mapping already matches a layout. Deleting a layout (the bin in the dropdown) keeps everyone's buttons; they just read Custom until you save again.
- All players at the top sets and saves everyone at once. A grip only some bodies fit — Mario Kart Wheel, say — gives the rest the same game's other grip. A saved set remembers who held which body ("P1 L, P2 R, P3 L/R") and stays greyed out until those players are back.
- Sideways Wii Remote. On the Wii console, a lone Joy-Con also gets this switch, for games that steer by tilting a sideways remote. On, up on the stick is towards the rail; off, towards L or R. The layout sets it (on for Mario Kart) and you can override it until you next pick a layout.
The layouts the app ships:
| Layout | For |
|---|---|
| Wii | The Wii Remote's own arrangement: the trigger under your finger is B, 1 and 2 under the thumb |
| Joy-Con | The same, with the Joy-Con's own B as B, 1 and 2 on the shoulders so your thumb stays on the stick, and Recenter on the stick click |
| Mario Kart Wheel | A lone Joy-Con held sideways as a wheel, laid out the way Mario Kart 8 uses one — 2 accelerates, 1 brakes, SR hops and tricks, and SL throws an item alongside the stick. Steers by tilt, so it plays as a sideways Wii Remote: the d-pad turns with it and a right Joy-Con aims from its tail |
| Mario Kart Nunchuck | The remote-and-nunchuk scheme, which steers by stick instead. A pair splits the halves across the hands, each index finger on the shoulder its controller keeps a trigger on; a lone Joy-Con plays both halves itself, its own stick standing in for the Nunchuk's and its rails carrying C and Z |
Note
Auto setup needs Shizuku, and some devices block writing into another app's Android/data — use
manual setup if it fails. Emulators rewrite their config when they exit, so let the
app close an open one first. Run Set up again after changing players or updating the app.
Manual setup
The DSU server binds each player to slot N−1. Press-to-detect in Android emulators never sees DSU inputs, so pick them from the input list instead. The info button on the DSU mapping screen has these steps and the server address to copy.
DSU input names
DSU uses DS4 names. SL, SR and C aren't streamed, except that a sideways Joy-Con's SL/SR arrive as its shoulder buttons.
| Button | DSU name | Button | DSU name |
|---|---|---|---|
| A | Circle |
B | Cross |
| X | Triangle |
Y | Square |
| L / R | L1 / R1 |
ZL / ZR | L2 / R2 |
| − / + | Share / Options |
LS / RS | L3 / R3 |
| Home | PS |
Capture | Touch Button |
| D-pad | Pad N/S/E/W |
Sticks | Left X±/Y±, Right X±/Y± |
Eden
- In Eden's controller settings, turn on motion and the UDP controller, and add
127.0.0.1:26760as a server. - Point each player's buttons, sticks and motion at the UDP controller. A pair has two motion inputs: the second reads the left Joy-Con's own slot.
Dolphin (Wii)
Create
Android/data/org.dolphinemu.dolphinemu/files/Config/DSUClient.inicontaining exactly:[Server] Enabled = True Entries = Joycon2:127.0.0.1:26760;Restart Dolphin and open Wii Remote N → Emulated. A
DSUClient/<slot>/Joycon2device appears once Dolphin's DSU client starts — open a mapping screen or a game first.Map buttons from the input list (long-press → Advanced Mapping).
Under Motion Input, map the accelerometer and gyroscope, and map Recenter — press it while aiming at the screen centre to bring the pointer back. A pair maps name-to-name; a single Joy-Con streams in its sideways grip, so map it back to the remote's body:
Dolphin input Pair Left Joy-Con Right Joy-Con Accelerometer Up / Down Accel Up/Downsame same Accelerometer Left / Right Accel Left/RightAccel Backward/ForwardAccel Forward/BackwardAccelerometer Forward / Backward Accel Forward/BackwardAccel Left/RightAccel Right/LeftGyroscope Pitch Up / Down Gyro Pitch Up/DownGyro Roll Right/LeftGyro Roll Left/RightGyroscope Roll Left / Right Gyro Roll Left/RightGyro Pitch Up/DownGyro Pitch Down/UpGyroscope Yaw Left / Right Gyro Yaw Left/Rightsame same That restores each Joy-Con's own body, which is what pointing wants: the remote's nose is the shoulder edge, so aim R/ZR (or L/ZL) at the screen. Also set Total Yaw to around 60 — Dolphin's 25 clamps the cursor after ±12.5° of turn, which a hand-held aim overruns.
For a game written for a sideways Wii Remote (Mario Kart Wii and its Wii Wheel) — both Mario Kart layouts write these for you:
- Give a right Joy-Con the left column. Sideways, its top edge points where a sideways remote's tail does, so without that half turn the wheel steers backwards; a left Joy-Con already matches. Aiming then moves to the tail on that body.
- Turn the four D-pad bindings a quarter: put the source you'd bind to Up on D-Pad/Right, Right on Down, Down on Left, Left on Up. A sideways remote's d-pad turns with it, so the player's up is the remote's right.
- For tricks and wheelies, append
+ pulse(<flick>, 0.6) * max(sin(timer(0.15) * 6.2832), 0) * 50to IMUAccelerometer/Up, where<flick>is(\`Gyro Pitch Up\` / 9) & not(pulse(\`Gyro Pitch Down\` / 9, 0.4))— then the same on /Down with Up and Down swapped (why). Dolphin's own Shake group doesn't land tricks, but you can bind Shake to a button.
Under Swing, set Forward to
(`Accel Forward` - `Accel Backward`) - smooth((`Accel Forward` - `Accel Backward`), 0.03), Range to 7% and Dead Zone to 20%. For a single Joy-Con use whichever pair its nose reads above —Accel Right/Lefton a right Joy-Con, and the other way round when it plays sideways. This lets thrusts reach games like Wii Play Billiards (why).Pair only: under Nunchuk → Motion Input, map each accelerometer entry to the left Joy-Con's slot, e.g.
`DSUClient/3/Joycon2:Accel Up`— the highest slot no player uses (3 with one player).
Warning
Leave Dolphin's Sideways Wii Remote off with this mapping — it rotates motion a second time.
Troubleshooting
| Problem | Fix |
|---|---|
| "Shizuku is not running" | Open Shizuku and start it |
| "Shizuku permission denied" | Shizuku → Apps → allow Joycon2Android |
| Controller not found | Hold SYNC again and move closer |
| Controller stops responding | Press SYNC and reconnect; wait a moment if it stays silent |
| Gamepad doesn't show up in games | Check adb shell getevent -p lists "Joy-Con Virtual Gamepad" |
| No DSUClient device in the emulator | Check the server address, restart the emulator and open a mapping screen; adb logcat -s DsuServer shows whether it's connecting |
| Emulator won't detect DSU presses | Pick inputs from the list — detection never sees DSU — with the virtual gamepad off |
| Motion aiming stutters | Settings (gear, top right): keep Ignore this device's motion in Eden on, and try Faster controller updates |
| Tilting the device moves the aim in Eden | Turn on Ignore this device's motion in Eden |
| Pointer drifts or starts off-screen | Rest the controller for ~2 s, then press Recenter |
| MotionPlus tutorial replays every boot (Dolphin) | Set MPLS.MOVIE in Wii/shared2/sys/SYSCONF with Dolphin closed (why) |
Roadmap and feedback
Planned and in-progress work is on the project board.
Every card is an issue you can subscribe to, and area: labels filter it to the parts
you use. Found a bug or want something? Open an issue.
Contributing
Start with CONTRIBUTING.md, then the docs:
- Architecture and adding a feature
- BLE protocol — identifiers, packets, Android BLE gotchas
- Virtual gamepad — UHID, keycodes, sideways Joy-Cons
- DSU motion — slots, motion frames, emulator mapping details
- Debug tools — a DSU client for inspecting the stream
Credits
Built on the community's reverse-engineering work, in particular:
- Joycon2forMac by seitanmen — the working macOS BLE implementation the connection sequence, init commands and packet layout came from.
- JoyconDriver by german77 — Switch controller protocol docs, including the Switch 2 Wireshark dissector and SPI flash map (shell colours).
- ProCon 2 Enabler Tool by HandHeldLegend — a Web Bluetooth implementation whose SPI-read bytes unlocked reading controller colours.
- Nintendo_Switch_Reverse_Engineering by dekuNukem — the original Joy-Con docs, and the battery voltage thresholds.
- cemuhook protocol docs by v1993 — the DSU wire format.
- Shizuku by RikkaApps — privileged access without root.
License
GNU General Public License v3.0. If you find this useful, you can support development on Ko-fi.
Disclaimer
Not affiliated with, endorsed by, or sponsored by Nintendo. Joy-Con, Nintendo Switch and GameCube are trademarks of Nintendo. The BLE protocol was reverse-engineered by the community from their own hardware; this project contains no Nintendo code.
Claude (Anthropic's AI assistant) was used in building this project, directed and reviewed throughout by a professional software and Android engineer.
How Shizuku is used
Can expose Joy-Cons as virtual gamepads, configure emulators and block motion sensors via `Shizuku newProcess` shell processes.
This is an AI-assisted analysis of Shizuku-related usages in the app's public source code. It is best effort, so it may not catch every single usage.
How this app uses Shizuku
Shizuku is used to run a privileged helper and shell commands that turn connected Joy-Cons into usable controllers and set up emulator apps.
- Create virtual gamepads: connected Joy-Con input is exposed as system-wide virtual gamepads by launching a bundled relay helper through Shizuku and streaming button, stick, trigger and motion reports to it through
/dev/uhid. - Install relay helper: the relay binary is copied from the app to a shell accessible location and made executable with a
cpandchmodshell command through Shizuku before it is launched. - Configure emulator controls: controller mappings and network motion settings for Dolphin and Eden are applied by reading their config files with
catand writing updated files with redirectedcat, checking whether the emulator is running withpidofand stopping it witham force-stopwhen the user chooses to close it first. - Block device motion: physical device motion is blocked or unblocked for Eden packages with the
cmd sensorserviceshell command through Shizuku so emulator motion input comes from the Joy-Cons.
Android APIs or commands used
catmkdir -pcpchmod 755pidofam force-stopcmd sensorservice set-uid-statecmd sensorservice reset-uid-state/dev/uhid
Changelog
What's new for version 1.3.0
Wii layouts for every player, Mario Kart grips that trick with a flick, and a Joy-Con pair that plays as one Wii Remote in Dolphin. Run Set up again to apply them.
What's new
- Every player picks their own layout. Map buttons per player, save a mapping as a layout, or set everyone at once from All players.
- Wii layouts, including two for Mario Kart. Choose Wii, Joy-Con, Mario Kart Wheel (steer by tilt) or Mario Kart Nunchuck (steer by stick).
- Mario Kart tricks and wheelies land with a flick. Flick the Joy-Con, or press the shoulder you hop with, as the kart leaves a ramp.
- A lone Joy-Con can play as a sideways Wii Remote. A per-player switch turns steering and the d-pad for games held sideways; with it off, up on the stick points toward L or R.
- Recenter can go on any button. It sits on R (L on a lone left Joy-Con), or the stick click in the Joy-Con layout.
- A Joy-Con pair plays as one Wii Remote in Dolphin. Both Joy-Cons drive one player and one pointer.
Install
Download joycon2android-1.3.0.apk below and install it over your existing copy. See the README for the full setup guide.
Notes
- SYNC is required for every connection. Switch 2's button-press reconnect is console-exclusive at the link layer and can't be reproduced through Android's BLE API.
- Not affiliated with, endorsed by, or sponsored by Nintendo. The BLE protocol was reverse-engineered by the community; this project contains no Nintendo code. See the credits.
Permissions
13 permissions requested