Skip to content

Commit

Permalink
Fix multiple client/multiple controller support, fix button presses n…
Browse files Browse the repository at this point in the history
…ot being registered, fix controller mapping
  • Loading branch information
joaorb64 committed May 16, 2020
1 parent 2a6a243 commit e51f79c
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 45 deletions.
8 changes: 4 additions & 4 deletions Nintendo Switch Combined Joy-Cons.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"left_analog_x": "ABS_X",
"left_analog_y": "ABS_Y",
"left_analog_y": "-ABS_Y",
"right_analog_x": "ABS_RX",
"right_analog_y": "ABS_RY",
"right_analog_y": "-ABS_RY",
"dpad_up": "BTN_DPAD_UP",
"dpad_down": "BTN_DPAD_DOWN",
"dpad_left": "BTN_DPAD_LEFT",
Expand All @@ -17,8 +17,8 @@
"button_r1": "BTN_TR",
"button_r2": "BTN_TR2",
"button_r3": "BTN_THUMBR",
"button_share": "BTN_Z",
"button_options": "BTN_SELECT",
"button_share": "BTN_SELECT",
"button_options": "BTN_START",
"button_ps": "BTN_MODE",
"motion_y": null,
"motion_x": null,
Expand Down
8 changes: 4 additions & 4 deletions Nintendo Switch Left Joy-Con.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"left_analog_x": "ABS_X",
"left_analog_y": "ABS_Y",
"left_analog_y": "-ABS_Y",
"right_analog_x": "ABS_RX",
"right_analog_y": "ABS_RY",
"right_analog_y": "-ABS_RY",
"dpad_up": "BTN_DPAD_UP",
"dpad_down": "BTN_DPAD_DOWN",
"dpad_left": "BTN_DPAD_LEFT",
Expand All @@ -17,8 +17,8 @@
"button_r1": "BTN_TR",
"button_r2": "BTN_TR2",
"button_r3": "BTN_THUMBR",
"button_share": "BTN_Z",
"button_options": "BTN_SELECT",
"button_share": "BTN_SELECT",
"button_options": "BTN_START",
"button_ps": "BTN_MODE",
"motion_y": null,
"motion_x": null,
Expand Down
8 changes: 4 additions & 4 deletions Nintendo Switch Pro Controller.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"left_analog_x": "ABS_X",
"left_analog_y": "ABS_Y",
"left_analog_y": "-ABS_Y",
"right_analog_x": "ABS_RX",
"right_analog_y": "ABS_RY",
"right_analog_y": "-ABS_RY",
"dpad_up": "-ABS_HAT0Y",
"dpad_down": "ABS_HAT0Y",
"dpad_left": "-ABS_HAT0X",
Expand All @@ -17,8 +17,8 @@
"button_r1": "BTN_TR",
"button_r2": "BTN_TR2",
"button_r3": "BTN_THUMBR",
"button_share": "BTN_Z",
"button_options": "BTN_SELECT",
"button_share": "BTN_SELECT",
"button_options": "BTN_START",
"button_ps": "BTN_MODE",
"motion_y": null,
"motion_x": null,
Expand Down
8 changes: 4 additions & 4 deletions Nintendo Switch Right Joy-Con.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"left_analog_x": "ABS_X",
"left_analog_y": "ABS_Y",
"left_analog_y": "-ABS_Y",
"right_analog_x": "ABS_RX",
"right_analog_y": "ABS_RY",
"right_analog_y": "-ABS_RY",
"dpad_up": "BTN_DPAD_UP",
"dpad_down": "BTN_DPAD_DOWN",
"dpad_left": "BTN_DPAD_LEFT",
Expand All @@ -17,8 +17,8 @@
"button_r1": "BTN_TR",
"button_r2": "BTN_TR2",
"button_r3": "BTN_THUMBR",
"button_share": "BTN_Z",
"button_options": "BTN_SELECT",
"button_share": "BTN_SELECT",
"button_options": "BTN_START",
"button_ps": "BTN_MODE",
"motion_y": null,
"motion_x": null,
Expand Down
55 changes: 26 additions & 29 deletions joycond-cemuhook.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,37 +276,30 @@ def _req_ports(self, message, address):
def _req_data(self, message, address):
flags = self._compat_ord(message[24])
reg_id = self._compat_ord(message[25])
slot_id = self._compat_ord(message[21])
# reg_mac = message[26:32]

