-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 067b1a1
Showing
22 changed files
with
1,671 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
remotegamepad |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
# remotegamepad | ||
|
||
Remote Gamepad allows you or your friends to use any browser-supported gamepad | ||
to mimic a Nintendo Switch Pro Controller by using a Raspberry Pi as a relay. | ||
|
||
![remotegamepad screenshot](remotegamepad_screenshot.png) | ||
|
||
## How It Works | ||
|
||
* Web browsers have a [Gamepad API](https://caniuse.com/gamepad). You can check if your gamepad/controller is supported at [Gamepad Tester](https://gamepad-tester.com/). | ||
* Inexpensive devices such as the Raspberry Pi Zero W are capable of imitating a Nintendo Switch Pro Controller when placed in OTG/USB gadget mode. | ||
* Remote Gamepad provides some glue between the two by setting up button mapping and sending a stream of controller data to the Raspberry Pi which in turn will relay it to the Switch via USB. | ||
|
||
If you have a capture card and a low latency way to share the video stream, you | ||
can game with friends who don't have a Switch over the Internet. Map/redirect a | ||
port on your router/gateway to port 8085 on your Raspberry Pi and have your | ||
friend connect to it with their browser. | ||
|
||
## Requirements | ||
|
||
* Nintendo Switch | ||
* Nintendo Switch Dock | ||
* Raspberry Pi Zero W, Raspberry Pi 4 Model B, or other board cable of OTG mode+network | ||
* Browser support for your controller/gamepad | ||
|
||
## Pi Setup | ||
|
||
Enable dwc2 USB controller driver | ||
|
||
echo "dtoverlay=dwc2" | sudo tee -a /boot/config.txt | ||
|
||
Enable needed kernel modules | ||
|
||
echo "dwc2" | sudo tee -a /etc/modules.d/dwc2.conf | ||
echo "libcomposite" | sudo tee -a /etc/modules.d/libcomposite.conf | ||
|
||
Reboot for changes to take effect | ||
|
||
sudo reboot | ||
|
||
Download [add_procon_gadget.sh](https://gist.github.com/mzyy94/60ae253a45e2759451789a117c59acf9#file-add_procon_gadget-sh) | ||
and run it with root privileges. By default the resulting device, `/dev/hidg0` can only be used by root. You should chown/chmod like so: | ||
|
||
sudo chown root:dialout /dev/hidg0 | ||
sudo chmod 660 /dev/hidg0 | ||
|
||
If you're going to be using the setup long-term, a udev rule should be used instead. | ||
|
||
## Launch | ||
|
||
[Download the release](https://github.com/jolan/remotegamepad/releases), extract it, | ||
`cd` into the directory and run `./remotegamepad` | ||
|
||
Or get the source: | ||
|
||
go get -u -v github.com/jolan/remotepamepad | ||
|
||
And then build and run it: | ||
|
||
cd ~/go/src/github.com/jolan/remotegamepad && go build && ./remotegamepad | ||
|
||
Or cross-compile it and then copy everything to the Raspberry Pi: | ||
|
||
env GOOS=linux GOARCH=arm GOARM=6 go build | ||
|
||
The binary expects to find `webroot` in the same directory that is run from. | ||
|
||
Finally, enter the URL to your Raspberry Pi (e.g. http://192.0.2.53:8085) into your browser. | ||
|
||
## Adding A Profile For A Controller | ||
|
||
1. Go to https://gamepad-tester.com/. | ||
2. Copy/paste the full controller name and annotate the button layout for your controller in gamepadStateSend(). | ||
3. Add shortname to gamepadShortName(). | ||
|
||
## Limitations | ||
|
||
* Non-Switch controllers cannot be used to wake the system from sleep. | ||
* Starting a session requires the Switch to be out of sleep mode. | ||
* At the moment, the supported controller list is hardcoded and tiny. | ||
* Can only use a single gamepad per computer (seems to be a browser limitation). | ||
* Every remote gamepad requires their own Raspberry Pi/relay device. | ||
|
||
## Roadmap | ||
|
||
* Add profiles for common controllers like Wii U, DualShock, Xbox 360, etc. | ||
* Add button mapping dialog for controllers using the default profile. | ||
* Improve binary release with systemd service, config/logging options, udev rule, etc. | ||
* Code cleanup. | ||
* Add mouse/keyboard support. | ||
* Test on non-Chrome browsers to check for bugs/quirks. | ||
* Determine if multiple controllers-on-a-single is possible. | ||
* Add audio/video streaming support. | ||
* Maybe support consoles other than the Switch one day. | ||
|
||
## Acknowledgements | ||
|
||
@mzyy94 - remotegamepad borrows much of the functionality from his work. | ||
|
||
* https://github.com/mzyy94/nscon | ||
* https://github.com/mzyy94/ns-remote | ||
* https://mzyy94.com/blog/2020/03/20/nintendo-switch-pro-controller-usb-gadget/ | ||
* https://mzyy94.com/blog/2020/04/17/nintendo-switch-audio-uac-gadget/ | ||
* https://mzyy94.com/blog/2020/05/11/play-nintendo-switch-on-smartphone/ | ||
* https://mzyy94.com/blog/2020/05/12/raspberry-pi-hdmi-edid-cec/ | ||
|
||
Thanks to others for precursor/similar/inspiring work: | ||
|
||
* @dekuNekum - https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering | ||
* @shinyquagsire23 - https://github.com/shinyquagsire23/HID-Joy-Con-Whispering | ||
* @Xfennec - https://gist.github.com/Xfennec/e1215febb15b40c21bf029b38a31640b | ||
* @mumumusuc - https://github.com/mumumusuc/pi-joystick | ||
* @omakoto - https://github.com/omakoto/raspberry-switch-control | ||
* @mart1nro - https://github.com/mart1nro/joycontrol | ||
* @javmarina - https://github.com/javmarina/Nintendo-Switch-Remote-Control | ||
* @ndeadly - https://github.com/ndeadly/MissionControl | ||
* Parsec - https://www.youtube.com/watch?v=uTlwVyWobRc | ||
|
||
## License | ||
|
||
[GPL v3](LICENSE) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
module github.com/jolan/remotegamepad | ||
|
||
go 1.15 | ||
|
||
require ( | ||
github.com/gorilla/mux v1.8.0 | ||
github.com/gorilla/websocket v1.4.2 | ||
github.com/mzyy94/nscon v0.1.0 | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= | ||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= | ||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= | ||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= | ||
github.com/mzyy94/nscon v0.1.0 h1:K6DZWWvaVtIsUxtcaLVGq6AjAHLEHPZXaTI1/81TcO0= | ||
github.com/mzyy94/nscon v0.1.0/go.mod h1:5XyHX0uDmuhaKIDkJz+Xi4BK027IcrLswlzNjg6x7L0= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package main | ||
|
||
import ( | ||
"flag" | ||
|
||
"github.com/jolan/remotegamepad/webserver" | ||
"github.com/mzyy94/nscon" | ||
) | ||
|
||
func main() { | ||
var ( | ||
device = flag.String("device", "/dev/hidg0", "simulating hid gadget path") | ||
) | ||
flag.Parse() | ||
|
||
controller := nscon.NewController(*device) | ||
|
||
webserver.StartHTTPServer(controller) | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
body { | ||
padding-top: 5rem; | ||
} | ||
.remotegamepad { | ||
padding: 3rem 1.5rem; | ||
text-align: center; | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
|
||
<head> | ||
<meta charset="utf-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no"> | ||
<meta name="description" content="Remote Gamepad allows you to connect a controller to your switch remotely"> | ||
<title>Remote Gamepad · Home</title> | ||
<link rel="apple-touch-icon" sizes="180x180" href="./apple-touch-icon.png"> | ||
<link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png" type="image/png"> | ||
<link rel="icon" type="image/png" sizes="16x16" href="./favicon-16x16.png" type="image/png"> | ||
<link rel="manifest" href="./site.webmanifest"> | ||
<!-- TODO check if updated to 4.5.3 has been pushed --> | ||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootswatch/4.5.2/slate/bootstrap.min.css" | ||
integrity="sha384-8iuq0iaMHpnH2vSyvZMSIqQuUnQA7QM+f6srIdlgBrTSEyd//AWNMyEaSF2yPzNQ" crossorigin="anonymous"> | ||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.1/css/all.css" | ||
integrity="sha384-vp86vTRFVJgpjF9jiIGPEEqYqlDwgyBgEF109VFjmqGmIY/Y4HV4d3Gp2irVfcrp" crossorigin="anonymous"> | ||
<style> | ||
.bd-placeholder-img { | ||
font-size: 1.125rem; | ||
text-anchor: middle; | ||
-webkit-user-select: none; | ||
-moz-user-select: none; | ||
-ms-user-select: none; | ||
user-select: none; | ||
} | ||
|
||
@media (min-width: 768px) { | ||
.bd-placeholder-img-lg { | ||
font-size: 3.5rem; | ||
} | ||
} | ||
</style> | ||
<link href="./css/remotegamepad.css" rel="stylesheet"> | ||
</head> | ||
|
||
<body> | ||
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top"> | ||
<a class="navbar-brand" href="#">Remote Gamepad <i class="fas fa-laptop-house"></i><i | ||
class="fas fa-gamepad"></i></a> | ||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" | ||
aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation"> | ||
<span class="navbar-toggler-icon"></span> | ||
</button> | ||
|
||
<div class="collapse navbar-collapse" id="navbarsExampleDefault"> | ||
<ul class="navbar-nav mr-auto"> | ||
<li class="nav-item active"> | ||
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a> | ||
</li> | ||
</ul> | ||
<span><a href="http://github.com/jolan/remotegamepad">v0.1.0 <i class="fab fa-github"></i></a></span> | ||
</div> | ||
</nav> | ||
|
||
<main role="main" class="container"> | ||
<div id="sessions" class="remotegamepad table-responsive"> | ||
<h1 id="sessionsActiveHeader" style="display: none;">Active Sessions</h1> | ||
<table id="sessionsActive" class="table table-bordered table-condensed table-hover table-striped" | ||
style="display: none;"> | ||
<thead> | ||
<tr> | ||
<th><i class="fas fa-gamepad fa-2x"><br></i><br>Gamepad</th> | ||
<th><i class="fab fa-raspberry-pi fa-2x"></i><br>Raspberry Pi</th> | ||
<th><i class="fas fa-stream fa-2x"></i><br>Status</th> | ||
<th><i class="fas fa-sort-amount-up-alt fa-2x"></i><br>Buffer</th> | ||
<th><i class="fas fa-cog fa-2x"></i><br>Control</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
</tbody> | ||
</table> | ||
<h1>Start Session</h1> | ||
<table id="sessionsAvailable" class="table table-bordered table-condensed table-hover table-striped"> | ||
<thead> | ||
<tr> | ||
<th style="vertical-align: middle;"><i class=" fas fa-gamepad fa-2x"></i><br>Gamepad</th> | ||
<th style="vertical-align: middle;"><i class="fas fa-sliders-h fa-2x"></i><br>Swap Buttons | ||
<button type="button" class="btn btn-sm btn-dark" data-toggle="tooltip" data-placement="top" | ||
title="Whether to swap the face buttons or not (e.g. B<->A, X<->Y)"><i | ||
class="fas fa-question-circle"></i></button> | ||
</th> | ||
<th style="vertical-align: middle;"><i class="fab fa-raspberry-pi fa-2x"></i><br>Raspberry Pi | ||
</th> | ||
<th style="vertical-align: middle;"><i class="fas fa-cog fa-2x"></i><br>Control</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
</tbody> | ||
</table> | ||
|
||
<div id="status"></div> | ||
<div class="alert alert-info alert-dismissible fade show" role="alert"> | ||
<strong>Welcome! Here are some tips to get started:</strong> | ||
<div class="text-left"> | ||
<ul> | ||
<li>Press a button or wiggle the joysticks to trigger detection of the gamepad.</li> | ||
<li>Close any applications in the background that may interfere with input e.g. Steam.</li> | ||
<li>Use Chrome/Chromium, leave the tab in the foreground, and don't refresh the page.</li> | ||
</ul> | ||
</div> | ||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"> | ||
<span aria-hidden="true">×</span> | ||
</button> | ||
</div> | ||
<!-- TODO | ||
<div class="alert alert-danger alert-dismissible fade show" role="alert"> | ||
<strong>Known Issues:</strong> | ||
<div class="text-left"> | ||
<ul> | ||
<li>Multiple gamepads don't work. Only the first/lowest gamepad will work. Seems to be a | ||
browser limitation.</li> | ||
<li>The switch needs to powered on/not sleeping when starting a session or else pairing will | ||
fail and the switch communication library used, nscon, will silently hang.</li> | ||
<li>Only two models of Xbox One and the Switch Pro Controller are currently supported.</li> | ||
</ul> | ||
</div> | ||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"> | ||
<span aria-hidden="true">×</span> | ||
</button> | ||
</div> --> | ||
</div> | ||
|
||
</main><!-- /.container --> | ||
<script src="https://code.jquery.com/jquery-3.5.1.min.js" | ||
integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script> | ||
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" | ||
integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" | ||
crossorigin="anonymous"></script> | ||
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" | ||
integrity="sha384-w1Q4orYjBQndcko6MimVbzY0tgp4pWB4lZ7lr30WKz0vr/aWKhXdBNmNb5D92v7s" | ||
crossorigin="anonymous"></script> | ||
<script src="./js/remotegamepad.config.js"></script> | ||
<!-- fallback to default config if no custom config present --> | ||
<script>if (typeof relayservers == 'undefined') { | ||
document.write(unescape("%3Cscript src='./js/remotegamepad.config-default.js' type='text/javascript'%3E%3C/script%3E")); | ||
}</script> | ||
<script src="./js/remotegamepad.js"></script> | ||
</body> | ||
|
||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
remotegamepad.config.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
var relayservers = {}; | ||
relayservers[0] = { | ||
"name": "pi", | ||
"dsn": window.location.hostname + ":" + location.port | ||
}; |
Oops, something went wrong.