add password + enter for worf warden
This commit is contained in:
parent
6632f2f123
commit
ab56048574
3 changed files with 79 additions and 61 deletions
|
@ -44,7 +44,7 @@ impl PasswordProvider {
|
||||||
key.clone(),
|
key.clone(),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
vec![],
|
vec![].into_iter().collect(),
|
||||||
None,
|
None,
|
||||||
0.0,
|
0.0,
|
||||||
Some(MenuItemMetaData { ids: value.clone() }),
|
Some(MenuItemMetaData { ids: value.clone() }),
|
||||||
|
@ -59,7 +59,7 @@ impl PasswordProvider {
|
||||||
format!("Error from rbw: {error}"),
|
format!("Error from rbw: {error}"),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
vec![],
|
vec![].into_iter().collect(),
|
||||||
None,
|
None,
|
||||||
0.0,
|
0.0,
|
||||||
None,
|
None,
|
||||||
|
@ -79,11 +79,11 @@ impl PasswordProvider {
|
||||||
rbw_get_user(id, false)?,
|
rbw_get_user(id, false)?,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
vec![],
|
vec![].into_iter().collect(),
|
||||||
None,
|
None,
|
||||||
0.0,
|
0.0,
|
||||||
Some(MenuItemMetaData {
|
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() {
|
fn keyboard_tab() {
|
||||||
Command::new("ydotool")
|
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()
|
.output()
|
||||||
.expect("Failed to execute ydotool");
|
.expect("Failed to execute ydotool");
|
||||||
}
|
}
|
||||||
|
@ -178,7 +187,7 @@ fn rbw_get_totp(id: &str, copy: bool) -> Result<String, String> {
|
||||||
fn key_type_all() -> KeyBinding {
|
fn key_type_all() -> KeyBinding {
|
||||||
KeyBinding {
|
KeyBinding {
|
||||||
key: Key::Num1,
|
key: Key::Num1,
|
||||||
modifiers: Modifier::Alt,
|
modifiers: vec![Modifier::Alt].into_iter().collect(),
|
||||||
label: "<b>Alt+1</b> Type All".to_string(),
|
label: "<b>Alt+1</b> Type All".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,7 +195,7 @@ fn key_type_all() -> KeyBinding {
|
||||||
fn key_type_user() -> KeyBinding {
|
fn key_type_user() -> KeyBinding {
|
||||||
KeyBinding {
|
KeyBinding {
|
||||||
key: Key::Num2,
|
key: Key::Num2,
|
||||||
modifiers: Modifier::Alt,
|
modifiers: vec![Modifier::Alt].into_iter().collect(),
|
||||||
label: "<b>Alt+2</b> Type User".to_string(),
|
label: "<b>Alt+2</b> Type User".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,15 +203,23 @@ fn key_type_user() -> KeyBinding {
|
||||||
fn key_type_password() -> KeyBinding {
|
fn key_type_password() -> KeyBinding {
|
||||||
KeyBinding {
|
KeyBinding {
|
||||||
key: Key::Num3,
|
key: Key::Num3,
|
||||||
modifiers: Modifier::Alt,
|
modifiers: vec![Modifier::Alt].into_iter().collect(),
|
||||||
label: "<b>Alt+3</b> Type Password".to_string(),
|
label: "<b>Alt+3</b> 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: "<b>Alt+Shift+3</b> Type Password + Enter".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn key_type_totp() -> KeyBinding {
|
fn key_type_totp() -> KeyBinding {
|
||||||
KeyBinding {
|
KeyBinding {
|
||||||
key: Key::Num4,
|
key: Key::Num4,
|
||||||
modifiers: Modifier::Alt,
|
modifiers: vec![Modifier::Alt].into_iter().collect(),
|
||||||
label: "<b>Alt+4</b> Type Totp".to_string(),
|
label: "<b>Alt+4</b> Type Totp".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,7 +227,7 @@ fn key_type_totp() -> KeyBinding {
|
||||||
fn key_sync() -> KeyBinding {
|
fn key_sync() -> KeyBinding {
|
||||||
KeyBinding {
|
KeyBinding {
|
||||||
key: Key::R,
|
key: Key::R,
|
||||||
modifiers: Modifier::Alt,
|
modifiers: vec![Modifier::Alt].into_iter().collect(),
|
||||||
label: "<b>Alt+r</b> Sync".to_string(),
|
label: "<b>Alt+r</b> Sync".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,7 +236,7 @@ fn key_sync() -> KeyBinding {
|
||||||
fn key_totp() -> KeyBinding {
|
fn key_totp() -> KeyBinding {
|
||||||
KeyBinding {
|
KeyBinding {
|
||||||
key: Key::T,
|
key: Key::T,
|
||||||
modifiers: Modifier::Alt,
|
modifiers: vec![Modifier::Alt].into_iter().collect(),
|
||||||
label: "<b>Alt+t</b> Totp".to_string(),
|
label: "<b>Alt+t</b> Totp".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -227,7 +244,7 @@ fn key_totp() -> KeyBinding {
|
||||||
fn key_lock() -> KeyBinding {
|
fn key_lock() -> KeyBinding {
|
||||||
KeyBinding {
|
KeyBinding {
|
||||||
key: Key::L,
|
key: Key::L,
|
||||||
modifiers: Modifier::Alt,
|
modifiers: vec![Modifier::Alt].into_iter().collect(),
|
||||||
label: "<b>Alt+l</b> Lock".to_string(),
|
label: "<b>Alt+l</b> Lock".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -242,6 +259,7 @@ fn show(config: Config, provider: PasswordProvider) -> Result<(), String> {
|
||||||
key_type_all(),
|
key_type_all(),
|
||||||
key_type_user(),
|
key_type_user(),
|
||||||
key_type_password(),
|
key_type_password(),
|
||||||
|
key_type_password_and_enter(),
|
||||||
key_type_totp(),
|
key_type_totp(),
|
||||||
key_sync(),
|
key_sync(),
|
||||||
key_totp(),
|
key_totp(),
|
||||||
|
@ -256,7 +274,7 @@ fn show(config: Config, provider: PasswordProvider) -> Result<(), String> {
|
||||||
|
|
||||||
let id = meta.ids.first().unwrap_or(&selection.menu.label);
|
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 let Some(key) = selection.custom_key {
|
||||||
if key == key_type_all() {
|
if key == key_type_all() {
|
||||||
keyboard_type(&rbw_get_user(id, false)?);
|
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)?);
|
keyboard_type(&rbw_get_user(id, false)?);
|
||||||
} else if key == key_type_password() {
|
} else if key == key_type_password() {
|
||||||
keyboard_type(&rbw_get_password(id, false)?);
|
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() {
|
} else if key == key_type_totp() {
|
||||||
keyboard_type(&rbw_get_totp(id, false)?);
|
keyboard_type(&rbw_get_totp(id, false)?);
|
||||||
} else if key == key_lock() {
|
} else if key == key_lock() {
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::Instant;
|
||||||
|
|
||||||
use crossbeam::channel;
|
use crossbeam::channel;
|
||||||
use crossbeam::channel::Sender;
|
use crossbeam::channel::Sender;
|
||||||
use crossbeam::channel::internal::SelectHandle;
|
|
||||||
use gdk4::Display;
|
use gdk4::Display;
|
||||||
use gdk4::gio::File;
|
use gdk4::gio::File;
|
||||||
use gdk4::glib::{MainContext, Propagation};
|
use gdk4::glib::{MainContext, Propagation};
|
||||||
|
@ -339,24 +338,39 @@ pub enum Modifier {
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<gdk4::ModifierType> for Modifier {
|
fn modifiers_from_mask(mask: gdk4::ModifierType) -> HashSet<Modifier> {
|
||||||
fn from(value: gdk4::ModifierType) -> Self {
|
let mut modifiers = HashSet::new();
|
||||||
match value {
|
|
||||||
gdk4::ModifierType::SHIFT_MASK => Modifier::Shift,
|
if mask.contains(gdk4::ModifierType::SHIFT_MASK) {
|
||||||
gdk4::ModifierType::CONTROL_MASK => Modifier::Control,
|
modifiers.insert(Modifier::Shift);
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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 struct KeyBinding {
|
||||||
pub key: Key,
|
pub key: Key,
|
||||||
pub modifiers: Modifier, // todo support masks
|
pub modifiers: HashSet<Modifier>,
|
||||||
pub label: String,
|
pub label: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,22 +580,19 @@ fn build_ui<T, P>(
|
||||||
let (_changed, provider_elements) = get_provider_elements.join().unwrap();
|
let (_changed, provider_elements) = get_provider_elements.join().unwrap();
|
||||||
log::debug!("got items after {:?}", wait_for_items.elapsed());
|
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 animate_window = ui_elements.window.clone();
|
||||||
|
|
||||||
let (sender, receiver) = channel::bounded(1);
|
|
||||||
animate_window.connect_is_active_notify(move |w| {
|
animate_window.connect_is_active_notify(move |w| {
|
||||||
w.set_opacity(1.0);
|
window_show_resize(&active_cfg.clone(), w);
|
||||||
window_show_resize(&animate_cfg.clone(), w);
|
});
|
||||||
if let Err(e) = sender.send(()) {
|
animate_window.connect_map(move |w| {
|
||||||
log::debug!("cannot unblock menu builder {e:?}");
|
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();
|
let window_start = Instant::now();
|
||||||
ui_elements.window.present();
|
ui_elements.window.present();
|
||||||
log::debug!("window show took {:?}", window_start.elapsed());
|
log::debug!("window show took {:?}", window_start.elapsed());
|
||||||
|
@ -685,7 +696,6 @@ fn build_ui_from_menu_items<T: Clone + 'static + Send>(
|
||||||
ui: &Rc<UiElements<T>>,
|
ui: &Rc<UiElements<T>>,
|
||||||
meta: &Rc<MetaData<T>>,
|
meta: &Rc<MetaData<T>>,
|
||||||
mut items: Vec<MenuItem<T>>,
|
mut items: Vec<MenuItem<T>>,
|
||||||
wait_for_signal: Option<channel::Receiver<()>>,
|
|
||||||
) {
|
) {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
{
|
{
|
||||||
|
@ -699,12 +709,6 @@ fn build_ui_from_menu_items<T: Clone + 'static + Send>(
|
||||||
let ui_clone = Rc::<UiElements<T>>::clone(ui);
|
let ui_clone = Rc::<UiElements<T>>::clone(ui);
|
||||||
|
|
||||||
glib::idle_add_local(move || {
|
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();
|
ui_clone.main_box.unset_sort_func();
|
||||||
let mut done = false;
|
let mut done = false;
|
||||||
{
|
{
|
||||||
|
@ -797,15 +801,18 @@ fn handle_key_press<T: Clone + 'static + Send>(
|
||||||
let update_view_from_provider = |query: &String| {
|
let update_view_from_provider = |query: &String| {
|
||||||
let (changed, filtered_list) = meta.item_provider.lock().unwrap().get_elements(Some(query));
|
let (changed, filtered_list) = meta.item_provider.lock().unwrap().get_elements(Some(query));
|
||||||
if changed {
|
if changed {
|
||||||
build_ui_from_menu_items(ui, meta, filtered_list, None);
|
build_ui_from_menu_items(ui, meta, filtered_list);
|
||||||
}
|
}
|
||||||
update_view(query);
|
update_view(query);
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(custom_keys) = custom_keys {
|
if let Some(custom_keys) = custom_keys {
|
||||||
|
let mods = modifiers_from_mask(modifier_type);
|
||||||
for custom_key in custom_keys {
|
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();
|
let search_lock = ui.search_text.lock().unwrap();
|
||||||
if let Err(e) = handle_selected_item(
|
if let Err(e) = handle_selected_item(
|
||||||
ui,
|
ui,
|
||||||
|
@ -874,7 +881,7 @@ fn handle_key_press<T: Clone + 'static + Send>(
|
||||||
if let Some(changed) = opt_changed {
|
if let Some(changed) = opt_changed {
|
||||||
let items = changed.0.1.unwrap_or_default();
|
let items = changed.0.1.unwrap_or_default();
|
||||||
if changed.0.0 {
|
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;
|
let query = changed.1;
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::desktop::{copy_to_clipboard, spawn_fork};
|
use crate::desktop::spawn_fork;
|
||||||
use crate::gui::{ItemProvider, MenuItem};
|
use crate::gui::{ItemProvider, MenuItem};
|
||||||
use crate::modes::drun::{DRunProvider, update_drun_cache_and_run};
|
use crate::modes::drun::{DRunProvider, update_drun_cache_and_run};
|
||||||
use crate::modes::emoji::EmojiProvider;
|
|
||||||
use crate::modes::file::FileItemProvider;
|
use crate::modes::file::FileItemProvider;
|
||||||
use crate::modes::math::MathProvider;
|
use crate::modes::math::MathProvider;
|
||||||
use crate::modes::ssh;
|
use crate::modes::ssh;
|
||||||
|
@ -16,7 +15,6 @@ enum AutoRunType {
|
||||||
DRun,
|
DRun,
|
||||||
File,
|
File,
|
||||||
Ssh,
|
Ssh,
|
||||||
Emoji,
|
|
||||||
// WebSearch,
|
// WebSearch,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,14 +150,6 @@ pub fn show(config: &Config) -> Result<(), Error> {
|
||||||
ssh::launch(&selection_result, config)?;
|
ssh::launch(&selection_result, config)?;
|
||||||
break;
|
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") {
|
} else if selection_result.label.starts_with("ssh") {
|
||||||
selection_result.label = selection_result.label.chars().skip(4).collect();
|
selection_result.label = selection_result.label.chars().skip(4).collect();
|
||||||
|
|
Loading…
Add table
Reference in a new issue