Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

53
vendor/gilrs/examples/ev.rs vendored Normal file
View File

@@ -0,0 +1,53 @@
// Copyright 2016-2018 Mateusz Sieczko and other GilRs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use gilrs::ev::filter::{Filter, Repeat};
use gilrs::GilrsBuilder;
use std::process;
fn main() {
env_logger::init();
let mut gilrs = match GilrsBuilder::new().set_update_state(false).build() {
Ok(g) => g,
Err(gilrs::Error::NotImplemented(g)) => {
eprintln!("Current platform is not supported");
g
}
Err(e) => {
eprintln!("Failed to create gilrs context: {}", e);
process::exit(-1);
}
};
let repeat_filter = Repeat::new();
loop {
while let Some(ev) = gilrs
.next_event_blocking(None)
.filter_ev(&repeat_filter, &mut gilrs)
{
gilrs.update(&ev);
println!("{:?}", ev);
}
if gilrs.counter() % 25 == 0 {
for (id, gamepad) in gilrs.gamepads() {
println!(
"Power info of gamepad {}({}): {:?}",
id,
gamepad.name(),
gamepad.power_info()
);
}
}
gilrs.inc();
}
}

47
vendor/gilrs/examples/ff.rs vendored Normal file
View File

@@ -0,0 +1,47 @@
// Copyright 2016-2018 Mateusz Sieczko and other GilRs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use gilrs::ff::{BaseEffect, BaseEffectType, EffectBuilder, Replay, Ticks};
use gilrs::Gilrs;
use std::thread;
use std::time::Duration;
fn main() {
env_logger::init();
let mut gilrs = Gilrs::new().unwrap();
let support_ff = gilrs
.gamepads()
.filter_map(|(id, gp)| if gp.is_ff_supported() { Some(id) } else { None })
.collect::<Vec<_>>();
let duration = Ticks::from_ms(150);
let effect = EffectBuilder::new()
.add_effect(BaseEffect {
kind: BaseEffectType::Strong { magnitude: 60_000 },
scheduling: Replay {
play_for: duration,
with_delay: duration * 3,
..Default::default()
},
envelope: Default::default(),
})
.add_effect(BaseEffect {
kind: BaseEffectType::Weak { magnitude: 60_000 },
scheduling: Replay {
after: duration * 2,
play_for: duration,
with_delay: duration * 3,
},
..Default::default()
})
.gamepads(&support_ff)
.finish(&mut gilrs)
.unwrap();
effect.play().unwrap();
thread::sleep(Duration::from_secs(11));
}

201
vendor/gilrs/examples/ff_pos.rs vendored Normal file
View File

