#hid #bluetooth #gamedev #send-receive #joycon #nintendo-switch

bin+lib joycon-rs

a framework for dealing with Nintendo Switch Joy-Con on Rust easily and efficiently

17 releases

0.6.3 Dec 5, 2021
0.6.1 Jun 6, 2020
0.5.6 Jun 5, 2020
0.5.3 May 31, 2020
0.1.1 Apr 16, 2020

#315 in Game dev

Apache-2.0

125KB
2.5K SLoC


Joycon-rs

Documentation| Examples| Changelog| ドキュメント

A framework for dealing with Nintendo Switch Joy-Con on Rust easily and efficiently via Bluetooth.

Joycon-rs provides utility to find communicate with, and operate Joy-Con. Please see the documentation comments for detailed instructions on how to use it.

Joycon-rs is in development and is still incomplete. Please be aware the update will include breaking changes for the time being. Pardon out dust!

Setup

On macOS or Windows, there are no preparation.

On linux,

$ sudo apt-get install libudev-dev libusb-1.0-0-dev libfox-1.6-dev

Usage

First, add dependency to Cargo.toml

[dependencies]
joycon_rs = "*"

Then, use prelude on .rs file.

use joycon_rs::prelude::*;

Perfect! Now you have Joycon-rs available in code.

Receive reports

For starters, let's take a simple signal from JoyCon. If you use more than one JoyCon, mspc can be very helpful.

use joycon_rs::prelude::*;

let (tx, rx) = std::sync::mpsc::channel();

let _output = std::thread::spawn(move || {
    // Push buttons or tilt the stick please.
    // Stop with `Cmd + C` or `Ctrl + C`
    while let Ok(message) = rx.recv() {
        dbg!(message);
    }
});

let manager = JoyConManager::get_instance();
let (managed_devices, new_devices) = {
let lock = manager.lock();
    match lock {
        Ok(m) => (m.managed_devices(),m.new_devices()),
        Err(_) => unreachable!()
    }
};

managed_devices.into_iter()
    .chain(new_devices)
    .flat_map(|dev| SimpleJoyConDriver::new(&dev))
    .try_for_each::<_, JoyConResult<()>>(|driver| {
        // Change JoyCon to Simple hid mode.
        let simple_hid_mode = SimpleHIDMode::new(driver)?;
    
        let tx = tx.clone();
    
        // Spawn thread
        std::thread::spawn( move || {
            loop {
                // Forward the report to the main thread
                tx.send(simple_hid_mode.read_input_report()).unwrap();
            }
        });
    
        Ok(())
    })
    .unwrap();

Set player lights

Then, lets deal with player lights.

use joycon_rs::prelude::{*, lights::*};

let (tx, rx) = std::sync::mpsc::channel();

let _output = std::thread::spawn(move || {
    // Stop with `Cmd + C` or `Ctrl + C`
    while let Ok(message) = rx.recv() {
        dbg!(message);
    }
});

let manager = JoyConManager::get_instance();
let (managed_devices, new_devices) = {
let lock = manager.lock();
    match lock {
        Ok(m) => (m.managed_devices(),m.new_devices()),
        Err(_) => unreachable!()
    }
};

managed_devices.into_iter()
    .chain(new_devices)
    .flat_map(|dev| SimpleJoyConDriver::new(&dev))
    .try_for_each::<_, JoyConResult<()>>(|mut driver| {
        // Set player lights
        // [SL BUTTON] 📸💡📸💡 [SR BUTTON]
        driver.set_player_lights(&vec![LightUp::LED1, LightUp::LED3], &vec![Flash::LED0, Flash::LED2]).unwrap();
        tx.send(driver.get_player_lights()).unwrap();
        Ok(())
    })
    .unwrap();

Rumble

use joycon_rs::prelude::*;
use std::convert::TryInto;
use std::ops::Deref;
use joycon_rs::joycon::joycon_features::JoyConFeature;

fn main() -> JoyConResult<()> {
    // First, connect your Joy-Cons to your computer!

    let manager = JoyConManager::get_instance();
    let (managed_devices, new_devices) = {
        let lock = manager.lock();
        match lock {
            Ok(manager) =>
                (manager.managed_devices(), manager.new_devices()),
            Err(_) => unreachable!(),
        }
    };

    managed_devices.into_iter()
        .chain(new_devices)
        .inspect(|d| {
            let lock = d.lock();
            let device = match lock {
                Ok(device) => device,
                Err(e) => e.into_inner(),
            };
            let hid_device: JoyConResult<&HidDevice> = device.deref().try_into();
            if let Ok(hid_device) = hid_device {
                println!("{:?}", hid_device.get_product_string())
            }
        })
        .try_for_each::<_, JoyConResult<()>>(|d| {
            let mut driver = SimpleJoyConDriver::new(&d)?;

            driver.enable_feature(JoyConFeature::Vibration)?;

            // let rumble = Rumble::new(80.0,0.2);
            let rumble = Rumble::new(300.0,0.9);
            driver.rumble((Some(rumble), Some(rumble)))?;

            Ok(())
        })?;

    Ok(())
}

More Examples

Here.

Features

You can use Joycon-rs for...

Planning

  • Receive NFC/IR data
  • Deal with Pro Controller

License

Licensed under Apache License, Version 2.0 (LICENSE or http://www.apache.org/licenses/LICENSE-2.0)

Contribution

We gladly accept contributions via GitHub pull requests. If you find a bug in the library, it would be appreciated if you could report it in detail to Issues so that it can be reproduced.

Dependencies

~0.7–1.4MB
~26K SLoC