input as events

This commit is contained in:
2026-02-13 19:02:40 +01:00
parent 37d834d80b
commit 85f1154c03
4 changed files with 350 additions and 344 deletions

98
Cargo.lock generated
View File

@@ -103,6 +103,12 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "aliasable"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd"
[[package]] [[package]]
name = "aligned" name = "aligned"
version = "0.4.3" version = "0.4.3"
@@ -2376,6 +2382,19 @@ dependencies = [
"byteorder", "byteorder",
] ]
[[package]]
name = "embedded-graphics-simulator"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31606a4fb7d9d3a79a38d27bc2954cfa98682c8fea4b22c09a442785a80424e"
dependencies = [
"base64",
"embedded-graphics",
"image",
"ouroboros",
"sdl2",
]
[[package]] [[package]]
name = "encase" name = "encase"
version = "0.12.0" version = "0.12.0"
@@ -2785,6 +2804,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"ctrlc", "ctrlc",
"embedded-graphics", "embedded-graphics",
"embedded-graphics-simulator",
"g13-driver", "g13-driver",
"mlua", "mlua",
"time", "time",
@@ -3076,6 +3096,12 @@ dependencies = [
"stable_deref_trait", "stable_deref_trait",
] ]
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.5.2" version = "0.5.2"
@@ -4196,6 +4222,30 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "ouroboros"
version = "0.18.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59"
dependencies = [
"aliasable",
"ouroboros_macro",
"static_assertions",
]
[[package]]
name = "ouroboros_macro"
version = "0.18.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0"
dependencies = [
"heck",
"proc-macro2",
"proc-macro2-diagnostics",
"quote",
"syn",
]
[[package]] [[package]]
name = "owned_ttf_parser" name = "owned_ttf_parser"
version = "0.25.1" version = "0.25.1"
@@ -4426,6 +4476,19 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "proc-macro2-diagnostics"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
dependencies = [
"proc-macro2",
"quote",
"syn",
"version_check",
"yansi",
]
[[package]] [[package]]
name = "profiling" name = "profiling"
version = "1.0.17" version = "1.0.17"
@@ -4847,6 +4910,29 @@ dependencies = [
"tiny-skia", "tiny-skia",
] ]
[[package]]
name = "sdl2"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b498da7d14d1ad6c839729bd4ad6fc11d90a57583605f3b4df2cd709a9cd380"
dependencies = [
"bitflags 1.3.2",
"lazy_static",
"libc",
"sdl2-sys",
]
[[package]]
name = "sdl2-sys"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "951deab27af08ed9c6068b7b0d05a93c91f0a8eb16b6b816a5e73452a43521d3"
dependencies = [
"cfg-if",
"libc",
"version-compare",
]
[[package]] [[package]]
name = "self_cell" name = "self_cell"
version = "1.2.2" version = "1.2.2"
@@ -5549,6 +5635,12 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version-compare"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.5" version = "0.9.5"
@@ -6625,6 +6717,12 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448" checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448"
[[package]]
name = "yansi"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
[[package]] [[package]]
name = "yazi" name = "yazi"
version = "0.2.1" version = "0.2.1"

View File

