DEV Community

Sofia Winters
Sofia Winters

Posted on

joyshop, a small shortcut launcher for JoyCon

Release of joyshop

joyshop

I've just released SofiaWinters/joyshop, a small shortcut launcher for JoyCon on Windows 10. With this app, I use JoyCon as a left-handed shortcut launcher for PhotoShop.

This is my first Rust project, and I met some obstacles and great crates.

Lack of GUI libraries

For Rust, some GUI libraries work on Windows, including Iced, Azul, native-windows-gui, and Conrod. They have a lot of functionality and flexibility. However, I'd like to make a transparent layered window as a tooltip, so I decided to call Win32API directly.

Thanks to the winapi crate, writing GUI code in Rust is very similar to C. (My code to create window is joyshop/window.rs)

This is just a tip; I needed to put #![windows_subsystem = "windows"] in main.rs to hide a command prompt window.

Building GUI with Win32API is unfamiliar to me. Everything was tough but worked. Next, I want to find a way to use a resource file to build GUI.

Issue of mpsc::channel

I got panic when I call mpsc::channel's recv method. It should relate to Panic in Receiver::recv() · Issue #39364 · rust-lang/rust.

I just switched to the crossbeam-rs/crossbeam because I couldn't find a solution or workaround.

Great KaiseiYokoyama/joycon-rs crate

joycon-rs is a crate that can get inputs from JoyCon and control lights and vibration.

I've tried to make the same application before with C#, but there are no stable libraries that meet my requirements. On the other hand, Rust has joycon-rs, which is stable and easy to use.

There is one pitfall to use. The example doesn't work correctly especially using multiple controllers.

All the examples have codes like this.

new_devices
    .into_iter()
    .flat_map(|dev| SimpleJoyConDriver::new(&dev))
    .for_each(...);
Enter fullscreen mode Exit fullscreen mode

It looks like it works for multiple controllers, but doesn't. Because flat_map discards drivers that failed to be initialized. And often contiguous initialization for multiple controllers fails.

Thus, we have to handle the initialization error like this.

new_devices
    .into_iter()
    .for_each(|dev| {
        let driver = create_driver(&dev);
        ...
    });

fn create_driver(device: &Arc<Mutex<JoyConDevice>>) -> SimpleJoyConDriver {
    loop {
        match SimpleJoyConDriver::new(device) {
            Ok(d) => return d,
            Err(e) => {
                println!("JoyCon init error (will retry):{:?}", e);
                sleep(std::time::Duration::from_millis(100));
                continue;
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Discussion (0)