Pre-bevy minigame commit
This commit is contained in:
19
joystick/Cargo.toml
Normal file
19
joystick/Cargo.toml
Normal 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
28
joystick/src/error.rs
Normal 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
157
joystick/src/joystick.rs
Normal 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
120
joystick/src/main.rs
Normal 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()?;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user