Pre-bevy minigame commit

This commit is contained in:
2026-02-10 12:32:01 +01:00
commit 498d0b1ba8
14 changed files with 1316 additions and 0 deletions

19
joystick/Cargo.toml Normal file
View File

@@ -0,0 +1,19 @@
[package]
name = "g13-joystick"
version.workspace = true
edition.workspace = true
[dependencies]
g13-driver.workspace = true
input-linux = "0.7.1"
embedded-graphics = "0.8.1"
time = { version = "0.3.47", features = ["formatting", "macros"] }
tokio = { version = "1.49.0", features = [
"rt",
"rt-multi-thread",
"sync",
"macros",
"net",
"signal",
"time",
] }

28
joystick/src/error.rs Normal file
View File

@@ -0,0 +1,28 @@
use std::{error, fmt, io};
#[derive(Debug)]
pub enum Error {
IoError(io::Error),
OutOfRangeError { min: i32, max: i32, actual: i32 },
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self {
Error::IoError(io_error) => write!(f, "IoError: {}", io_error),
Error::OutOfRangeError { min, max, actual } => write!(
f,
"OutOfRangeError: min: {}, max: {}, actual: {}",
min, max, actual
),
}
}
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Self {
Error::IoError(e)
}
}
impl error::Error for Error {}

157
joystick/src/joystick.rs Normal file
View File

@@ -0,0 +1,157 @@
// gracefully stolen from https://github.com/gwilymk/arduino-joystick/tree/master/joystick-daemon/src/joystick <3
pub use crate::error::Error;
use g13_driver::joystick::{Axis, Button};
use input_linux::sys;
use std::{fs, sync::Arc};
#[derive(Clone)]
pub struct Joystick {
device: Arc<input_linux::UInputHandle<fs::File>>,
}
impl Joystick {
pub fn new(name: &str) -> Result<Self, Error> {
let device = create_joystick_device(name)?;
Ok(Joystick {
device: Arc::new(device),
})
}
pub fn move_axis(&self, axis: Axis, position: i32) -> Result<(), Error> {
if !(-512..=512).contains(&position) {
return Err(Error::OutOfRangeError {
min: -512,
max: 512,
actual: position,
});
}
self.write_event(input_linux::AbsoluteEvent::new(
empty_event_time(),
to_evdev_axis(axis),
position,
))
}
pub fn button_press(&self, button: Button, is_pressed: bool) -> Result<(), Error> {
let value = if is_pressed {
input_linux::KeyState::PRESSED
} else {
input_linux::KeyState::RELEASED
};
self.write_event(input_linux::KeyEvent::new(
empty_event_time(),
to_evdev_button(button),
value,
))
}
pub fn synchronise(&self) -> Result<(), Error> {
self.write_event(input_linux::SynchronizeEvent::report(empty_event_time()))
}
fn write_event(&self, event: impl std::convert::AsRef<sys::input_event>) -> Result<(), Error> {
self.device.write(&[*event.as_ref()])?;
Ok(())
}
}
fn empty_event_time() -> input_linux::EventTime {
input_linux::EventTime::new(0, 0)
}
fn create_joystick_device(name: &str) -> Result<input_linux::UInputHandle<fs::File>, Error> {
let uinput_file = fs::File::create("/dev/uinput")?;
let device = input_linux::UInputHandle::new(uinput_file);
let input_id = input_linux::InputId {
bustype: sys::BUS_VIRTUAL,
vendor: 34,
product: 10,
version: 1,
};
let standard_info = input_linux::AbsoluteInfo {
value: 0,
minimum: -512,
maximum: 512,
fuzz: 0,
flat: 0,
resolution: 50,
};
device.set_evbit(input_linux::EventKind::Absolute)?;
device.set_evbit(input_linux::EventKind::Key)?;
device.set_keybit(input_linux::Key::ButtonTrigger)?;
for button in Button::all_buttons() {
device.set_keybit(to_evdev_button(*button))?;
}
device.create(
&input_id,
name.as_bytes(),
0,
&Axis::all_axes()
.map(|axis| input_linux::AbsoluteInfoSetup {
axis: to_evdev_axis(*axis),
info: standard_info,
})
.collect::<Vec<_>>(),
)?;
Ok(device)
}
fn to_evdev_axis(axis: Axis) -> input_linux::AbsoluteAxis {
match axis {
Axis::X => input_linux::AbsoluteAxis::RX,
Axis::Y => input_linux::AbsoluteAxis::RY,
}
}
fn to_evdev_button(button: Button) -> input_linux::Key {
match button {
Button::Action => input_linux::Key::ButtonBack,
Button::Screen1 => input_linux::Key::Button0,
Button::Screen2 => input_linux::Key::Button1,
Button::Screen3 => input_linux::Key::Button2,
Button::Screen4 => input_linux::Key::Button3,
Button::Light => input_linux::Key::Button4,
Button::M1 => input_linux::Key::Button5,
Button::M2 => input_linux::Key::Button6,
Button::M3 => input_linux::Key::Button7,
Button::MR => input_linux::Key::Button8,
Button::G1 => input_linux::Key::Button9,
Button::G2 => input_linux::Key::Unknown10A,
Button::G3 => input_linux::Key::Unknown10B,
Button::G4 => input_linux::Key::Unknown10C,
Button::G5 => input_linux::Key::Unknown10D,
Button::G6 => input_linux::Key::Unknown10E,
Button::G7 => input_linux::Key::Unknown10F,
Button::G8 => input_linux::Key::Unknown118,
Button::G9 => input_linux::Key::Unknown119,
Button::G10 => input_linux::Key::Unknown11A,
Button::G11 => input_linux::Key::Unknown11B,
Button::G12 => input_linux::Key::Unknown11C,
Button::G13 => input_linux::Key::Unknown11D,
Button::G14 => input_linux::Key::Unknown11E,
Button::G15 => input_linux::Key::Unknown11F,
Button::G16 => input_linux::Key::Unknown12C,
Button::G17 => input_linux::Key::Unknown12D,
Button::G18 => input_linux::Key::Unknown12E,
Button::G19 => input_linux::Key::Unknown13F,
Button::G20 => input_linux::Key::Unknown152,
Button::G21 => input_linux::Key::Unknown153,
Button::G22 => input_linux::Key::Unknown154,
Button::Stick1 => input_linux::Key::Unknown155,
Button::Stick2 => input_linux::Key::Unknown156,
Button::Stick3 => input_linux::Key::Unknown157,
}
}