@@ -0,0 +1,201 @@
// Copyright 2016-2018 Mateusz Sieczko and other GilRs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use gilrs::ff::{BaseEffect, BaseEffectType, DistanceModel, EffectBuilder};
use gilrs::{Axis, Button, EventType, Gilrs};
use std::io::{self, Write};
use std::thread;
use std::time::Duration;
#[derive(Copy, Clone, PartialEq, Debug)]
enum Modify {
DistModel,
RefDistance,
RolloffFactor,
MaxDistance,
}
impl Modify {
fn next(&mut self) {
use crate::Modify::*;
*self = match *self {
DistModel => RefDistance,
RefDistance => RolloffFactor,
RolloffFactor => MaxDistance,
MaxDistance => DistModel,
};
print!("\x1b[2K\r{:?}", self);
io::stdout().flush().unwrap();
}
fn prev(&mut self) {
use crate::Modify::*;
*self = match *self {
DistModel => MaxDistance,
RefDistance => DistModel,
RolloffFactor => RefDistance,
MaxDistance => RolloffFactor,
};
print!("\x1b[2K\r{:?}", self);
io::stdout().flush().unwrap();
}
}
fn main() {
env_logger::init();
let mut gilrs = Gilrs::new().unwrap();
println!("Connected gamepads:");
let mut support_ff = Vec::new();
for (idx, gp) in gilrs.gamepads() {
let ff = gp.is_ff_supported();
println!(
"{}) {} ({})",
idx,
gp.name(),
if ff {
"Force feedback supported"
} else {
"Force feedback not supported"
}
);
if ff {
support_ff.push(idx);
}
}
println!("----------------------------------------");
println!(
"Use sticks to move listener. Triggers change properties of distance model. South/west \
button changes active property. Press east button on action pad to quit."
);
let pos1 = [-100.0, 0.0, 0.0];
let mut effect_builder = EffectBuilder::new()
.add_effect(BaseEffect {
kind: BaseEffectType::Strong { magnitude: 45_000 },
..Default::default()
})
.add_effect(BaseEffect {
kind: BaseEffectType::Weak { magnitude: 45_000 },
..Default::default()
})
.distance_model(DistanceModel::None)
.gamepads(&support_ff)
.clone();
let left_effect = effect_builder.position(pos1).finish(&mut gilrs).unwrap();
left_effect.play().unwrap();
println!("Playing one effects…");
println!("Position of effect sources: {:?}", pos1);
let mut listeners = support_ff
.iter()
.map(|&idx| (idx, [0.0, 0.0, 0.0]))
.collect::<Vec<_>>();
let mut ref_distance = 10.0;
let mut rolloff_factor = 0.5;
let mut max_distance = 100.0;
let mut modify = Modify::DistModel;
let mut model = 0usize;
'main: loop {
while let Some(event) = gilrs.next_event() {
match event.event {
EventType::ButtonReleased(Button::East, ..) => break 'main,
EventType::ButtonReleased(Button::South, ..) => modify.next(),
EventType::ButtonReleased(Button::West, ..) => modify.prev(),
EventType::ButtonReleased(Button::LeftTrigger, ..)
if modify == Modify::DistModel =>
{
model = model.wrapping_sub(1);
}
EventType::ButtonReleased(Button::RightTrigger, ..)
if modify == Modify::DistModel =>
{
model = model.wrapping_add(1);
}
_ => (),
}
}
for &mut (idx, ref mut pos) in &mut listeners {
let velocity = 0.5;
let gp = gilrs.gamepad(idx);
let (sx, sy) = (gp.value(Axis::LeftStickX), gp.value(Axis::LeftStickY));
if sx.abs() > 0.5 || sy.abs() > 0.5 {
if sx.abs() > 0.5 {
pos[0] += velocity * sx.signum();
}
if sy.abs() > 0.5 {
pos[1] += velocity * sy.signum();
}
gilrs.gamepad(idx).set_listener_position(*pos).unwrap();
let dist = ((pos[0] - pos1[0]).powi(2) + (pos[1] - pos1[1]).powi(2)).sqrt();
print!(
"\x1b[2K\rPosition of listener {:2} has changed: [{:6.1}, {:6.1}].Distance: \
{:.1}",
idx, pos[0], pos[1], dist
);
io::stdout().flush().unwrap();
}
let x = if gp.is_pressed(Button::LeftTrigger) {
-1.0
} else if gp.is_pressed(Button::RightTrigger) {
1.0
} else {
continue;
};
match modify {
Modify::RolloffFactor => rolloff_factor += x * velocity * 0.1,
Modify::RefDistance => ref_distance += x * velocity * 0.1,
Modify::MaxDistance => max_distance += x * velocity * 1.0,
Modify::DistModel => (), // DistanceModel handled in event loop
}
let model = match model % 4 {
0 => DistanceModel::None,
1 => DistanceModel::LinearClamped {
ref_distance,
rolloff_factor,
max_distance,
},
2 => DistanceModel::InverseClamped {
ref_distance,
rolloff_factor,
max_distance,
},
3 => DistanceModel::ExponentialClamped {
ref_distance,
rolloff_factor,
max_distance,
},
_ => unreachable!(),
};
match left_effect.set_distance_model(model) {
Ok(()) => print!("\x1b[2K\r{:?}", model),
Err(e) => print!("\x1b[2K\r{}", e),
}
io::stdout().flush().unwrap();
}
thread::sleep(Duration::from_millis(16));
}
}

60
vendor/gilrs/examples/gamepad_info.rs vendored Normal file
View File

