Skip to content

benmaidel/joy_bridge

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

joy_bridge

Bridge a dev joy device from host to client.

A Python package for bridging joystick/gamepad devices between host and client systems over a network connection. This allows you to use a joystick connected to one computer to control applications on another computer.

Features

  • Cross-platform support: Works on Windows, macOS, and Linux
  • Automatic OS detection: Single joy-sender command automatically uses the right implementation for your platform
  • Multiple sender variants: Auto-detecting sender, Linux evdev sender, and macOS/Windows pygame sender
  • Controller configuration support: Pre-configured mappings for Xbox, PlayStation, Logitech F710, and custom YAML configs
  • Real-time data transmission: Low-latency joystick data streaming
  • Configurable update rates: Customize transmission frequency
  • Extensible receiver: Add custom callbacks for data processing
  • Statistics and monitoring: Built-in packet rate monitoring

Installation

Install the package using pip:

pip install joy_bridge

On Linux, the receiver now uses the official evdev module by default. Install with Linux extras to get evdev support:

pip install joy_bridge[linux]

Or install from source:

git clone https://github.com/benmaidel/joy_bridge.git
cd joy_bridge
pip install .
# On Linux, for evdev support (recommended for receiver):
pip install .[linux]

Dependencies

  • Python 3.7+
  • pygame >= 2.0.0
  • pyyaml >= 5.1 (for controller configuration files)
  • evdev >= 1.0.0 (Linux only, required for receiver by default, also used for evdev-based sender)

Usage

Quick Start

  1. Start the receiver on the target computer:

    joy-receiver --host 0.0.0.0 --port 8080
  2. Start the sender on the computer with the joystick:

    joy-sender --host <receiver_ip> --port 8080

    The joy-sender command uses pygame-based sender for all platforms:

    • On Linux: Uses pygame-based sender (requires pygame package)
    • On macOS: Uses pygame-based sender (requires pygame package)
    • On Windows: Uses pygame-based sender (requires pygame package)

    If you don't specify --index, an interactive menu will appear to let you select which joystick to use.

  3. Alternative: Linux evdev-based sender

    You can also use the evdev-based sender on Linux:

    # Linux with evdev (legacy/alternative)
    joy-sender-linux --device /dev/input/event0 --host <receiver_ip> --port 8080

Command Line Options

joy-sender (unified pygame-based)

joy-sender --host HOST [--port PORT] [--index INDEX] [--rate-limit RATE_LIMIT] [--config CONFIG] [--list-configs]

The command uses pygame for all platforms. If --index is not specified, an interactive menu is shown to select the joystick.

Options:

  • --host: Target host IP address (required)
  • --port: Target port number (default: 50000)
  • --index: Joystick index to use (optional, shows menu if not specified)
  • --rate-limit: Optional sleep seconds per packet (default: 0.0)
  • --config: Controller config name or path (e.g., 'xbox_one', 'playstation', '/path/to/config.yaml')
  • --list-configs: List available built-in controller configurations

joy-sender-linux

