I wanted to operate Splatoon 2 of Nintendo Switch with a mouse. In the streets, converters that can move the Nintendo switch with a mouse are already on the market. However, commercial converters only replaced the movement of the mouse stick with the movement of the mouse (as far as I could see). I thought that it would not work well with that method. Therefore, I made a device that replaces the movement of the gyro of the professional controller with the movement of the mouse.
However, it became something that I could not operate well with my technical skills. I think that the method of replacing the movement of the gyro with the movement of the mouse will be practical if made well. I'm going to publish what I've done so far here.
Articles that were very helpful
-Operate Nintendo Switch with your smartphone ~ Simulate Pro Controller with USB Gadget ~
The mouse I'm using https://www.elecom.co.jp/products/M-Y8UBXBK.html I think this is probably the case. If the data format sent by the mouse is the same as that of my mouse, I think it will save you the trouble of rewriting the python code that will be posted later.
Please set up Raspberry Pi (this time I chose Raspbian as the OS normally).
Turn on the wired connection in the Nintendo Switch controller settings.
Turn on the gyro in the Splatoon 2 settings.
Find out the Vendor ID (VID) of your mouse. The VID of my ELECOM mouse was 04F3
Connect your mouse, keyboard, and Pro controller to the Raspberry Pi's USB Type-A port.
Connect HDMI port 0 on the Raspberry Pi to the display.
The connected display is for displaying the screen of Raspberry Pi. The display that displays the game screen connects to the HDMI port on the Nintendo Switch dock.
After confirming that the Nintendo Switch is activated,
Connect the Nintendo Switch to the Type-C port (I connected it to the USB port on the Nintendo Switch Dock).
Then Raspberry Pi will start.
In Raspbian, add dtoverlay = dwc2 to /boot/config.txt and dwc2 and libcomposite to / etc / modules to load the dwc2 module.
Be able to become superuser with su
on the command line
Create a file called add_procon_gadget.sh shown below
Type source add_procon_gadget.sh
on the command line
add_procon_gadget.sh
#!/bin/bash
cd /sys/kernel/config/usb_gadget/
mkdir -p procon
cd procon
echo 0x057e > idVendor
echo 0x2009 > idProduct
echo 0x0200 > bcdDevice
echo 0x0200 > bcdUSB
echo 0x00 > bDeviceClass
echo 0x00 > bDeviceSubClass
echo 0x00 > bDeviceProtocol
mkdir -p strings/0x409
echo "000000000001" > strings/0x409/serialnumber
echo "Nintendo Co., Ltd." > strings/0x409/manufacturer
echo "Pro Controller" > strings/0x409/product
mkdir -p configs/c.1/strings/0x409
echo "Nintendo Switch Pro Controller" > configs/c.1/strings/0x409/configuration
echo 500 > configs/c.1/MaxPower
echo 0xa0 > configs/c.1/bmAttributes
mkdir -p functions/hid.usb0
echo 0 > functions/hid.usb0/protocol
echo 0 > functions/hid.usb0/subclass
echo 64 > functions/hid.usb0/report_length
echo 050115000904A1018530050105091901290A150025017501950A5500650081020509190B290E150025017501950481027501950281030B01000100A1000B300001000B310001000B320001000B35000100150027FFFF0000751095048102C00B39000100150025073500463B0165147504950181020509190F2912150025017501950481027508953481030600FF852109017508953F8103858109027508953F8103850109037508953F9183851009047508953F9183858009057508953F9183858209067508953F9183C0 | xxd -r -ps > functions/hid.usb0/report_desc
ln -s functions/hid.usb0 configs/c.1/
ls /sys/class/udc > UDC
Type ʻexiton the command line to return to a normal user. Type
sudo dmesg | grep -A7 057e` on the command line.
pi@raspberrypi:~ $ sudo dmesg | grep -A7 057e
[ 7201.091044] usb 1-1.3: New USB device found, idVendor=057e, idProduct=2009, bcdDevice= 2.00
[ 7201.091060] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 7201.091074] usb 1-1.3: Product: Pro Controller
[ 7201.091087] usb 1-1.3: Manufacturer: Nintendo Co., Ltd.
[ 7201.091099] usb 1-1.3: SerialNumber: 000000000001
[ 7201.112454] input: Nintendo Co., Ltd. Pro Controller as /devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.3/1-1.3:1.0/0003:057E:2009.0002/input/input1
[ 7201.114447] hid-generic 0003:057E:2009.0002: input,hidraw0: USB HID v1.11 Joystick [Nintendo Co., Ltd. Pro Controller] on usb-0000:01:00.0-1.3/input0
There is a place where it says hidraw0. This is like a file that represents a Pro controller, and the numbers below hidraw may vary depending on your environment, so check what number hidraw is.
Next, the mouse will find out what number hidraw is, so on the command line
sudo dmesg | grep -A7 Replace the" mouse VID "part of the mouse VID
with the mouse VID and hit it. The VID of my ELECOM mouse was 04F3
.
Check what number your mouse is hidraw.
Create a program that interrupts mouse operation data between the communication between the Nintendo Switch and the Pro controller. Create the Python code file shown below. (Sorry for the very dirty code).
mouse_gyro.py
#!/usr/bin/env python3
import os
import threading
import time
import random
# Re-connect USB Gadget device
os.system('echo > /sys/kernel/config/usb_gadget/procon/UDC')
os.system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC')
time.sleep(0.5)
gadget = os.open('/dev/hidg0', os.O_RDWR | os.O_NONBLOCK)
procon = os.open('/dev/hidraw3', os.O_RDWR | os.O_NONBLOCK)
mouse = os.open('/dev/hidraw2', os.O_RDWR | os.O_NONBLOCK)
mouse_int = bytes([0,0,0,0])
def mouse_input():
global mouse_int
while True:
try:
mouse_int = os.read(mouse, 128)
#print('<<<', output_data.hex())
#print(output_mouse.hex())
#os.write(gadget, output_mouse)
except BlockingIOError:
pass
except:
os._exit(1)
def procon_input():
while True:
try:
input_data = os.read(gadget, 128)
#print('>>>', input_data.hex())
os.write(procon, input_data)
except BlockingIOError:
pass
except:
os._exit(1)
def convert(ou_dt_i, mo_in_i, weight, reflect):
mo_in_i = int.from_bytes(mo_in_i, byteorder='little', signed=True)
ou_dt_i = int.from_bytes(ou_dt_i, byteorder='little', signed=True)
if reflect == True:
mo_in_i = mo_in_i * -1
ou_dt_i = ou_dt_i * -1
merged_gy = ou_dt_i + mo_in_i * weight
if merged_gy > 32767:
merged_gy = 32767
elif merged_gy < -32768:
merged_gy = -32768
else:
pass
merged_gy = merged_gy.to_bytes(2, byteorder='little', signed=True)
return merged_gy
def replace_mouse(output_data, mouse_int):
#a = output_data[0:13]
#mouse no click wo migi no button ni henkan
ri_btn = 0
if mouse_int[0] == 1:#hidari click
ri_btn = 0x80#ZR button
elif mouse_int[0] == 2:#migi click
ri_btn = 0x40#R button
elif mouse_int[0] == 4:#chuu click
ri_btn = 0x08#A button
ri_btn = (output_data[3] + ri_btn).to_bytes(1, byteorder='little')
a = output_data[0:3] + ri_btn + output_data[4:13]
#kasokudo sensor ni tekitou ni atai wo ire naito setsuzoku ga kireru
if mouse_int[1] != 0:
b = 127
else:
b=0
if mouse_int[2] != 0:
b = 127
else:
b = 0
d = bytes([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0])
ac0 = bytes([255]) if output_data[14] + b > 255 else bytes([output_data[14] + b])
ac1 = bytes([255]) if output_data[16] + b > 255 else bytes([output_data[16] + b])
ac2 = bytes([255]) if output_data[18] + b > 255 else bytes([output_data[18] + b])
ac0_1 = bytes([255]) if output_data[26] + b > 255 else bytes([output_data[26] + b])
ac1_1 = bytes([255]) if output_data[28] + b > 255 else bytes([output_data[28] + b])
ac2_1 = bytes([255]) if output_data[30] + b > 255 else bytes([output_data[30] + b])
ac0_2 = bytes([255]) if output_data[38] + b > 255 else bytes([output_data[38] + b])
ac1_2 = bytes([255]) if output_data[40] + b > 255 else bytes([output_data[40] + b])
ac2_2 = bytes([255]) if output_data[42] + b > 255 else bytes([output_data[42] + b])
#mouse no ugoki wo gyro no ugoki ni henkan
gy0_0 = convert(output_data[19:21], mouse_int[1:2], 250, False)#
gy1_0 = convert(output_data[21:23], mouse_int[2:3], 250, False)#
gy2_0 = convert(output_data[23:25], mouse_int[2:3], 0, False)#
gy0_1 = convert(output_data[31:33], mouse_int[1:2], 250, False)#
gy1_1 = convert(output_data[33:35], mouse_int[2:3], 250, False)#
gy2_1 = convert(output_data[35:37], mouse_int[2:3], 0, False)#
gy0_2 = convert(output_data[43:45], mouse_int[1:2], 250, False)#
gy1_2 = convert(output_data[45:47], mouse_int[2:3], 250, False)#
gy2_2 = convert(output_data[47:49], mouse_int[2:3], 0, False)#
e = a+output_data[13:14]+ac0+output_data[15:16]+ac1+output_data[17:18]+ac2 \
+gy0_0+gy1_0+gy2_0 \
+output_data[25:26]+ac0_1+output_data[27:28]+ac1_1+output_data[29:30]+ac2_1 \
+gy0_1+gy1_1+gy2_1 \
+output_data[37:38]+ac0_2+output_data[39:40]+ac1_2+output_data[41:42]+ac2_2 \
+gy0_2+gy1_2+gy2_2 \
+d
print(int.from_bytes(gy1_0, byteorder='little'))
#print(mouse_int[1])
return e
def procon_output():
global mouse_int
while True:
try:
output_data = os.read(procon, 128)
#output_mouse = os.read(mouse, 128)
#print('<<<', output_data.hex())
#print(output_data)
e = replace_mouse(output_data, mouse_int)
#print(e.hex())
os.write(gadget, e)#output_data
mouse_int = bytes([0,0,0,0])
except BlockingIOError:
pass
except Exception as g:
print(type(g))
print(g)
os._exit(1)
threading.Thread(target=procon_input).start()
threading.Thread(target=procon_output).start()
threading.Thread(target=mouse_input).start()
Rewrite the number after hidraw assigned to the variables procon
and mouse
to the number you confirmed earlier.
Next, I rewrite the python code to match the python code with the signal sent by the mouse.
The mouse I'm using
https://www.elecom.co.jp/products/M-Y8UBXBK.html
I think this is probably the case, but with it you may not need to rewrite your code.
To find out what data your mouse sends, uncomment #print (output_mouse.hex ())
in the mouse_input ()
function. Instead, it's easier to see if you comment out the print ()
part elsewhere.
To run this python code, type sudo python3 mouse_gyro.py
on the command line.
Hopefully, you can move the gyro awkwardly with the mouse, like the video above.
It often happens that the Pro controller is disconnected in the middle. Try following the instructions on the switch screen, or press and hold the small round button on the side of the controller to re-register the controller.
At that time, the next number of hidraw may change. In that case, rewrite the assignment part of the procon
variable of the python code by typing the command to check the hidraw number written above again.
If you watched the above video or tried the operation, you will understand. Even if I move the mouse, the gyro does not move properly. I would like to ask for your help. The Python code is available on GitHub, and there is no special license, so feel free to modify it. I would be very grateful if you could cooperate.
Thank you for reading.
https://github.com/Bokuchin/SwitchProconGyroMouse
-Operate Nintendo Switch with your smartphone ~ Simulate Pro Controller with USB Gadget ~
Recommended Posts