Port changes from -x repo (#3)

* Port config support from -x repo

* Port changes from -x repo
This commit is contained in:
Aleksander
2024-01-29 18:14:54 +01:00
committed by GitHub
parent 3b0440562a
commit dded4f6398
16 changed files with 352 additions and 91 deletions

View File

@@ -1,9 +1,6 @@
use std::{
collections::HashMap,
env::var,
fs,
io::Cursor,
path::PathBuf,
process::{Child, Command},
str::FromStr,
sync::Arc,
@@ -11,14 +8,15 @@ use std::{
use crate::{
backend::overlay::{OverlayData, OverlayState},
config,
gui::{color_parse, CanvasBuilder, Control},
hid::{KeyModifier, VirtualKey, KEYS_TO_MODS},
state::AppState,
state::{AppSession, AppState},
};
use glam::{vec2, vec3a, Affine2};
use once_cell::sync::Lazy;
use regex::Regex;
use rodio::{Decoder, OutputStream, Source};
use rodio::{Decoder, OutputStream, OutputStreamHandle, Source};
use serde::{Deserialize, Serialize};
const PIXELS_PER_UNIT: f32 = 80.;
@@ -37,6 +35,8 @@ where
modifiers: 0,
processes: vec![],
audio_stream: None,
first_try: true,
audio_handle: None,
};
let mut canvas = CanvasBuilder::new(
@@ -109,7 +109,7 @@ where
let interaction_transform = Affine2::from_translation(vec2(0.5, 0.5))
* Affine2::from_scale(vec2(1., -size.x as f32 / size.y as f32));
let width = LAYOUT.row_size * 0.05;
let width = LAYOUT.row_size * 0.05 * app.session.config.keyboard_scale;
OverlayData {
state: OverlayState {
@@ -134,7 +134,7 @@ fn key_press(
) {
match control.state.as_mut() {
Some(KeyButtonData::Key { vk, pressed }) => {
data.key_click();
data.key_click(&app.session);
app.hid_provider.send_key(*vk as _, true);
*pressed = true;
}
@@ -145,12 +145,12 @@ fn key_press(
}) => {
*sticky = data.modifiers & *modifier == 0;
data.modifiers |= *modifier;
data.key_click();
data.key_click(&app.session);
app.hid_provider.set_modifiers(data.modifiers);
*pressed = true;
}
Some(KeyButtonData::Macro { verbs }) => {
data.key_click();
data.key_click(&app.session);
for (vk, press) in verbs {
app.hid_provider.send_key(*vk as _, *press);
}
@@ -160,7 +160,7 @@ fn key_press(
data.processes
.retain_mut(|child| !matches!(child.try_wait(), Ok(Some(_))));
data.key_click();
data.key_click(&app.session);
if let Ok(child) = Command::new(program).args(args).spawn() {
data.processes.push(child);
}
@@ -210,19 +210,31 @@ struct KeyboardData {
modifiers: KeyModifier,
processes: Vec<Child>,
audio_stream: Option<OutputStream>,
audio_handle: Option<OutputStreamHandle>,
first_try: bool,
}
impl KeyboardData {
fn key_click(&mut self) {
let wav = include_bytes!("../res/421581.wav");
let cursor = Cursor::new(wav);
let source = Decoder::new_wav(cursor).unwrap();
self.audio_stream = None;
if let Ok((stream, handle)) = OutputStream::try_default() {
fn key_click(&mut self, session: &AppSession) {
if !session.config.keyboard_sound_enabled {
return;
}
if self.audio_stream.is_none() && self.first_try {
self.first_try = false;
if let Ok((stream, handle)) = OutputStream::try_default() {
self.audio_stream = Some(stream);
self.audio_handle = Some(handle);
} else {
log::error!("Failed to open audio stream");
}
}
if let Some(handle) = &self.audio_handle {
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());
self.audio_stream = Some(stream);
} else {
log::error!("Failed to play key click");
}
}
}
@@ -246,18 +258,13 @@ enum KeyButtonData {
},
}
static KEYBOARD_YAML: Lazy<PathBuf> = Lazy::new(|| {
let home = &var("HOME").unwrap();
[home, ".config/wlxoverlay/keyboard.yaml"].iter().collect() //TODO other paths
});
static LAYOUT: Lazy<Layout> = Lazy::new(Layout::load_from_disk);
static MACRO_REGEX: Lazy<Regex> =
Lazy::new(|| Regex::new(r"^([A-Za-z0-1_-]+)(?: +(UP|DOWN))?$").unwrap());
#[derive(Debug, Deserialize, Serialize)]
struct Layout {
pub struct Layout {
name: String,
row_size: f32,
key_sizes: Vec<Vec<f32>>,
@@ -269,16 +276,8 @@ struct Layout {
impl Layout {
fn load_from_disk() -> Layout {
let mut yaml = fs::read_to_string(KEYBOARD_YAML.as_path()).ok();
if yaml.is_none() {
yaml = Some(include_str!("../res/keyboard.yaml").to_string());
}
let mut layout: Layout =
serde_yaml::from_str(&yaml.unwrap()).expect("Failed to parse keyboard.yaml");
let mut layout = config::load_keyboard();
layout.post_load();
layout
}

View File

@@ -1,11 +1,14 @@
use core::slice;
use serde::{Deserialize, Serialize};
use std::{
collections::HashMap,
error::Error,
f32::consts::PI,
path::Path,
ops::Deref,
path::PathBuf,
ptr,
sync::{mpsc::Receiver, Arc},
time::{Duration, Instant},
usize,
};
use vulkano::{
buffer::Subbuffer,
@@ -30,6 +33,8 @@ use crate::{
input::{InteractionHandler, PointerHit, PointerMode},
overlay::{OverlayData, OverlayRenderer, OverlayState, SplitOverlayBackend},
},
config::def_pw_tokens,
config_io,
graphics::{fourcc_to_vk, Vert2Uv, WlxGraphics, WlxPipeline},
hid::{MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT},
state::{AppSession, AppState},
@@ -79,9 +84,6 @@ impl InteractionHandler for ScreenInteractionHandler {
}
}
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) {
let pos = self.mouse_transform.transform_point2(hit.uv);
app.hid_provider.mouse_move(pos);
let btn = match hit.mode {
PointerMode::Right => MOUSE_RIGHT,
PointerMode::Middle => MOUSE_MIDDLE,
@@ -89,11 +91,14 @@ impl InteractionHandler for ScreenInteractionHandler {
};
if pressed {
self.next_move =
Instant::now() + Duration::from_millis(app.session.click_freeze_time_ms);
self.next_move = Instant::now()
+ Duration::from_millis(app.session.config.click_freeze_time_ms as u64);
}
app.hid_provider.send_button(btn, pressed);
let pos = self.mouse_transform.transform_point2(hit.uv);
app.hid_provider.mouse_move(pos);
}
fn on_scroll(&mut self, app: &mut AppState, _hit: &PointerHit, delta: f32) {
let millis = (1. - delta.abs()) * delta;
@@ -342,7 +347,12 @@ impl OverlayRenderer for ScreenRenderer {
}
}
fn try_create_screen<O>(wl: &WlxClient, id: u32, session: &AppSession) -> Option<OverlayData<O>>
fn try_create_screen<O>(
wl: &WlxClient,
id: u32,
pw_token_store: &mut HashMap<String, String>,
session: &AppSession,
) -> Option<OverlayData<O>>
where
O: Default,
{
@@ -366,9 +376,18 @@ where
if capture.is_none() {
log::info!("{}: Using Pipewire capture", &output.name);
let file_name = format!("{}.token", &output.name);
let full_path = Path::new(&session.config_path).join(file_name);
let token = std::fs::read_to_string(full_path).ok();
let display_name = output.name.deref();
// Find existing token by display
let token = pw_token_store.get(display_name).map(|s| s.as_str());
if let Some(t) = token {
println!(
"Found existing Pipewire token for display {}: {}",
display_name, t
);
}
capture = ScreenRenderer::new_pw(
output,
@@ -416,7 +435,7 @@ where
want_visible: session.show_screens.iter().any(|s| s == &*output.name),
show_hide: true,
grabbable: true,
spawn_scale: 1.5,
spawn_scale: 1.5 * session.config.desktop_view_scale,
spawn_point: vec3a(0., 0.5, -1.),
spawn_rotation: Quat::from_axis_angle(axis, angle),
interaction_transform,
@@ -431,6 +450,44 @@ where
}
}
#[derive(Deserialize, Serialize, Default)]
pub struct TokenConf {
#[serde(default = "def_pw_tokens")]
pub pw_tokens: Vec<(String, String)>,
}
fn get_pw_token_path() -> PathBuf {
let mut path = config_io::get_conf_d_path();
path.push("pw_tokens.yaml");
path
}
pub fn save_pw_token_config(tokens: &HashMap<String, String>) -> Result<(), Box<dyn Error>> {
let mut conf = TokenConf::default();
for (name, token) in tokens {
conf.pw_tokens.push((name.clone(), token.clone()));
}
let yaml = serde_yaml::to_string(&conf)?;
std::fs::write(get_pw_token_path(), yaml)?;
Ok(())
}
pub fn load_pw_token_config() -> Result<HashMap<String, String>, Box<dyn Error>> {
let mut map: HashMap<String, String> = HashMap::new();
let yaml = std::fs::read_to_string(get_pw_token_path())?;
let conf: TokenConf = serde_yaml::from_str(yaml.as_str())?;
for (name, token) in conf.pw_tokens {
map.insert(name, token);
}
Ok(map)
}
pub fn get_screens_wayland<O>(session: &AppSession) -> (Vec<OverlayData<O>>, Vec2)
where
O: Default,
@@ -438,11 +495,28 @@ where
let mut overlays = vec![];
let wl = WlxClient::new().unwrap();
// Load existing Pipewire tokens from file
let mut pw_tokens: HashMap<String, String> = if let Ok(conf) = load_pw_token_config() {
conf
} else {
HashMap::new()
};
let pw_tokens_copy = pw_tokens.clone();
for id in wl.outputs.keys() {
if let Some(overlay) = try_create_screen(&wl, *id, &session) {
if let Some(overlay) = try_create_screen(&wl, *id, &mut pw_tokens, session) {
overlays.push(overlay);
}
}
if pw_tokens_copy != pw_tokens {
// Token list changed, re-create token config file
if let Err(err) = save_pw_token_config(&pw_tokens) {
log::error!("Failed to save Pipewire token config: {}", err);
}
}
let extent = wl.get_desktop_extent();
(overlays, Vec2::new(extent.0 as f32, extent.1 as f32))
}

View File

@@ -169,7 +169,7 @@ where
name: "Watch".into(),
size: (400, 200),
want_visible: true,
spawn_scale: 0.065,
spawn_scale: 0.065 * state.session.config.watch_scale,
spawn_point: state.session.watch_pos.into(),
spawn_rotation: state.session.watch_rot,
interaction_transform,