improve error handling
This commit is contained in:
@@ -136,8 +136,8 @@ impl GeneralConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn post_load(&self) {
|
fn post_load(&self) {
|
||||||
GeneralConfig::sanitize_range("keyboard_scale", self.keyboard_scale, 0.0, 5.0);
|
GeneralConfig::sanitize_range("keyboard_scale", self.keyboard_scale, 0.05, 5.0);
|
||||||
GeneralConfig::sanitize_range("desktop_view_scale", self.desktop_view_scale, 0.0, 5.0);
|
GeneralConfig::sanitize_range("desktop_view_scale", self.desktop_view_scale, 0.05, 5.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,12 +192,31 @@ pub fn load_general() -> GeneralConfig {
|
|||||||
// Add files from conf.d directory
|
// Add files from conf.d directory
|
||||||
let path_conf_d = get_conf_d_path();
|
let path_conf_d = get_conf_d_path();
|
||||||
if let Ok(paths_unsorted) = std::fs::read_dir(path_conf_d) {
|
if let Ok(paths_unsorted) = std::fs::read_dir(path_conf_d) {
|
||||||
|
let mut paths: Vec<_> = paths_unsorted
|
||||||
|
.filter_map(|r| match r {
|
||||||
|
Ok(entry) => Some(entry),
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to read conf.d directory: {}", e);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
// Sort paths alphabetically
|
// Sort paths alphabetically
|
||||||
let mut paths: Vec<_> = paths_unsorted.map(|r| r.unwrap()).collect(); // TODO safe unwrap?
|
|
||||||
paths.sort_by_key(|dir| dir.path());
|
paths.sort_by_key(|dir| dir.path());
|
||||||
for path in paths {
|
for path in paths {
|
||||||
if !path.file_type().unwrap().is_file() {
|
let file_type = match path.file_type() {
|
||||||
// TODO safe unwrap?
|
Ok(file_type) => file_type,
|
||||||
|
Err(e) => {
|
||||||
|
error!(
|
||||||
|
"Failed to get file type of {}: {}",
|
||||||
|
path.path().to_string_lossy(),
|
||||||
|
e
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if !file_type.is_file() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -106,9 +106,7 @@ impl FontCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let pattern_str = format!("{PRIMARY_FONT}-{size}:style=bold:charset={cp:04x}");
|
let pattern_str = format!("{PRIMARY_FONT}-{size}:style=bold:charset={cp:04x}");
|
||||||
|
let mut pattern = OwnedPattern::from_str(&pattern_str).unwrap(); // safe because PRIMARY_FONT is const
|
||||||
let mut pattern =
|
|
||||||
OwnedPattern::from_str(&pattern_str).expect("Failed to create fontconfig pattern");
|
|
||||||
self.fc
|
self.fc
|
||||||
.substitute(&mut pattern, fontconfig::MatchKind::Pattern);
|
.substitute(&mut pattern, fontconfig::MatchKind::Pattern);
|
||||||
pattern.default_substitute();
|
pattern.default_substitute();
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use std::{
|
use std::{
|
||||||
f32::consts::PI,
|
f32::consts::PI,
|
||||||
io::Cursor,
|
|
||||||
ops::Add,
|
ops::Add,
|
||||||
process::{self, Child},
|
process::{self, Child},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
@@ -8,7 +7,6 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use glam::{Quat, Vec3A};
|
use glam::{Quat, Vec3A};
|
||||||
use rodio::{Decoder, Source};
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -613,11 +611,8 @@ fn run_window(window: &Arc<str>, action: &WindowAction, app: &mut AppState) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const THUMP_AUDIO_WAV: &'static [u8] = include_bytes!("../../res/380885.wav");
|
||||||
|
|
||||||
fn audio_thump(app: &mut AppState) {
|
fn audio_thump(app: &mut AppState) {
|
||||||
if let Some(handle) = app.audio.get_handle() {
|
app.audio.play(THUMP_AUDIO_WAV);
|
||||||
let wav = include_bytes!("../../res/380885.wav");
|
|
||||||
let cursor = Cursor::new(wav);
|
|
||||||
let source = Decoder::new_wav(cursor).unwrap();
|
|
||||||
let _ = handle.play_raw(source.convert_samples());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
io::Cursor,
|
|
||||||
process::{Child, Command},
|
process::{Child, Command},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
};
|
};
|
||||||
@@ -18,7 +17,6 @@ use crate::{
|
|||||||
use glam::{vec2, vec3a, Affine2, Vec4};
|
use glam::{vec2, vec3a, Affine2, Vec4};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use rodio::{Decoder, Source};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
const PIXELS_PER_UNIT: f32 = 80.;
|
const PIXELS_PER_UNIT: f32 = 80.;
|
||||||
@@ -83,10 +81,14 @@ where
|
|||||||
verbs: key_events_for_macro(macro_verbs),
|
verbs: key_events_for_macro(macro_verbs),
|
||||||
});
|
});
|
||||||
} else if let Some(exec_args) = LAYOUT.exec_commands.get(key) {
|
} else if let Some(exec_args) = LAYOUT.exec_commands.get(key) {
|
||||||
|
if exec_args.is_empty() {
|
||||||
|
log::error!("Keyboard: EXEC args empty for {}", key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
maybe_state = Some(KeyButtonData::Exec {
|
maybe_state = Some(KeyButtonData::Exec {
|
||||||
program: exec_args
|
program: exec_args
|
||||||
.first()
|
.first()
|
||||||
.expect("Keyboard: Invalid EXEC args")
|
.unwrap() // safe because we checked is_empty
|
||||||
.clone(),
|
.clone(),
|
||||||
args: exec_args.iter().skip(1).cloned().collect(),
|
args: exec_args.iter().skip(1).cloned().collect(),
|
||||||
});
|
});
|
||||||
@@ -227,18 +229,12 @@ struct KeyboardData {
|
|||||||
processes: Vec<Child>,
|
processes: Vec<Child>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const KEY_AUDIO_WAV: &'static [u8] = include_bytes!("../res/421581.wav");
|
||||||
|
|
||||||
impl KeyboardData {
|
impl KeyboardData {
|
||||||
fn key_click(&mut self, app: &mut AppState) {
|
fn key_click(&mut self, app: &mut AppState) {
|
||||||
if !app.session.config.keyboard_sound_enabled {
|
if app.session.config.keyboard_sound_enabled {
|
||||||
return;
|
app.audio.play(KEY_AUDIO_WAV);
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(handle) = app.audio.get_handle() {
|
|
||||||
// https://freesound.org/people/UberBosser/sounds/421581/
|
|
||||||
let wav = include_bytes!("../res/421581.wav");
|
|
||||||
let cursor = Cursor::new(wav);
|
|
||||||
let source = Decoder::new_wav(cursor).unwrap();
|
|
||||||
let _ = handle.play_raw(source.convert_samples());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -253,7 +249,7 @@ enum KeyButtonData {
|
|||||||
static LAYOUT: Lazy<Layout> = Lazy::new(Layout::load_from_disk);
|
static LAYOUT: Lazy<Layout> = Lazy::new(Layout::load_from_disk);
|
||||||
|
|
||||||
static MACRO_REGEX: Lazy<Regex> =
|
static MACRO_REGEX: Lazy<Regex> =
|
||||||
Lazy::new(|| Regex::new(r"^([A-Za-z0-1_-]+)(?: +(UP|DOWN))?$").unwrap());
|
Lazy::new(|| Regex::new(r"^([A-Za-z0-1_-]+)(?: +(UP|DOWN))?$").unwrap()); // want panic
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
pub struct Layout {
|
pub struct Layout {
|
||||||
@@ -314,11 +310,17 @@ impl Layout {
|
|||||||
key = &key[3..];
|
key = &key[3..];
|
||||||
}
|
}
|
||||||
if key.contains('_') {
|
if key.contains('_') {
|
||||||
key = key.split('_').next().unwrap();
|
key = key.split('_').next().unwrap_or_else(|| {
|
||||||
|
log::error!(
|
||||||
|
"keyboard.yaml: Key '{}' must not start or end with '_'!",
|
||||||
|
key
|
||||||
|
);
|
||||||
|
"???"
|
||||||
|
});
|
||||||
}
|
}
|
||||||
vec![format!(
|
vec![format!(
|
||||||
"{}{}",
|
"{}{}",
|
||||||
key.chars().next().unwrap().to_uppercase(),
|
key.chars().next().unwrap().to_uppercase(), // safe because we checked is_empty
|
||||||
&key[1..].to_lowercase()
|
&key[1..].to_lowercase()
|
||||||
)]
|
)]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
use std::{
|
use std::{
|
||||||
io::Cursor,
|
|
||||||
ops::Add,
|
ops::Add,
|
||||||
sync::{atomic::AtomicUsize, Arc},
|
sync::{atomic::AtomicUsize, Arc},
|
||||||
time::Instant,
|
time::Instant,
|
||||||
};
|
};
|
||||||
|
|
||||||
use rodio::{Decoder, Source};
|
|
||||||
|
|
||||||
use glam::vec3a;
|
use glam::vec3a;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -21,6 +18,7 @@ use crate::{
|
|||||||
const FONT_SIZE: isize = 16;
|
const FONT_SIZE: isize = 16;
|
||||||
const PADDING: (f32, f32) = (25., 7.);
|
const PADDING: (f32, f32) = (25., 7.);
|
||||||
const PIXELS_TO_METERS: f32 = 1. / 2000.;
|
const PIXELS_TO_METERS: f32 = 1. / 2000.;
|
||||||
|
const TOAST_AUDIO_WAV: &'static [u8] = include_bytes!("../res/557297.wav");
|
||||||
|
|
||||||
static AUTO_INCREMENT: AtomicUsize = AtomicUsize::new(0);
|
static AUTO_INCREMENT: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
@@ -79,12 +77,7 @@ impl Toast {
|
|||||||
.enqueue_at(TaskType::DropOverlay(selector), destroy_at);
|
.enqueue_at(TaskType::DropOverlay(selector), destroy_at);
|
||||||
|
|
||||||
if has_sound {
|
if has_sound {
|
||||||
if let Some(handle) = app.audio.get_handle() {
|
app.audio.play(TOAST_AUDIO_WAV);
|
||||||
let wav = include_bytes!("../res/557297.wav");
|
|
||||||
let cursor = Cursor::new(wav);
|
|
||||||
let source = Decoder::new_wav(cursor).unwrap();
|
|
||||||
let _ = handle.play_raw(source.convert_samples());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
23
src/state.rs
23
src/state.rs
@@ -1,8 +1,8 @@
|
|||||||
use std::{path::PathBuf, sync::Arc};
|
use std::{io::Cursor, path::PathBuf, sync::Arc};
|
||||||
|
|
||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
use glam::Vec3;
|
use glam::Vec3;
|
||||||
use rodio::{OutputStream, OutputStreamHandle};
|
use rodio::{Decoder, OutputStream, OutputStreamHandle, Source};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use vulkano::format::Format;
|
use vulkano::format::Format;
|
||||||
@@ -126,18 +126,33 @@ impl AudioOutput {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_handle(&mut self) -> Option<&OutputStreamHandle> {
|
fn get_handle(&mut self) -> Option<&OutputStreamHandle> {
|
||||||
if self.audio_stream.is_none() && self.first_try {
|
if self.audio_stream.is_none() && self.first_try {
|
||||||
self.first_try = false;
|
self.first_try = false;
|
||||||
if let Ok((stream, handle)) = OutputStream::try_default() {
|
if let Ok((stream, handle)) = OutputStream::try_default() {
|
||||||
self.audio_stream = Some((stream, handle));
|
self.audio_stream = Some((stream, handle));
|
||||||
} else {
|
} else {
|
||||||
log::error!("Failed to open audio stream");
|
log::error!("Failed to open audio stream. Audio will not work.");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.audio_stream.as_ref().map(|(_, h)| h)
|
self.audio_stream.as_ref().map(|(_, h)| h)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn play(&mut self, wav_bytes: &'static [u8]) {
|
||||||
|
let Some(handle) = self.get_handle() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let cursor = Cursor::new(wav_bytes);
|
||||||
|
let source = match Decoder::new_wav(cursor) {
|
||||||
|
Ok(source) => source,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to play sound: {:?}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let _ = handle.play_raw(source.convert_samples());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ScreenMeta {
|
pub struct ScreenMeta {
|
||||||
|
|||||||
Reference in New Issue
Block a user