120
joystick/src/main.rs Normal file
View File

@@ -0,0 +1,120 @@
mod error;
mod joystick;
use std::time::Duration;
use embedded_graphics::{
mono_font::{MonoTextStyle, ascii::*},
pixelcolor::BinaryColor,
prelude::*,
text::{Alignment, Text, TextStyleBuilder},
};
use time::{OffsetDateTime, macros::offset};
use tokio::time::Instant;
use g13_driver::{
G13, G13_LCD_COLUMNS, G13_LCD_ROWS,
joystick::{Axis, Button},
};
use crate::joystick::Joystick;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let g13 = G13::new()?;
let joystick = Joystick::new("g13-joystick")?;
g13.set_lcd_color(4, 8, 96)?;
let mut _g13 = g13.clone();
tokio::spawn(async move {
let character_style = MonoTextStyle::new(&FONT_10X20, BinaryColor::On);
let textstyle = TextStyleBuilder::new()
.alignment(Alignment::Center)
.baseline(embedded_graphics::text::Baseline::Middle)
.build();
loop {
let start = Instant::now();
let now = OffsetDateTime::now_utc().to_offset(offset!(+1)); // GMT+1
// Render
let string = format!(
"{:0>2}:{:0>2}:{:0>2}",
now.hour(),
now.minute(),
now.second()
);
_g13.clear(BinaryColor::Off).unwrap();
Text::with_text_style(
&string,
Point::new(
(G13_LCD_COLUMNS as f64 / 2.0) as i32,
(G13_LCD_ROWS as f64 / 2.0) as i32,
),
character_style,
textstyle,
)
.draw(&mut _g13)
.unwrap();
_g13.render().unwrap();
// Calculate delta time
let delta = Instant::now() - start;
tokio::time::sleep(Duration::from_millis(33) - delta).await;
}
});
loop {
let state = g13.read()?;
joystick.move_axis(Axis::X, state.x)?;
joystick.move_axis(Axis::Y, state.y)?;
joystick.button_press(Button::Action, state.buttons.action)?;
joystick.button_press(Button::Screen1, state.buttons.screen1)?;
joystick.button_press(Button::Screen2, state.buttons.screen2)?;
joystick.button_press(Button::Screen3, state.buttons.screen3)?;
joystick.button_press(Button::Screen4, state.buttons.screen4)?;
joystick.button_press(Button::Light, state.buttons.light)?;
joystick.button_press(Button::M1, state.buttons.m1)?;
joystick.button_press(Button::M2, state.buttons.m2)?;
joystick.button_press(Button::M3, state.buttons.m3)?;
joystick.button_press(Button::MR, state.buttons.mr)?;
joystick.button_press(Button::G1, state.buttons.g1)?;
joystick.button_press(Button::G2, state.buttons.g2)?;
joystick.button_press(Button::G3, state.buttons.g3)?;
joystick.button_press(Button::G4, state.buttons.g4)?;
joystick.button_press(Button::G5, state.buttons.g5)?;
joystick.button_press(Button::G6, state.buttons.g6)?;
joystick.button_press(Button::G7, state.buttons.g7)?;
joystick.button_press(Button::G8, state.buttons.g8)?;
joystick.button_press(Button::G9, state.buttons.g9)?;
joystick.button_press(Button::G10, state.buttons.g10)?;
joystick.button_press(Button::G11, state.buttons.g11)?;
joystick.button_press(Button::G12, state.buttons.g12)?;
joystick.button_press(Button::G13, state.buttons.g13)?;
joystick.button_press(Button::G14, state.buttons.g14)?;
joystick.button_press(Button::G15, state.buttons.g15)?;
joystick.button_press(Button::G16, state.buttons.g16)?;
joystick.button_press(Button::G17, state.buttons.g17)?;
joystick.button_press(Button::G18, state.buttons.g18)?;
joystick.button_press(Button::G19, state.buttons.g19)?;
joystick.button_press(Button::G20, state.buttons.g20)?;
joystick.button_press(Button::G21, state.buttons.g21)?;
joystick.button_press(Button::G22, state.buttons.g22)?;
joystick.button_press(Button::Stick1, state.buttons.stick1)?;
joystick.button_press(Button::Stick2, state.buttons.stick2)?;
joystick.button_press(Button::Stick3, state.buttons.stick3)?;
joystick.synchronise()?;
}
}