From ab560485743d41eb390caf046f0bb3a9d1bb830a Mon Sep 17 00:00:00 2001 From: Alexander Mohr Date: Fri, 16 May 2025 22:31:58 +0200 Subject: [PATCH] add password + enter for worf warden --- examples/worf-warden/src/main.rs | 47 +++++++++++++----- worf/src/lib/gui.rs | 81 +++++++++++++++++--------------- worf/src/lib/modes/auto.rs | 12 +---- 3 files changed, 79 insertions(+), 61 deletions(-) diff --git a/examples/worf-warden/src/main.rs b/examples/worf-warden/src/main.rs index 13c2b41..fbc64b0 100644 --- a/examples/worf-warden/src/main.rs +++ b/examples/worf-warden/src/main.rs @@ -44,7 +44,7 @@ impl PasswordProvider { key.clone(), None, None, - vec![], + vec![].into_iter().collect(), None, 0.0, Some(MenuItemMetaData { ids: value.clone() }), @@ -59,7 +59,7 @@ impl PasswordProvider { format!("Error from rbw: {error}"), None, None, - vec![], + vec![].into_iter().collect(), None, 0.0, None, @@ -79,11 +79,11 @@ impl PasswordProvider { rbw_get_user(id, false)?, None, None, - vec![], + vec![].into_iter().collect(), None, 0.0, Some(MenuItemMetaData { - ids: vec![id.clone()], + ids: vec![id.clone()].into_iter().collect(), }), )) }) @@ -125,7 +125,16 @@ fn keyboard_type(text: &str) { fn keyboard_tab() { Command::new("ydotool") - .arg("TAB") + .arg("type") + .arg("\t") + .output() + .expect("Failed to execute ydotool"); +} + +fn keyboard_return() { + Command::new("ydotool") + .arg("type") + .arg("\n") .output() .expect("Failed to execute ydotool"); } @@ -178,7 +187,7 @@ fn rbw_get_totp(id: &str, copy: bool) -> Result { fn key_type_all() -> KeyBinding { KeyBinding { key: Key::Num1, - modifiers: Modifier::Alt, + modifiers: vec![Modifier::Alt].into_iter().collect(), label: "Alt+1 Type All".to_string(), } } @@ -186,7 +195,7 @@ fn key_type_all() -> KeyBinding { fn key_type_user() -> KeyBinding { KeyBinding { key: Key::Num2, - modifiers: Modifier::Alt, + modifiers: vec![Modifier::Alt].into_iter().collect(), label: "Alt+2 Type User".to_string(), } } @@ -194,15 +203,23 @@ fn key_type_user() -> KeyBinding { fn key_type_password() -> KeyBinding { KeyBinding { key: Key::Num3, - modifiers: Modifier::Alt, + modifiers: vec![Modifier::Alt].into_iter().collect(), label: "Alt+3 Type Password".to_string(), } } +fn key_type_password_and_enter() -> KeyBinding { + KeyBinding { + key: Key::Hash, + modifiers: vec![Modifier::Alt, Modifier::Shift].into_iter().collect(), + label: "Alt+Shift+3 Type Password + Enter".to_string(), + } +} + fn key_type_totp() -> KeyBinding { KeyBinding { key: Key::Num4, - modifiers: Modifier::Alt, + modifiers: vec![Modifier::Alt].into_iter().collect(), label: "Alt+4 Type Totp".to_string(), } } @@ -210,7 +227,7 @@ fn key_type_totp() -> KeyBinding { fn key_sync() -> KeyBinding { KeyBinding { key: Key::R, - modifiers: Modifier::Alt, + modifiers: vec![Modifier::Alt].into_iter().collect(), label: "Alt+r Sync".to_string(), } } @@ -219,7 +236,7 @@ fn key_sync() -> KeyBinding { fn key_totp() -> KeyBinding { KeyBinding { key: Key::T, - modifiers: Modifier::Alt, + modifiers: vec![Modifier::Alt].into_iter().collect(), label: "Alt+t Totp".to_string(), } } @@ -227,7 +244,7 @@ fn key_totp() -> KeyBinding { fn key_lock() -> KeyBinding { KeyBinding { key: Key::L, - modifiers: Modifier::Alt, + modifiers: vec![Modifier::Alt].into_iter().collect(), label: "Alt+l Lock".to_string(), } } @@ -242,6 +259,7 @@ fn show(config: Config, provider: PasswordProvider) -> Result<(), String> { key_type_all(), key_type_user(), key_type_password(), + key_type_password_and_enter(), key_type_totp(), key_sync(), key_totp(), @@ -256,7 +274,7 @@ fn show(config: Config, provider: PasswordProvider) -> Result<(), String> { let id = meta.ids.first().unwrap_or(&selection.menu.label); - sleep(Duration::from_millis(250)); + sleep(Duration::from_millis(500)); if let Some(key) = selection.custom_key { if key == key_type_all() { keyboard_type(&rbw_get_user(id, false)?); @@ -266,6 +284,9 @@ fn show(config: Config, provider: PasswordProvider) -> Result<(), String> { keyboard_type(&rbw_get_user(id, false)?); } else if key == key_type_password() { keyboard_type(&rbw_get_password(id, false)?); + } else if key == key_type_password_and_enter() { + keyboard_type(&rbw_get_password(id, false)?); + keyboard_return(); } else if key == key_type_totp() { keyboard_type(&rbw_get_totp(id, false)?); } else if key == key_lock() { diff --git a/worf/src/lib/gui.rs b/worf/src/lib/gui.rs index a5a0d30..a472693 100644 --- a/worf/src/lib/gui.rs +++ b/worf/src/lib/gui.rs @@ -1,12 +1,11 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::rc::Rc; use std::sync::{Arc, Mutex}; use std::thread; -use std::time::{Duration, Instant}; +use std::time::Instant; use crossbeam::channel; use crossbeam::channel::Sender; -use crossbeam::channel::internal::SelectHandle; use gdk4::Display; use gdk4::gio::File; use gdk4::glib::{MainContext, Propagation}; @@ -339,24 +338,39 @@ pub enum Modifier { None, } -impl From for Modifier { - fn from(value: gdk4::ModifierType) -> Self { - match value { - gdk4::ModifierType::SHIFT_MASK => Modifier::Shift, - gdk4::ModifierType::CONTROL_MASK => Modifier::Control, - gdk4::ModifierType::ALT_MASK => Modifier::Alt, - gdk4::ModifierType::SUPER_MASK => Modifier::Super, - gdk4::ModifierType::META_MASK => Modifier::Meta, - gdk4::ModifierType::LOCK_MASK => Modifier::CapsLock, - _ => Modifier::None, - } +fn modifiers_from_mask(mask: gdk4::ModifierType) -> HashSet { + let mut modifiers = HashSet::new(); + + if mask.contains(gdk4::ModifierType::SHIFT_MASK) { + modifiers.insert(Modifier::Shift); } + if mask.contains(gdk4::ModifierType::CONTROL_MASK) { + modifiers.insert(Modifier::Control); + } + if mask.contains(gdk4::ModifierType::ALT_MASK) { + modifiers.insert(Modifier::Alt); + } + if mask.contains(gdk4::ModifierType::SUPER_MASK) { + modifiers.insert(Modifier::Super); + } + if mask.contains(gdk4::ModifierType::META_MASK) { + modifiers.insert(Modifier::Meta); + } + if mask.contains(gdk4::ModifierType::LOCK_MASK) { + modifiers.insert(Modifier::CapsLock); + } + + if modifiers.is_empty() { + modifiers.insert(Modifier::None); + } + + modifiers } -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Debug)] pub struct KeyBinding { pub key: Key, - pub modifiers: Modifier, // todo support masks + pub modifiers: HashSet, pub label: String, } @@ -566,22 +580,19 @@ fn build_ui( let (_changed, provider_elements) = get_provider_elements.join().unwrap(); log::debug!("got items after {:?}", wait_for_items.elapsed()); - let animate_cfg = config.clone(); + let active_cfg = config.clone(); + let map_cfg = config.clone(); let animate_window = ui_elements.window.clone(); - let (sender, receiver) = channel::bounded(1); animate_window.connect_is_active_notify(move |w| { - w.set_opacity(1.0); - window_show_resize(&animate_cfg.clone(), w); - if let Err(e) = sender.send(()) { - log::debug!("cannot unblock menu builder {e:?}"); - } + window_show_resize(&active_cfg.clone(), w); + }); + animate_window.connect_map(move |w| { + window_show_resize(&map_cfg.clone(), w); }); - build_ui_from_menu_items(&ui_elements, &meta, provider_elements, Some(receiver)); + build_ui_from_menu_items(&ui_elements, &meta, provider_elements); - // hide the fact that we are starting with a small window - ui_elements.window.set_opacity(0.01); let window_start = Instant::now(); ui_elements.window.present(); log::debug!("window show took {:?}", window_start.elapsed()); @@ -685,7 +696,6 @@ fn build_ui_from_menu_items( ui: &Rc>, meta: &Rc>, mut items: Vec>, - wait_for_signal: Option>, ) { let start = Instant::now(); { @@ -699,12 +709,6 @@ fn build_ui_from_menu_items( let ui_clone = Rc::>::clone(ui); glib::idle_add_local(move || { - if let Some(wait) = &wait_for_signal { - if !wait.is_ready() { - return ControlFlow::Continue; - } - } - ui_clone.main_box.unset_sort_func(); let mut done = false; { @@ -797,15 +801,18 @@ fn handle_key_press( let update_view_from_provider = |query: &String| { let (changed, filtered_list) = meta.item_provider.lock().unwrap().get_elements(Some(query)); if changed { - build_ui_from_menu_items(ui, meta, filtered_list, None); + build_ui_from_menu_items(ui, meta, filtered_list); } update_view(query); }; if let Some(custom_keys) = custom_keys { + let mods = modifiers_from_mask(modifier_type); for custom_key in custom_keys { - if custom_key.key == keyboard_key.into() && custom_key.modifiers == modifier_type.into() - { + log::debug!( + "comparing custom key {custom_key:?} to mask {mods:?} and key {keyboard_key}" + ); + if custom_key.key == keyboard_key.into() && mods.is_subset(&custom_key.modifiers) { let search_lock = ui.search_text.lock().unwrap(); if let Err(e) = handle_selected_item( ui, @@ -874,7 +881,7 @@ fn handle_key_press( if let Some(changed) = opt_changed { let items = changed.0.1.unwrap_or_default(); if changed.0.0 { - build_ui_from_menu_items(ui, meta, items, None); + build_ui_from_menu_items(ui, meta, items); } let query = changed.1; diff --git a/worf/src/lib/modes/auto.rs b/worf/src/lib/modes/auto.rs index 9943eff..a223bed 100644 --- a/worf/src/lib/modes/auto.rs +++ b/worf/src/lib/modes/auto.rs @@ -1,8 +1,7 @@ use crate::config::Config; -use crate::desktop::{copy_to_clipboard, spawn_fork}; +use crate::desktop::spawn_fork; use crate::gui::{ItemProvider, MenuItem}; use crate::modes::drun::{DRunProvider, update_drun_cache_and_run}; -use crate::modes::emoji::EmojiProvider; use crate::modes::file::FileItemProvider; use crate::modes::math::MathProvider; use crate::modes::ssh; @@ -16,7 +15,6 @@ enum AutoRunType { DRun, File, Ssh, - Emoji, // WebSearch, } @@ -152,14 +150,6 @@ pub fn show(config: &Config) -> Result<(), Error> { ssh::launch(&selection_result, config)?; break; } - AutoRunType::Emoji => { - if let Some(action) = selection_result.action { - copy_to_clipboard(action, None)?; - } else { - return Err(Error::MissingAction); - } - break; - } } } else if selection_result.label.starts_with("ssh") { selection_result.label = selection_result.label.chars().skip(4).collect();