add key handling by code
This commit is contained in:
parent
f0f9b83270
commit
22458ddd4a
4 changed files with 163 additions and 21 deletions
|
@ -55,6 +55,15 @@ pub enum CustomKeyHintLocation {
|
|||
Bottom,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
|
||||
pub enum KeyDetectionType {
|
||||
/// Raw keyboard value, might not be correct all layouts
|
||||
Code,
|
||||
/// The value of the key, but note that shift+3 != 3 (as shift+3 = #)
|
||||
Value,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum Mode {
|
||||
/// searches `$PATH` for executables and allows them to be run by selecting them.
|
||||
|
@ -151,6 +160,20 @@ impl FromStr for SortOrder {
|
|||
}
|
||||
}
|
||||
|
||||
impl FromStr for KeyDetectionType {
|
||||
type Err = ArgsError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"value" => Ok(KeyDetectionType::Value),
|
||||
"code" => Ok(KeyDetectionType::Code),
|
||||
_ => Err(ArgsError::InvalidParameter(
|
||||
format!("{s} is not a valid argument, see help for details").to_owned(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, Parser)]
|
||||
#[clap(about = "Worf is a wofi clone written in rust, it aims to be a drop-in replacement")]
|
||||
#[derive(Default)]
|
||||
|
@ -161,7 +184,7 @@ pub struct Config {
|
|||
|
||||
/// Selects a config file to use
|
||||
#[clap(short = 'c', long = "conf")]
|
||||
config: Option<String>,
|
||||
cfg_path: Option<String>,
|
||||
|
||||
/// Prints the version and then exits
|
||||
#[clap(short = 'v', long = "version")]
|
||||
|
@ -329,7 +352,7 @@ pub struct Config {
|
|||
|
||||
/// Orientation of items in the row box where items are displayed
|
||||
#[clap(long = "row-box-orientation")]
|
||||
row_bow_orientation: Option<Orientation>,
|
||||
row_box_orientation: Option<Orientation>,
|
||||
|
||||
#[clap(long = "line-wrap")]
|
||||
line_wrap: Option<WrapMode>,
|
||||
|
@ -337,6 +360,9 @@ pub struct Config {
|
|||
/// Display only icon in emoji mode
|
||||
#[clap(long = "emoji-hide-string")]
|
||||
emoji_hide_label: Option<bool>,
|
||||
|
||||
#[clap(long = "keyboard-detection-type")]
|
||||
key_detection_type: Option<KeyDetectionType>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
|
@ -438,7 +464,7 @@ impl Config {
|
|||
|
||||
#[must_use]
|
||||
pub fn row_bow_orientation(&self) -> Orientation {
|
||||
self.row_bow_orientation.unwrap_or(Orientation::Horizontal)
|
||||
self.row_box_orientation.unwrap_or(Orientation::Horizontal)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
@ -519,6 +545,13 @@ impl Config {
|
|||
pub fn emoji_hide_label(&self) -> bool {
|
||||
self.emoji_hide_label.unwrap_or(false)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn key_detection_type(&self) -> KeyDetectionType {
|
||||
self.key_detection_type
|
||||
.clone()
|
||||
.unwrap_or(KeyDetectionType::Value)
|
||||
}
|
||||
}
|
||||
|
||||
fn default_false() -> bool {
|
||||
|
@ -672,7 +705,7 @@ pub fn resolve_path(
|
|||
/// * no config file exists
|
||||
/// * config file and args cannot be merged
|
||||
pub fn load_config(args_opt: Option<&Config>) -> Result<Config, Error> {
|
||||
let config_path = conf_path(args_opt.as_ref().and_then(|c| c.config.as_ref()));
|
||||
let config_path = conf_path(args_opt.as_ref().and_then(|c| c.cfg_path.as_ref()));
|
||||
match config_path {
|
||||
Ok(path) => {
|
||||
let toml_content = fs::read_to_string(path).map_err(|e| Error::Io(format!("{e}")))?;
|
||||
|
|
|
@ -25,7 +25,9 @@ use gtk4_layer_shell::{Edge, KeyboardMode, LayerShell};
|
|||
use log;
|
||||
use regex::Regex;
|
||||
|
||||
use crate::config::{Anchor, Config, CustomKeyHintLocation, MatchMethod, SortOrder, WrapMode};
|
||||
use crate::config::{
|
||||
Anchor, Config, CustomKeyHintLocation, KeyDetectionType, MatchMethod, SortOrder, WrapMode,
|
||||
};
|
||||
use crate::desktop::known_image_extension_regex_pattern;
|
||||
use crate::{Error, config, desktop};
|
||||
|
||||
|
@ -335,6 +337,109 @@ impl From<gdk::Key> for Key {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<u32> for Key {
|
||||
fn from(value: u32) -> Self {
|
||||
match value {
|
||||
// Letters
|
||||
38 => Key::A,
|
||||
56 => Key::B,
|
||||
54 => Key::C,
|
||||
40 => Key::D,
|
||||
26 => Key::E,
|
||||
41 => Key::F,
|
||||
42 => Key::G,
|
||||
43 => Key::H,
|
||||
31 => Key::I,
|
||||
44 => Key::J,
|
||||
45 => Key::K,
|
||||
46 => Key::L,
|
||||
58 => Key::M,
|
||||
57 => Key::N,
|
||||
32 => Key::O,
|
||||
33 => Key::P,
|
||||
24 => Key::Q,
|
||||
27 => Key::R,
|
||||
39 => Key::S,
|
||||
28 => Key::T,
|
||||
30 => Key::U,
|
||||
55 => Key::V,
|
||||
25 => Key::W,
|
||||
53 => Key::X,
|
||||
29 => Key::Y,
|
||||
52 => Key::Z,
|
||||
|
||||
// Numbers
|
||||
10 => Key::Num0,
|
||||
11 => Key::Num1,
|
||||
12 => Key::Num2,
|
||||
13 => Key::Num3,
|
||||
14 => Key::Num4,
|
||||
15 => Key::Num5,
|
||||
16 => Key::Num6,
|
||||
17 => Key::Num7,
|
||||
18 => Key::Num8,
|
||||
19 => Key::Num9,
|
||||
|
||||
// Function Keys
|
||||
67 => Key::F1,
|
||||
68 => Key::F2,
|
||||
69 => Key::F3,
|
||||
70 => Key::F4,
|
||||
71 => Key::F5,
|
||||
72 => Key::F6,
|
||||
73 => Key::F7,
|
||||
74 => Key::F8,
|
||||
75 => Key::F9,
|
||||
76 => Key::F10,
|
||||
77 => Key::F11,
|
||||
78 => Key::F12,
|
||||
|
||||
// Navigation / Editing
|
||||
9 => Key::Escape,
|
||||
36 => Key::Enter,
|
||||
65 => Key::Space,
|
||||
23 => Key::Tab,
|
||||
22 => Key::Backspace,
|
||||
118 => Key::Insert,
|
||||
119 => Key::Delete,
|
||||
110 => Key::Home,
|
||||
115 => Key::End,
|
||||
112 => Key::PageUp,
|
||||
117 => Key::PageDown,
|
||||
113 => Key::Left,
|
||||
114 => Key::Right,
|
||||
111 => Key::Up,
|
||||
116 => Key::Down,
|
||||
|
||||
// Special characters
|
||||
20 => Key::Exclamation,
|
||||
63 => Key::At,
|
||||
3 => Key::Hash,
|
||||
4 => Key::Dollar,
|
||||
5 => Key::Percent,
|
||||
6 => Key::Caret,
|
||||
7 => Key::Ampersand,
|
||||
8 => Key::Asterisk,
|
||||
34 => Key::LeftParen,
|
||||
35 => Key::RightParen,
|
||||
48 => Key::Minus,
|
||||
47 => Key::Underscore,
|
||||
21 => Key::Equal,
|
||||
49 => Key::Plus,
|
||||
51 => Key::Backslash,
|
||||
94 => Key::Pipe,
|
||||
50 => Key::Quote,
|
||||
59 => Key::Comma,
|
||||
60 => Key::Period,
|
||||
61 => Key::Slash,
|
||||
62 => Key::Question,
|
||||
96 => Key::Grave,
|
||||
97 => Key::Tilde,
|
||||
_ => Key::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum Modifier {
|
||||
Shift,
|
||||
|
@ -771,8 +876,6 @@ fn build_ui_from_menu_items<T: Clone + 'static + Send>(
|
|||
let meta_clone = Rc::<MetaData<T>>::clone(meta);
|
||||
let ui_clone = Rc::<UiElements<T>>::clone(ui);
|
||||
|
||||
|
||||
|
||||
glib::idle_add_local(move || {
|
||||
let mut done = false;
|
||||
{
|
||||
|
@ -801,10 +904,9 @@ fn build_ui_from_menu_items<T: Clone + 'static + Send>(
|
|||
sort_flow_box_childs(child1, child2, &items_sort)
|
||||
});
|
||||
|
||||
|
||||
if done {
|
||||
let lock = ui_clone.menu_rows.read().unwrap();
|
||||
|
||||
|
||||
select_first_visible_child(&lock, &ui_clone.main_box);
|
||||
|
||||
log::debug!(
|
||||
|
@ -830,11 +932,12 @@ fn setup_key_event_handler<T: Clone + 'static + Send>(
|
|||
let ui_clone = Rc::clone(ui);
|
||||
let meta_clone = Rc::clone(meta);
|
||||
let keys_clone = custom_keys.cloned();
|
||||
key_controller.connect_key_pressed(move |_, key_value, _, modifier| {
|
||||
key_controller.connect_key_pressed(move |_, key_value, key_code, modifier| {
|
||||
handle_key_press(
|
||||
&ui_clone,
|
||||
&meta_clone,
|
||||
key_value,
|
||||
key_code,
|
||||
modifier,
|
||||
keys_clone.as_ref(),
|
||||
)
|
||||
|
@ -848,6 +951,7 @@ fn handle_key_press<T: Clone + 'static + Send>(
|
|||
ui: &Rc<UiElements<T>>,
|
||||
meta: &Rc<MetaData<T>>,
|
||||
keyboard_key: gdk4::Key,
|
||||
key_code: u32,
|
||||
modifier_type: gdk4::ModifierType,
|
||||
custom_keys: Option<&CustomKeys>,
|
||||
) -> Propagation {
|
||||
|
@ -873,10 +977,13 @@ fn handle_key_press<T: Clone + 'static + Send>(
|
|||
if let Some(custom_keys) = custom_keys {
|
||||
let mods = modifiers_from_mask(modifier_type);
|
||||
for custom_key in &custom_keys.bindings {
|
||||
log::debug!(
|
||||
"comparing custom key {custom_key:?} to mask {mods:?} and key {keyboard_key}"
|
||||
);
|
||||
if custom_key.key == keyboard_key.to_upper().into() && mods.is_subset(&custom_key.modifiers) {
|
||||
let custom_key_match = if meta.config.key_detection_type() == KeyDetectionType::Code {
|
||||
custom_key.key == key_code.into()
|
||||
} else {
|
||||
custom_key.key == keyboard_key.to_upper().into()
|
||||
} && mods.is_subset(&custom_key.modifiers);
|
||||
|
||||
if custom_key_match {
|
||||
let search_lock = ui.search_text.lock().unwrap();
|
||||
if let Err(e) = handle_selected_item(
|
||||
ui,
|
||||
|
|
|
@ -11,19 +11,22 @@ pub(crate) struct EmojiProvider<T: Clone> {
|
|||
}
|
||||
|
||||
impl<T: Clone> EmojiProvider<T> {
|
||||
pub(crate) fn new(data: T, sort_order: &SortOrder, hide_label: &bool) -> Self {
|
||||
pub(crate) fn new(data: T, sort_order: &SortOrder, hide_label: bool) -> Self {
|
||||
let emoji = emoji::search::search_annotation_all("");
|
||||
let mut menus = emoji
|
||||
.into_iter()
|
||||
.map(|e| {
|
||||
MenuItem::new(
|
||||
if *hide_label {
|
||||
e.glyph.to_string()
|
||||
if hide_label {
|
||||
e.glyph.to_string()
|
||||
} else {
|
||||
format!("{} — Category: {} — Name: {}", e.glyph, e.group, e.name)
|
||||
},
|
||||
None,
|
||||
Some(format!("emoji {} — Category: {} — Name: {}", e.glyph, e.group, e.name)),
|
||||
Some(format!(
|
||||
"emoji {} — Category: {} — Name: {}",
|
||||
e.glyph, e.group, e.name
|
||||
)),
|
||||
vec![],
|
||||
None,
|
||||
0.0,
|
||||
|
@ -55,7 +58,7 @@ impl<T: Clone> ItemProvider<T> for EmojiProvider<T> {
|
|||
///
|
||||
/// Forwards errors from the gui. See `gui::show` for details.
|
||||
pub fn show(config: &Config) -> Result<(), Error> {
|
||||
let provider = EmojiProvider::new(0, &config.sort_order(), &config.emoji_hide_label());
|
||||
let provider = EmojiProvider::new(0, &config.sort_order(), config.emoji_hide_label());
|
||||
let selection_result = gui::show(config.clone(), provider, true, None, None)?;
|
||||
match selection_result.menu.action {
|
||||
None => Err(Error::MissingAction),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use regex::Regex;
|
||||
use crate::config::Config;
|
||||
use crate::gui;
|
||||
use crate::gui::{ItemProvider, MenuItem};
|
||||
use regex::Regex;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct MathProvider<T: Clone> {
|
||||
|
@ -25,7 +25,6 @@ impl<T: Clone> ItemProvider<T> for MathProvider<T> {
|
|||
#[allow(clippy::cast_possible_truncation)]
|
||||
fn get_elements(&mut self, search: Option<&str>) -> (bool, Vec<MenuItem<T>>) {
|
||||
if let Some(search_text) = search {
|
||||
|
||||
let re = Regex::new(r"0x[0-9a-fA-F]+").unwrap();
|
||||
let result = re.replace_all(search_text, |caps: ®ex::Captures| {
|
||||
let hex_str = &caps[0][2..]; // Skip "0x"
|
||||
|
|
Loading…
Add table
Reference in a new issue