@@ -1,6 +1,7 @@
pub mod joystick; pub mod joystick;
use std::{ use std::{
collections::{HashMap, hash_map::Entry},
io::{Read, Write}, io::{Read, Write},
sync::{Arc, RwLock}, sync::{Arc, RwLock},
time::Duration, time::Duration,
@@ -16,62 +17,78 @@ use nusb::{
transfer::{ControlOut, ControlType, In, Interrupt, Out, Recipient}, transfer::{ControlOut, ControlType, In, Interrupt, Out, Recipient},
}; };
use crate::joystick::Button;
pub const G13_LCD_COLUMNS: i32 = 160; pub const G13_LCD_COLUMNS: i32 = 160;
pub const G13_LCD_ROWS: i32 = 43; pub const G13_LCD_ROWS: i32 = 43;
pub const G13_LCD_BYTES_PER_ROW: i32 = G13_LCD_COLUMNS / 8; pub const G13_LCD_BYTES_PER_ROW: i32 = G13_LCD_COLUMNS / 8;
pub const G13_LCD_BUF_SIZE: i32 = (G13_LCD_ROWS + 5) * G13_LCD_BYTES_PER_ROW; pub const G13_LCD_BUF_SIZE: i32 = (G13_LCD_ROWS + 5) * G13_LCD_BYTES_PER_ROW;
const BUTTON_MAP: &[(Button, usize, u8)] = &[
// buf[6]
(Button::Action, 6, 0b00000001),
(Button::Screen1, 6, 0b00000010),
(Button::Screen2, 6, 0b00000100),
(Button::Screen3, 6, 0b00001000),
(Button::Screen4, 6, 0b00010000),
(Button::M1, 6, 0b00100000),
(Button::M2, 6, 0b01000000),
(Button::M3, 6, 0b10000000),
// buf[7]
(Button::Light, 7, 0b01000000),
(Button::MR, 7, 0b00000001),
(Button::Stick1, 7, 0b00000010),
(Button::Stick2, 7, 0b00000100),
(Button::Stick3, 7, 0b00001000),
// buf[3]
(Button::G1, 3, 0b00000001),
(Button::G2, 3, 0b00000010),
(Button::G3, 3, 0b00000100),
(Button::G4, 3, 0b00001000),
(Button::G5, 3, 0b00010000),
(Button::G6, 3, 0b00100000),
(Button::G7, 3, 0b01000000),
(Button::G8, 3, 0b10000000),
// buf[4]
(Button::G9, 4, 0b00000001),
(Button::G10, 4, 0b00000010),
(Button::G11, 4, 0b00000100),
(Button::G12, 4, 0b00001000),
(Button::G13, 4, 0b00010000),
(Button::G14, 4, 0b00100000),
(Button::G15, 4, 0b01000000),
(Button::G16, 4, 0b10000000),
// buf[5]
(Button::G17, 5, 0b00000001),
(Button::G18, 5, 0b00000010),
(Button::G19, 5, 0b00000100),
(Button::G20, 5, 0b00001000),
(Button::G21, 5, 0b00010000),
(Button::G22, 5, 0b00100000),
];
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Vec2<T>
where
T: Copy,
{
pub x: T,
pub y: T,
}
impl<T> Vec2<T>
where
T: Copy,
{
pub fn new(x: T, y: T) -> Self {
Self { x, y }
}
}
#[derive(Clone)] #[derive(Clone)]
pub struct G13 { pub struct G13 {
interface: Interface, display: G13Display,
img_buffer: Arc<RwLock<[u8; G13_LCD_BUF_SIZE as usize + 8]>>, input: G13Input,
state: Arc<RwLock<State>>,
}
#[derive(Debug, Clone, Copy, Default)]
pub struct State {
pub x: i32,
pub y: i32,
pub buttons: Buttons,
}
#[derive(Debug, Clone, Copy, Default)]
pub struct Buttons {
pub action: bool,
pub screen1: bool,
pub screen2: bool,
pub screen3: bool,
pub screen4: bool,
pub light: bool,
pub m1: bool,
pub m2: bool,
pub m3: bool,
pub mr: bool,
pub g1: bool,
pub g2: bool,
pub g3: bool,
pub g4: bool,
pub g5: bool,
pub g6: bool,
pub g7: bool,
pub g8: bool,
pub g9: bool,
pub g10: bool,
pub g11: bool,
pub g12: bool,
pub g13: bool,
pub g14: bool,
pub g15: bool,
pub g16: bool,
pub g17: bool,
pub g18: bool,
pub g19: bool,
pub g20: bool,
pub g21: bool,
pub g22: bool,
pub stick1: bool,
pub stick2: bool,
pub stick3: bool,
} }
impl G13 { impl G13 {
@@ -96,80 +113,142 @@ impl G13 {
Err(e) => return Err(format!("Unable to claim interface: {:#?}", e).into()), Err(e) => return Err(format!("Unable to claim interface: {:#?}", e).into()),
}; };
let img_buffer = [0u8; G13_LCD_BUF_SIZE as usize + 8];
let mut buffer = [0u8; G13_LCD_BUF_SIZE as usize + 32 + 8];
buffer[0] = 0x03;
buffer[32..G13_LCD_BUF_SIZE as usize + 32 + 8].copy_from_slice(&img_buffer);
let mut w = interface.endpoint::<Interrupt, Out>(0x02)?.writer(64);
w.write_all(&buffer)?;
w.flush()?;
Ok(Self { Ok(Self {
interface, input: G13Input::new(interface.clone()),
img_buffer: Arc::new(RwLock::new(img_buffer)), display: G13Display::new(interface),
state: Arc::new(RwLock::new(Default::default())),
}) })
} }
pub fn state(&self) -> State { pub fn split(self) -> (G13Display, G13Input) {
*self.state.read().expect("Poisoned") (self.display, self.input)
}
}
#[derive(Debug)]
pub enum G13Event {
Axis(u8, u8),
Button(Button, (bool, bool)), // (old, new)
}
#[derive(Clone)]
pub struct G13Input {
interface: Interface,
buttons: HashMap<Button, bool>,
axis: Vec2<u8>,
calibrated_axis: (Vec2<u8>, Vec2<u8>), // this needs to be saved/loaded
calibrating: bool,
}
impl G13Input {
pub fn new(interface: Interface) -> Self {
Self {
interface,
buttons: HashMap::new(),
axis: Default::default(),
calibrated_axis: (Vec2::new(127, 127), Vec2::new(127, 127)),
calibrating: false,
}
}
pub fn calibrate(mut self) -> Self {
self.calibrating = true;
self
} }
pub fn read(&self) -> Result<State, Box<dyn std::error::Error>> { pub fn with_calibration_axis(mut self, min: Vec2<u8>, max: Vec2<u8>) -> Self {
let mut state = self.state(); self.calibrated_axis.0 = min;
self.calibrated_axis.1 = max;
self.calibrating = false;
self
}
let mut reader = self.interface.endpoint::<Interrupt, In>(0x81)?.reader(8); pub fn get_calibration_axis(&self) -> (Vec2<u8>, Vec2<u8>) {
self.calibrated_axis
}
fn handle_button(&mut self, button: Button, value: bool) -> Option<G13Event> {
if let Entry::Vacant(e) = self.buttons.entry(button) {
e.insert(value);
if value {
return Some(G13Event::Button(button, (!value, value)));
}
}
let prev = self.buttons[&button];
if self.buttons[&button] == value {
return None;
}
self.buttons.insert(button, value);
Some(G13Event::Button(button, (prev, value)))
}
}
impl Iterator for G13Input {
type Item = Option<G13Event>;
fn next(&mut self) -> Option<Self::Item> {
let mut reader = self
.interface
.endpoint::<Interrupt, In>(0x81)
.ok()?
.reader(8);
let mut buf = [0; 8]; let mut buf = [0; 8];
reader.read_exact(&mut buf)?; reader.read_exact(&mut buf).ok()?;
state.x = (((buf[1] as f64) / 256.0 * 1024.0) - 512.0) as i32; for &(button, index, mask) in BUTTON_MAP {
state.y = (((buf[2] as f64) / 256.0 * 1024.0) - 512.0) as i32; if let Some(event) = self.handle_button(button, buf[index] & mask != 0) {
self.calibrating = false;
return Some(Some(event));
}
}
state.buttons.action = buf[6] & 0b00000001 != 0; let axis = Vec2::new(buf[1], buf[2]);
state.buttons.screen1 = buf[6] & 0b00000010 != 0;
state.buttons.screen2 = buf[6] & 0b00000100 != 0;
state.buttons.screen3 = buf[6] & 0b00001000 != 0;
state.buttons.screen4 = buf[6] & 0b00010000 != 0;
state.buttons.light = buf[7] & 0b0100000 != 0;
state.buttons.m1 = buf[6] & 0b00100000 != 0; if self.axis == axis {
state.buttons.m2 = buf[6] & 0b01000000 != 0; return Some(None);
state.buttons.m3 = buf[6] & 0b10000000 != 0; }
state.buttons.mr = buf[7] & 0b00000001 != 0;
state.buttons.g1 = buf[3] & 0b00000001 != 0; self.axis = axis;
state.buttons.g2 = buf[3] & 0b00000010 != 0;
state.buttons.g3 = buf[3] & 0b00000100 != 0;
state.buttons.g4 = buf[3] & 0b00001000 != 0;
state.buttons.g5 = buf[3] & 0b00010000 != 0;
state.buttons.g6 = buf[3] & 0b00100000 != 0;
state.buttons.g7 = buf[3] & 0b01000000 != 0;
state.buttons.g8 = buf[3] & 0b10000000 != 0;
state.buttons.g9 = buf[4] & 0b00000001 != 0; self.calibrated_axis.0.x = self.calibrated_axis.0.x.min(axis.x);
state.buttons.g10 = buf[4] & 0b00000010 != 0; self.calibrated_axis.1.x = self.calibrated_axis.1.x.max(axis.x);
state.buttons.g11 = buf[4] & 0b00000100 != 0; self.calibrated_axis.0.y = self.calibrated_axis.0.y.min(axis.y);
state.buttons.g12 = buf[4] & 0b00001000 != 0; self.calibrated_axis.1.y = self.calibrated_axis.1.y.max(axis.y);
state.buttons.g13 = buf[4] & 0b00010000 != 0;
state.buttons.g14 = buf[4] & 0b00100000 != 0;
state.buttons.g15 = buf[4] & 0b01000000 != 0;
state.buttons.g16 = buf[4] & 0b10000000 != 0;
state.buttons.g17 = buf[5] & 0b00000001 != 0; let (xmin, xmax) = (self.calibrated_axis.0.x, self.calibrated_axis.1.x);
state.buttons.g18 = buf[5] & 0b00000010 != 0; let (ymin, ymax) = (self.calibrated_axis.0.y, self.calibrated_axis.1.y);
state.buttons.g19 = buf[5] & 0b00000100 != 0;
state.buttons.g20 = buf[5] & 0b00001000 != 0;
state.buttons.g21 = buf[5] & 0b00010000 != 0;
state.buttons.g22 = buf[5] & 0b00100000 != 0;
state.buttons.stick1 = buf[7] & 0b00000010 != 0; let x_output = map_range(self.axis.x, xmin, xmax);
state.buttons.stick2 = buf[7] & 0b00000100 != 0; let y_output = map_range(self.axis.y, ymin, ymax);
state.buttons.stick3 = buf[7] & 0b00001000 != 0;
*self.state.write().expect("Poisoned") = state; Some(Some(G13Event::Axis(x_output as u8, y_output as u8)))
}
}
Ok(state) fn map_range(v: u8, in_min: u8, in_max: u8) -> f64 {
if in_min == in_max {
return 0.0;
}
255.0 * (v as f64 - in_min as f64) / (in_max as f64 - in_min as f64)
}
#[derive(Clone)]
pub struct G13Display {
interface: Interface,
img_buffer: Arc<RwLock<[u8; G13_LCD_BUF_SIZE as usize + 8]>>,
}
impl G13Display {
pub fn new(interface: Interface) -> Self {
let img_buffer = [0u8; G13_LCD_BUF_SIZE as usize + 8];
// let mut buffer = [0u8; G13_LCD_BUF_SIZE as usize + 32 + 8];
// buffer[0] = 0x03;
// buffer[32..G13_LCD_BUF_SIZE as usize + 32 + 8].copy_from_slice(&img_buffer);
Self {
interface,
img_buffer: Arc::new(RwLock::new(img_buffer)),
}
} }
pub fn set_lcd_color(&self, r: u8, g: u8, b: u8) -> Result<(), Box<dyn std::error::Error>> { pub fn set_lcd_color(&self, r: u8, g: u8, b: u8) -> Result<(), Box<dyn std::error::Error>> {
@@ -202,9 +281,13 @@ impl G13 {
w.flush()?; w.flush()?;
Ok(()) Ok(())
} }
pub fn size(&self) -> Size {
Size::new(G13_LCD_COLUMNS as u32, G13_LCD_ROWS as u32)
}
} }
impl Dimensions for G13 { impl Dimensions for G13Display {
fn bounding_box(&self) -> Rectangle { fn bounding_box(&self) -> Rectangle {
Rectangle::new( Rectangle::new(
Point::new(0, 0), Point::new(0, 0),
@@ -213,7 +296,7 @@ impl Dimensions for G13 {
} }
} }
impl DrawTarget for G13 { impl DrawTarget for G13Display {
type Color = BinaryColor; type Color = BinaryColor;
type Error = Box<dyn std::error::Error>; type Error = Box<dyn std::error::Error>;

View File

@@ -4,8 +4,11 @@ version.workspace = true
edition.workspace = true edition.workspace = true
[dependencies] [dependencies]
# buoyant = "0.6.1"
ctrlc = "3.5" ctrlc = "3.5"
embedded-graphics = "0.8" embedded-graphics = "0.8"
g13-driver.workspace = true g13-driver.workspace = true
mlua = { version = "0.11.6", features = ["lua54", "async", "macros", "serde"] } mlua = { version = "0.11.6", features = ["lua54", "async", "macros", "serde"] }
time = { version = "0.3.47", features = ["formatting", "macros"] } time = { version = "0.3.47", features = ["formatting", "macros"] }
embedded-graphics-simulator = "0.7.0"

View File

@@ -1,251 +1,73 @@
pub mod mouse; // pub mod mouse;
mod os; // mod os;
use g13_driver::{G13, G13_LCD_COLUMNS, G13_LCD_ROWS}; // use embedded_graphics::prelude::{Dimensions, DrawTarget};
use mlua::{Error, ExternalResult, Lua}; // use embedded_graphics::{pixelcolor::BinaryColor, prelude::Size};
use std::{ // use embedded_graphics_simulator::{OutputSettingsBuilder, SimulatorDisplay, Window};
fs, // use mlua::{Error, ExternalResult, Lua};
sync::{ // use rsact_ui::prelude::*;
Arc, // use rsact_ui::{
atomic::{AtomicBool, Ordering}, // col,
}, // event::simulator::simulator_single_encoder,
thread::sleep, // render::{AntiAliasing, RendererOptions},
time::{Duration, Instant}, // row,
// style::accent::AccentStyler,
// ui::UI,
// };
// use std::fmt::Binary;
// use std::{
// fs,
// sync::{
// Arc,
// atomic::{AtomicBool, Ordering},
// },
// thread::sleep,
// time::{Duration, Instant},
// };
// use crate::os::G13Os;
use embedded_graphics::{
Drawable,
pixelcolor::BinaryColor,
prelude::{DrawTarget, Point},
}; };
use g13_driver::{G13, G13Event};
use crate::os::G13Os;
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let running = Arc::new(AtomicBool::new(true)); let g13 = G13::new()?;
let (mut display, input) = g13.split();
let _running = running.clone(); let character_style = embedded_graphics::mono_font::MonoTextStyle::new(
&embedded_graphics::mono_font::ascii::FONT_10X20,
let os = G13Os::new(); embedded_graphics::pixelcolor::BinaryColor::On,
);
os.run(); let textstyle = embedded_graphics::text::TextStyleBuilder::new()
.alignment(embedded_graphics::text::Alignment::Left)
/* .baseline(embedded_graphics::text::Baseline::Top)
let lua = Lua::new();
let globals = lua.globals();
let g13_table = lua.create_table()?;
let _running = running.clone();
let _g13 = g13.clone();
std::thread::spawn(move || {
while _running.load(Ordering::SeqCst) {
if _g13.read().is_err() {
_running.store(false, Ordering::SeqCst);
}
}
});
let _g13 = g13.clone();
g13_table.set(
"set_color",
lua.create_function(move |_, (r, g, b): (i32, i32, i32)| {
_g13.set_lcd_color(
r.clamp(0, 255) as u8,
g.clamp(0, 255) as u8,
b.clamp(0, 255) as u8,
)
.into_lua_err()
})?,
)?;
let _g13 = g13.clone();
let fn_clear = lua.create_function(move |_, on| {
let mut _g13 = _g13.clone();
use embedded_graphics::pixelcolor::BinaryColor;
use embedded_graphics::prelude::*;
let color = if on {
BinaryColor::On
} else {
BinaryColor::Off
};
_g13.clear(color).into_lua_err()
})?;
g13_table.set("clear", fn_clear)?;
let mut _g13 = g13.clone();
let fn_set_pixel = lua.create_function_mut(move |_, (x, y, on)| {
use embedded_graphics::pixelcolor::BinaryColor;
use embedded_graphics::prelude::*;
let color = if on {
BinaryColor::On
} else {
BinaryColor::Off
};
Pixel(Point::new(x, y), color)
.draw(&mut _g13)
.into_lua_err()
})?;
g13_table.set("set_pixel", fn_set_pixel)?;
let mut _g13 = g13.clone();
let fn_text = lua.create_function_mut(
move |_,
(text, x, y, color, alignment, baseline, size): (
String,
i32,
i32,
bool,
i32,
i32,
i32,
)| {
use embedded_graphics::mono_font::ascii::*;
use embedded_graphics::pixelcolor::BinaryColor;
use embedded_graphics::prelude::*;
use embedded_graphics::text::*;
let alignment = match alignment {
0 => Alignment::Left,
1 => Alignment::Center,
2 => Alignment::Right,
_ => {
return Err(Error::RuntimeError(
"Invalid alignment, allowed values: 0, 1, 2".into(),
));
}
};
let baseline = match baseline {
0 => Baseline::Top,
1 => Baseline::Middle,
2 => Baseline::Bottom,
_ => {
return Err(Error::RuntimeError(
"Invalid baseline, allowed values: 0, 1, 2".into(),
));
}
};
let color = if color {
BinaryColor::On
} else {
BinaryColor::Off
};
let size = match size {
2 => FONT_5X7,
3 => FONT_5X8,
4 => FONT_6X9,
5 => FONT_6X10,
6 => FONT_6X12,
7 => FONT_6X13,
8 => FONT_6X13_BOLD,
9 => FONT_6X13_ITALIC,
10 => FONT_7X13,
11 => FONT_7X13_BOLD,
12 => FONT_7X13_ITALIC,
13 => FONT_7X14,
14 => FONT_7X14_BOLD,
15 => FONT_8X13,
16 => FONT_8X13_BOLD,
17 => FONT_8X13_ITALIC,
18 => FONT_9X15,
19 => FONT_9X15_BOLD,
20 => FONT_9X18,
21 => FONT_9X18_BOLD,
22 => FONT_10X20,
_ => FONT_4X6,
};
let character_style = embedded_graphics::mono_font::MonoTextStyle::new(&size, color);
let textstyle = TextStyleBuilder::new()
.alignment(alignment)
.baseline(baseline)
.build(); .build();
let pos = Point::new(x, y); for event in input {
let Some(event) = event else {
Text::with_text_style(&text, pos, character_style, textstyle) continue;
.draw(&mut _g13)
.into_lua_err()?;
Ok(())
},
)?;
g13_table.set("text", fn_text)?;
g13_table.set("display_width", G13_LCD_COLUMNS)?;
g13_table.set("display_height", G13_LCD_ROWS)?;
globals.set("g13", g13_table)?;
let joy = lua.create_table()?;
joy.set("x", 0.0f32)?;
joy.set("y", 0.0f32)?;
joy.set("deadzone", 40)?;
globals.set("joy", joy)?;
// load all files from dir `./scripts` for now, user configurable later or ~/.config/g13-os/\*.<lua>
// for now, just main.luau
let main = fs::read_to_string("./scripts/main.lua")?;
lua.load(main).set_name("main.lua").exec()?;
if lua.load("setup ~= nil").eval()? {
lua.load("setup()").exec()?;
}
if lua.load("update ~= nil").eval()? {
let mut _g13 = g13.clone();
let mut delta: f32 = 0.0;
while running.load(std::sync::atomic::Ordering::SeqCst) {
let start = Instant::now();
let state = g13.state();
let mut deadzone: i32 = lua.load("joy.deadzone").eval()?;
if deadzone > 512 {
deadzone = 0;
}
let offset: i32 = 512 - deadzone;
let mut x = state.x;
let mut y = state.y;
x = if x.abs() < deadzone {
0
} else {
x - deadzone * x.signum()
}; };
y = if y.abs() < deadzone { println!("{:?}", event);
0
} else {
y - deadzone * y.signum()
};
lua.load(format!( display.clear(BinaryColor::Off)?;
"joy.x = {}\njoy.y = {}",
x as f32 / offset as f32,
y as f32 / offset as f32
))
.exec()?;
let buttons = lua.create_table()?; if let G13Event::Axis(x, y) = event {
buttons.set("t1", state.buttons.screen1)?; embedded_graphics::text::Text::with_text_style(
buttons.set("t2", state.buttons.screen2)?; &format!("{}x{}", x, y),
buttons.set("t3", state.buttons.screen3)?; Point::new(5, 5),
buttons.set("t4", state.buttons.screen4)?; character_style,
globals.set("buttons", buttons)?; textstyle,
)
lua.load(format!("update({})", delta)).exec()?; .draw(&mut display)?;
_g13.render()?;
let duration = Instant::now() - start;
// 30 fps lock
if duration < Duration::from_millis(33) {
sleep(Duration::from_millis(33) - duration);
} }
delta = (Instant::now() - start).as_secs_f32(); display.render()?;
}
} }
running.store(false, Ordering::SeqCst);
*/
Ok(()) Ok(())
} }