@@ -0,0 +1,60 @@
use gilrs::{Axis, Button, Gilrs};
use uuid::Uuid;
fn main() {
let gilrs = Gilrs::new().unwrap();
for (id, gamepad) in gilrs.gamepads() {
println!(
r#"Gamepad {id} ({name}):
Map name: {map_name:?}
Os name: {os_name}
UUID: {uuid}
Is connected: {is_connected}
Power info: {power_info:?}
Mapping source: {mapping_source:?}
Is ff supported: {ff}
Deadzone Left X: {dlx:?}
Deadzone Left Y: {dly:?}
Deadzone Right X: {drx:?}
Deadzone Right Y: {dry:?}
Deadzone Left Trigger: {dlt:?}
Deadzone Right Trigger: {drt:?}
Deadzone Left Trigger 2: {dlt2:?}
Deadzone Right Trigger 2: {drt2:?}
"#,
id = id,
name = gamepad.name(),
map_name = gamepad.map_name(),
os_name = gamepad.os_name(),
uuid = Uuid::from_bytes(gamepad.uuid()).as_hyphenated(),
is_connected = gamepad.is_connected(),
power_info = gamepad.power_info(),
mapping_source = gamepad.mapping_source(),
ff = gamepad.is_ff_supported(),
dlx = gamepad
.axis_code(Axis::LeftStickX)
.and_then(|code| gamepad.deadzone(code)),
dly = gamepad
.axis_code(Axis::LeftStickY)
.and_then(|code| gamepad.deadzone(code)),
drx = gamepad
.axis_code(Axis::RightStickX)
.and_then(|code| gamepad.deadzone(code)),
dry = gamepad
.axis_code(Axis::RightStickY)
.and_then(|code| gamepad.deadzone(code)),
dlt = gamepad
.button_code(Button::LeftTrigger)
.and_then(|code| gamepad.deadzone(code)),
drt = gamepad
.button_code(Button::RightTrigger)
.and_then(|code| gamepad.deadzone(code)),
dlt2 = gamepad
.button_code(Button::LeftTrigger2)
.and_then(|code| gamepad.deadzone(code)),
drt2 = gamepad
.button_code(Button::RightTrigger2)
.and_then(|code| gamepad.deadzone(code)),
);
}
}

329
vendor/gilrs/examples/gui.rs vendored Normal file
View File

@@ -0,0 +1,329 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
use crate::egui::plot::{MarkerShape, PlotPoints, Points};
use crate::egui::RichText;
use eframe::egui;
use eframe::egui::Vec2;
use gilrs::ev::AxisOrBtn;
use gilrs::ff::{BaseEffect, BaseEffectType, Effect, EffectBuilder, Repeat, Ticks};
use gilrs::{Axis, GamepadId, Gilrs, GilrsBuilder};
use gilrs_core::PowerInfo;
use std::time::UNIX_EPOCH;
use uuid::Uuid;
struct MyEguiApp {
gilrs: Gilrs,
current_gamepad: Option<GamepadId>,
log_messages: [Option<String>; 300],
// These will be none if Force feedback isn't supported for this platform e.g. Wasm
ff_strong: Option<Effect>,
ff_weak: Option<Effect>,
}
impl Default for MyEguiApp {
fn default() -> Self {
#[cfg(target_arch = "wasm32")]
console_log::init().unwrap();
const INIT: Option<String> = None;
let mut gilrs = GilrsBuilder::new().set_update_state(false).build().unwrap();
let ff_strong = EffectBuilder::new()
.add_effect(BaseEffect {
kind: BaseEffectType::Strong { magnitude: 60_000 },
scheduling: Default::default(),
envelope: Default::default(),
})
.repeat(Repeat::For(Ticks::from_ms(100)))
.finish(&mut gilrs)
.ok();
let ff_weak = EffectBuilder::new()
.add_effect(BaseEffect {
kind: BaseEffectType::Weak { magnitude: 60_000 },
scheduling: Default::default(),
envelope: Default::default(),
})
.repeat(Repeat::For(Ticks::from_ms(100)))
.finish(&mut gilrs)
.ok();
Self {
gilrs,
current_gamepad: None,
log_messages: [INIT; 300],
ff_strong,
ff_weak,
}
}
}
impl MyEguiApp {
fn log(&mut self, message: String) {
self.log_messages[0..].rotate_right(1);
self.log_messages[0] = Some(message);
}
}
impl MyEguiApp {
fn new(_cc: &eframe::CreationContext<'_>) -> Self {
Self::default()
}
}
impl eframe::App for MyEguiApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
while let Some(event) = self.gilrs.next_event() {
self.log(format!(
"{} : {} : {:?}",
event
.time
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_millis(),
event.id,
event.event
));
self.gilrs.update(&event);
if self.current_gamepad.is_none() {
self.current_gamepad = Some(event.id);
}
}
egui::SidePanel::left("side_panel").show(ctx, |ui| {
ui.heading("Controllers");
ui.separator();
for (id, gamepad) in self.gilrs.gamepads() {
if ui
.selectable_label(
self.current_gamepad == Some(id),
format!("{id}: {}", gamepad.name()),
)
.clicked()
{
self.current_gamepad = Some(id);
};
}
ui.allocate_space(ui.available_size());
});
egui::TopBottomPanel::bottom("log")
.resizable(true)
.default_height(200.0)
.show(ctx, |ui| {
ui.heading("Event Log");
egui::ScrollArea::vertical()
.max_height(ui.available_height())
.show(ui, |ui| {
for message in self.log_messages.iter().flatten() {
ui.label(message);
}
ui.allocate_space(ui.available_size());
});
});
egui::CentralPanel::default().show(ctx, |ui| {
egui::ScrollArea::both().show(ui, |ui| {
if let Some(gamepad_id) = self.current_gamepad {
let gamepad = self.gilrs.gamepad(gamepad_id);
let gamepad_state = gamepad.state();
ui.horizontal(|ui| {
ui.vertical(|ui| {
ui.heading("Info");
egui::Grid::new("info_grid")
.striped(true)
.num_columns(2)
.show(ui, |ui| {
ui.label("Name");
ui.label(gamepad.name());
ui.end_row();
if let Some(vendor) = gamepad.vendor_id() {
ui.label("Vendor ID");
ui.label(format!("{vendor:04x}"));
ui.end_row();
}
if let Some(product) = gamepad.product_id() {
ui.label("Product ID");
ui.label(format!("{product:04x}"));
ui.end_row();
}
ui.label("Gilrs ID");
ui.label(gamepad.id().to_string());
ui.end_row();
if let Some(map_name) = gamepad.map_name() {
ui.label("Map Name");
ui.label(map_name);
ui.end_row();
}
ui.label("Map Source");
ui.label(format!("{:?}", gamepad.mapping_source()));
ui.end_row();
ui.label("Uuid");
let uuid = Uuid::from_bytes(gamepad.uuid()).to_string();
ui.horizontal(|ui| {
ui.label(&uuid);
if ui.button("Copy").clicked() {
ui.output().copied_text = uuid;
}
});
ui.end_row();
ui.label("Power");
ui.label(match gamepad.power_info() {
PowerInfo::Unknown => "Unknown".to_string(),
PowerInfo::Wired => "Wired".to_string(),
PowerInfo::Discharging(p) => format!("Discharging {p}"),
PowerInfo::Charging(p) => format!("Charging {p}"),
PowerInfo::Charged => "Charged".to_string(),
});
ui.end_row();
});
});
if gamepad.is_ff_supported() {
ui.vertical(|ui| {
ui.label("Force Feedback");
if let Some(ff_strong) = &self.ff_strong {
if ui.button("Play Strong").clicked() {
ff_strong.add_gamepad(&gamepad).unwrap();
ff_strong.play().unwrap();
}
}
if let Some(ff_weak) = &self.ff_weak {
if ui.button("Play Weak").clicked() {
ff_weak.add_gamepad(&gamepad).unwrap();
ff_weak.play().unwrap();
}
}
});
}
});
ui.horizontal(|ui| {
ui.vertical(|ui| {
ui.set_width(300.0);
ui.heading("Buttons");
for (code, button_data) in gamepad_state.buttons() {
let name = match gamepad.axis_or_btn_name(code) {
Some(AxisOrBtn::Btn(b)) => format!("{b:?}"),
_ => "Unknown".to_string(),
};
ui.add(
egui::widgets::ProgressBar::new(button_data.value()).text(
RichText::new(format!(
"{name:<14} {:<5} {:.4} {}",
button_data.is_pressed(),
button_data.value(),
code
))
.monospace(),
),
);
}
});
ui.vertical(|ui| {
ui.set_width(300.0);
ui.heading("Axes");
ui.horizontal(|ui| {
for (name, x, y) in [
("Left Stick", Axis::LeftStickX, Axis::LeftStickY),
("Right Stick", Axis::RightStickX, Axis::RightStickY),
] {
ui.vertical(|ui| {
ui.label(name);
let y_axis = gamepad
.axis_data(y)
.map(|a| a.value())
.unwrap_or_default()
as f64;
let x_axis = gamepad
.axis_data(x)
.map(|a| a.value())
.unwrap_or_default()
as f64;
egui::widgets::plot::Plot::new(format!("{name}_plot"))
.width(150.0)
.height(150.0)
.min_size(Vec2::splat(3.25))
.include_x(1.25)
.include_y(1.25)
.include_x(-1.25)
.include_y(-1.25)
.allow_drag(false)
.allow_zoom(false)
.allow_boxed_zoom(false)
.allow_scroll(false)
.show(ui, |plot_ui| {
plot_ui.points(
Points::new(PlotPoints::new(vec![[
x_axis, y_axis,
]]))
.shape(MarkerShape::Circle)
.radius(4.0),
);
});
});
}
});
for (code, axis_data) in gamepad_state.axes() {
let name = match gamepad.axis_or_btn_name(code) {
None => code.to_string(),
Some(AxisOrBtn::Btn(b)) => format!("{b:?}"),
Some(AxisOrBtn::Axis(a)) => format!("{a:?}"),
};
ui.add(
egui::widgets::ProgressBar::new(
(axis_data.value() * 0.5) + 0.5,
)
.text(
RichText::new(format!(
"{:+.4} {name:<15} {}",
axis_data.value(),
code
))
.monospace(),
),
);
}
});
});
} else {
ui.label("Press a button on a controller or select it from the left.");
}
ui.allocate_space(ui.available_size());
});
});
ctx.request_repaint();
}
}
#[cfg(not(target_arch = "wasm32"))]
fn main() {
env_logger::init();
let native_options = eframe::NativeOptions {
initial_window_size: Some(Vec2::new(1024.0, 768.0)),
..Default::default()
};
eframe::run_native(
"Gilrs Input Tester",
native_options,
Box::new(|cc| Box::new(MyEguiApp::new(cc))),
);
}
#[cfg(target_arch = "wasm32")]
fn main() {
console_error_panic_hook::set_once();
let web_options = eframe::WebOptions::default();
eframe::start_web(
"canvas",
web_options,
Box::new(|cc| Box::new(MyEguiApp::new(cc))),
)
.unwrap();
}

32
vendor/gilrs/examples/wasm/README.md vendored Normal file
View File

@@ -0,0 +1,32 @@
# Wasm Example
These are instructions for running the GUI example in your web browser using Wasm.
Currently only the GUI example is set up to run with Wasm.
### Ubuntu requirements
```bash
sudo apt install build-essential
sudo apt-get install libssl-dev pkg-config
```
### Setup
```pwsh
rustup target add wasm32-unknown-unknown
cargo install wasm-bindgen-cli
cargo install basic-http-server
```
### Build and Run
Run these from the workspace root.
```pwsh
cargo build --release --example gui --target wasm32-unknown-unknown
wasm-bindgen --out-name wasm_example --out-dir gilrs/examples/wasm/target --target web target/wasm32-unknown-unknown/release/examples/gui.wasm
basic-http-server gilrs/examples/wasm
```
Now open your web browser and navigate to http://127.0.0.1:4000

34
vendor/gilrs/examples/wasm/index.html vendored Normal file
View File

@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Gilrs Example</title>
<style>
html, body {
margin: 0;
/* prevent scroll bar from showing */
overflow: hidden;
/*
Egui automatically resizes the canvas to fit it's parent element so ensures the canvas will
resize to always be fullscreen.
*/
width: 100%;
height: 100%;
}
canvas {
/*
Egui adds these to the canvas automatically, but not until it gets focus,
causing it to grow until you click on it. This prevents that.
*/
position: absolute;
top: 0;
}
</style>
</head>
<script type="module">
import init from './target/wasm_example.js'
init()
</script>
<canvas id="canvas"></canvas>
</html>

14
vendor/gilrs/examples/wasm/wasm_gui.ps1 vendored Normal file
View File

@@ -0,0 +1,14 @@
### This script can be used instead of the "Build and Run" step in `./gilrs/examples/wasm/README.md`.
### Useful for gilrs devs that want a single script to to point their IDE to for run configurations.
### Supports Powershell 5 and up on Windows or Linux
### Make sure to run the install steps from the readme first.
# Start at this script's path and go up three levels to the workspace root.
# Ensures a consistent path regardless of the working directory when you run the script.
$Path = $PSScriptRoot | Split-Path | Split-Path | Split-Path
$ProjectDir = Resolve-Path $Path
Set-Location $ProjectDir
cargo build --release --example gui --target wasm32-unknown-unknown
wasm-bindgen --out-name wasm_example --out-dir gilrs/examples/wasm/target --target web target/wasm32-unknown-unknown/release/examples/gui.wasm
basic-http-server gilrs/examples/wasm

17
vendor/gilrs/examples/wasm/wasm_gui.sh vendored Executable file
View File

@@ -0,0 +1,17 @@
#!/usr/bin/env bash
### This script can be used instead of the "Build and Run" step in `./gilrs/examples/wasm/README.md`.
### Useful for gilrs devs that want a single script to to point their IDE to for run configurations.
### Make sure to run the install steps from the readme first.
set -e
# Start at this script's path and go up three levels to the workspace root.
# Ensures a consistent path regardless of the working directory when you run the script.
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
PROJECT_DIR=$(dirname "$(dirname "$(dirname "$SCRIPT_DIR")")")
cd "$PROJECT_DIR" || exit
cargo build --release --example gui --target wasm32-unknown-unknown
wasm-bindgen --out-name wasm_example --out-dir gilrs/examples/wasm/target --target web target/wasm32-unknown-unknown/release/examples/gui.wasm
basic-http-server gilrs/examples/wasm