#### joy-sender-linux (legacy evdev-based)
```bash
joy-sender-linux --device DEVICE --host HOST [--port PORT] [--rate-limit RATE_LIMIT]
  • --device: Linux input device path (e.g., /dev/input/event0)
  • --host: Target host IP address (required)
  • --port: Target port number (default: 50000)
  • --rate-limit: Optional sleep seconds per packet (default: 0.0)

joy-receiver

joy-receiver [--bind BIND] [--port PORT] [--no-stats] [--syn-interval SYN_INTERVAL] [--print-values] [--idle-timeout IDLE_TIMEOUT] [--use-custom]
  • --bind: Host address to bind to (default: 0.0.0.0)
  • --port: Port to listen on (default: 50000)
  • --no-stats: Disable periodic statistics output
  • --syn-interval: Auto synchronization interval in seconds (default: 0.1)
  • --print-values: Print received joystick values (useful for debugging)
  • --idle-timeout: Time in seconds before detecting connection as closed (default: 5.0)
  • --use-custom: Use custom uinput implementation instead of official evdev module (default: use evdev)

UInput Implementation

The receiver supports two implementations for creating virtual input devices:

  1. Official evdev Module (default): Uses the python-evdev library for robust and well-tested uinput device creation
  2. Custom Implementation: A pure Python implementation that doesn't require external dependencies beyond standard Linux kernel support

Both implementations provide the same functionality and include validation to prevent EINVAL errors when unsupported events are received. The official evdev module is used by default for better reliability, but you can use the custom implementation if preferred:

# Use official evdev module (default)
joy-receiver --bind 0.0.0.0 --port 8080

# Use custom implementation
joy-receiver --bind 0.0.0.0 --port 8080 --use-custom

Note: The default configuration requires the evdev package: pip install evdev or pip install joy_bridge[linux]. If evdev is not available, you can use --use-custom to fall back to the custom implementation.

Controller Configuration

joy_bridge supports different controllers through configurable button and axis mappings. Built-in configurations are provided for popular controllers:

Built-in Configurations

  • xbox_one - Xbox One controller (standard layout)
  • playstation - PlayStation DualShock 4 / DualSense controllers
  • logitech_f710 - Logitech F710 wireless gamepad (XInput mode)
  • default - Generic controller with sequential mapping

Using Controller Configs

# List available configurations
joy-sender --list-configs

# Use a specific built-in config
joy-sender --host 192.168.1.100 --config xbox_one

# Use a custom config file
joy-sender --host 192.168.1.100 --config /path/to/my_controller.yaml

# Without config (uses default sequential mapping)
joy-sender --host 192.168.1.100

Creating Custom Configurations

Create a YAML file with button and axis mappings:

name: "My Custom Controller"
description: "Custom button/axis mapping"

# Button mappings: pygame index -> Linux button code
buttons:
  0: 0x130  # BTN_SOUTH (A/Cross)
  1: 0x131  # BTN_EAST (B/Circle)
  # ... more buttons

# Axis mappings: pygame index -> Linux axis code with type
axes:
  0:
    code: 0x00  # ABS_X (Left stick X)
    type: stick
    min: -32768
    max: 32767
  2:
    code: 0x02  # ABS_Z (Left trigger)
    type: trigger
    min: 0
    max: 32767
  # ... more axes

# Hat mappings: pygame index -> Linux hat codes
hats:
  0:
    x_code: 0x10  # ABS_HAT0X (D-pad X)
    y_code: 0x11  # ABS_HAT0Y (D-pad Y)
    min: -1
    max: 1

See joy_bridge/configs/README.md for detailed documentation on the configuration format and available Linux input event codes.

Programming Interface

You can also use the modules programmatically:

from joy_bridge import joy_sender, joy_receiver

# Create and configure a sender
sender = joy_sender.JoySender("192.168.1.100", 8080)
sender.connect()
sender.run(update_rate=30.0)

# Create and configure a receiver
receiver = joy_receiver.JoyReceiver("0.0.0.0", 8080)

# Add custom data processing callback
def my_callback(data):
    print(f"Received joystick data: {data}")

receiver.add_data_callback(my_callback)
receiver.run()

Data Format

The joystick data is transmitted over UDP with the following packet formats:

Packet Structure

All packets include a CRC32 checksum for data integrity verification:

  • CAP (Capability) Packet: CAP <json> <checksum>

    • Sent once at connection to describe the controller capabilities
    • Example: CAP {"caps":{"1":[304,305]},"ident":{"name":"Controller"}} 3664426552
  • EVT (Event) Packet: EVT <json> <checksum>

    • Sent for each joystick event (button press, axis movement, etc.)
    • Example: EVT {"sec":123,"usec":456,"type":3,"code":0,"value":100} 2405047441
  • EXIT Packet: EXIT

    • Sent when sender disconnects
    • Does not include a checksum (simple signal message)

Event Data Structure

The JSON payload in EVT packets contains:

{
    "sec": 1642123456,
    "usec": 789000,
    "type": 3,
    "code": 0,
    "value": 12345
}

Checksum

  • Uses CRC32 algorithm for fast and reliable error detection
  • Checksum is calculated on the JSON payload only
  • Receiver validates checksum and drops packets with invalid checksums
  • Provides protection against UDP transmission errors

Network Configuration

For network usage across different computers:

  1. Ensure the receiver host allows incoming connections on the specified port
  2. Configure firewall rules if necessary
  3. Use 0.0.0.0 as the host for the receiver to accept connections from any IP
  4. Replace localhost with the actual IP address of the receiver computer

Troubleshooting

  • No joysticks found: Ensure a joystick/gamepad is connected and recognized by the system
  • Connection refused: Check that the receiver is running and the port is not blocked
  • High latency: Try reducing the update rate or check network connectivity
  • Missing dependencies: If joy-sender fails, ensure pygame is installed: pip install pygame
  • Config file errors: If using --config, ensure PyYAML is installed: pip install pyyaml
  • Wrong button mappings: Try using a specific controller config with --config xbox_one or --config playstation
  • Receiver requires evdev: The receiver uses the evdev package by default on Linux: pip install evdev or pip install joy_bridge[linux]. If evdev is unavailable, use --use-custom to use the custom implementation.
  • Alternative sender: If you need lower-level access on Linux, use joy-sender-linux with evdev
  • Multiple joysticks: If you have multiple joysticks connected, joy-sender will show an interactive menu to select which one to use

License

MIT License - see LICENSE file for details.

About

Bridge a dev joy device from host to client

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages