OSC control bug

import tkinter as tk
from threading import Thread
from inputs import get_gamepad
from pythonosc.udp_client import SimpleUDPClient

OSC targets

osc_targets = [
SimpleUDPClient(“127.0.0.1”, 9000),
SimpleUDPClient(“127.0.0.1”, 9002),
SimpleUDPClient(“127.0.0.1”, 9004)
]

Configurable settings

DEAD_ZONE = 50
INVERT_LOOK_Y = True
INVERT_LOOK_X = False
INVERT_MOVE_Y = True

Button state tracking

button_states = {
“BTN_SOUTH”: 0,
“BTN_EAST”: 0,
“ABS_Y”: 128,
“ABS_X”: 128,
“ABS_RY”: 128,
“ABS_RX”: 128
}

def send_osc_to_all(address, value):
for client in osc_targets:
client.send_message(address, value)

def controller_loop(log_callback):
while True:
events = get_gamepad()
for event in events:
code = event.code
state = event.state

        # Jump
        if code == "BTN_SOUTH":
            if state != button_states[code]:
                send_osc_to_all("/input/Jump", state)
                log_callback(f"Jump: {state}")
                button_states[code] = state

        # Crouch
        elif code == "BTN_EAST":
            if state != button_states[code]:
                send_osc_to_all("/input/Crouch", state)
                log_callback(f"Crouch: {state}")
                button_states[code] = state

        # Movement - Forward/Backward
        elif code == "ABS_Y":
            forward = backward = 0
            if INVERT_MOVE_Y:
                if state > (128 + DEAD_ZONE):
                    forward = 1
                elif state < (128 - DEAD_ZONE):
                    backward = 1
            else:
                if state < (128 - DEAD_ZONE):
                    forward = 1
                elif state > (128 + DEAD_ZONE):
                    backward = 1

            send_osc_to_all("/input/MoveForward", forward)
            send_osc_to_all("/input/MoveBackward", backward)
            log_callback(f"Forward: {forward}, Backward: {backward}")
            button_states[code] = state

        # Movement - Left/Right
        elif code == "ABS_X":
            left = right = 0
            if state < (128 - DEAD_ZONE):
                left = 1
            elif state > (128 + DEAD_ZONE):
                right = 1

            send_osc_to_all("/input/MoveLeft", left)
            send_osc_to_all("/input/MoveRight", right)
            log_callback(f"Left: {left}, Right: {right}")
            button_states[code] = state

        # Look - Up/Down
        elif code == "ABS_RY":
            look_up = look_down = 0
            if INVERT_LOOK_Y:
                if state > (128 + DEAD_ZONE):
                    look_up = 1
                elif state < (128 - DEAD_ZONE):
                    look_down = 1
            else:
                if state < (128 - DEAD_ZONE):
                    look_up = 1
                elif state > (128 + DEAD_ZONE):
                    look_down = 1

            send_osc_to_all("/input/LookUp", look_up)
            send_osc_to_all("/input/LookDown", look_down)
            log_callback(f"LookUp: {look_up}, LookDown: {look_down}")
            button_states[code] = state

        # Look - Left/Right
        elif code == "ABS_RX":
            look_left = look_right = 0
            if INVERT_LOOK_X:
                if state > (128 + DEAD_ZONE):
                    look_left = 1
                elif state < (128 - DEAD_ZONE):
                    look_right = 1
            else:
                if state < (128 - DEAD_ZONE):
                    look_left = 1
                elif state > (128 + DEAD_ZONE):
                    look_right = 1

            send_osc_to_all("/input/LookLeft", look_left)
            send_osc_to_all("/input/LookRight", look_right)
            log_callback(f"LookLeft: {look_left}, LookRight: {look_right}")
            button_states[code] = state

GUI setup

def start_gui():
root = tk.Tk()
root.title(“VRChat Controller Router”)
root.geometry(“360x220”)
root.resizable(False, False)

log_box = tk.Text(root, height=12, width=45)
log_box.pack(pady=10)

def log(msg):
    log_box.insert(tk.END, msg + "\n")
    log_box.see(tk.END)

Thread(target=controller_loop, args=(log,), daemon=True).start()
root.mainloop()

Run GUI

start_gui()