if flags == 0 and reg_id == 0: # TODO: Check MAC
if address not in self.clients:
print('[udp] Client connected: {0[0]}:{0[1]}'.format(address))

self.clients[address] = time.time()

def _handle_request(self, request):
message, address = request

# client_id = message[12:16]
msg_type = message[16:20]

if msg_type == Message.Types['version']:
return
elif msg_type == Message.Types['ports']:
self._req_ports(message, address)
elif msg_type == Message.Types['data']:
self._req_data(message, address)
else:
print('Unknown message type: ' + str(msg_type))
self.clients[address] = {
"timestamp": time.time(),
"controllers": [0,0,0,0]
}
else:
self.clients[address]["timestamp"] = time.time()
self.clients[address]["controllers"][slot_id] = 1

def _res_data(self, message):
def _res_data(self, controller_index, message):
now = time.time()
for address, timestamp in self.clients.copy().items():
if now - timestamp < 5:
self.sock.sendto(message, address)
else:
print('[udp] Client disconnected: {0[0]}:{0[1]}'.format(address))
del self.clients[address]
for address, data in self.clients.copy().items():
if data["controllers"][controller_index] == 1:
if now - data["timestamp"] < 5:
self.sock.sendto(message, address)
else:
print('[udp] Client disconnected: {0[0]}:{0[1]}'.format(address))
del self.clients[address]

def _handle_request(self, request):
message, address = request
Expand Down Expand Up @@ -362,10 +355,14 @@ def report(self, device):
buttons1 |= int(abs_to_button(device_state.get("dpad_left", 0x00))/255) << 7

buttons2 = 0x00
buttons2 |= int(abs_to_button(device_state.get("button_l2", 0x00)/255))
buttons2 |= int(abs_to_button(device_state.get("button_r2", 0x00)/255)) << 1
buttons2 |= int(abs_to_button(device_state.get("button_l1", 0x00)/255)) << 2
buttons2 |= int(abs_to_button(device_state.get("button_r1", 0x00)/255)) << 3
buttons2 |= int(abs_to_button(device_state.get("button_l2", 0x00))/255)
buttons2 |= int(abs_to_button(device_state.get("button_r2", 0x00))/255) << 1
buttons2 |= int(abs_to_button(device_state.get("button_l1", 0x00))/255) << 2
buttons2 |= int(abs_to_button(device_state.get("button_r1", 0x00))/255) << 3
buttons2 |= int(abs_to_button(device_state.get("button_triangle", 0x00))/255) << 4
buttons2 |= int(abs_to_button(device_state.get("button_circle", 0x00))/255) << 5
buttons2 |= int(abs_to_button(device_state.get("button_cross", 0x00))/255) << 6
buttons2 |= int(abs_to_button(device_state.get("button_square", 0x00))/255) << 7

data.extend([
buttons1,
Expand Down Expand Up @@ -443,7 +440,7 @@ def report(self, device):
for sensor in sensors:
data.extend(struct.pack('<f', float(sensor)))

self._res_data(bytes(Message('data', data)))
self._res_data(i, bytes(Message('data', data)))

def report_clean(self, device):
i = self.slots.index(device) if device in self.slots else -1
Expand All @@ -458,7 +455,7 @@ def report_clean(self, device):
0x00, # ?
]

self._res_data(bytes(Message('data', data)))
self._res_data(i, bytes(Message('data', data)))

def handle_devices(self):
asyncio.set_event_loop(asyncio.new_event_loop())
Expand Down

1 comment on commit e51f79c

@joaorb64
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I could understand, even though the protocol supports up to 4 controllers per server, all emulators create a client for each emulated controller. Because of this, I had to get which controller each client was asking for via the id they requested in the request message.

Please sign in to comment.