Added Modifier-only keybinding support

This commit is contained in:
PixelDots 2023-09-30 08:42:42 -05:00
parent d051f41de6
commit 37fb26a403
4 changed files with 73 additions and 18 deletions

View file

@ -90,11 +90,11 @@ pub struct KeyPattern {
pub modifiers: KeyModifiers, pub modifiers: KeyModifiers,
/// The actual key, that was pressed /// The actual key, that was pressed
#[serde(deserialize_with = "deserialize_Keysym")] #[serde(deserialize_with = "deserialize_Keysym")]
pub key: u32, pub key: Option<u32>,
} }
impl KeyPattern { impl KeyPattern {
pub fn new(modifiers: impl Into<KeyModifiers>, key: u32) -> KeyPattern { pub fn new(modifiers: impl Into<KeyModifiers>, key: Option<u32>) -> KeyPattern {
KeyPattern { KeyPattern {
modifiers: modifiers.into(), modifiers: modifiers.into(),
key, key,
@ -117,7 +117,12 @@ impl ToString for KeyPattern {
if self.modifiers.shift { if self.modifiers.shift {
result += "Shift+"; result += "Shift+";
} }
result += &keysym_get_name(self.key);
if let Some(key) = self.key {
result += &keysym_get_name(key);
} else {
result.remove(result.len() - 1);
}
result result
} }
} }
@ -176,7 +181,7 @@ fn insert_binding(
for key in keys { for key in keys {
let pattern = KeyPattern { let pattern = KeyPattern {
modifiers: modifiers.clone(), modifiers: modifiers.clone(),
key, key: Some(key),
}; };
if !key_bindings.contains_key(&pattern) { if !key_bindings.contains_key(&pattern) {
key_bindings.insert(pattern, action.clone()); key_bindings.insert(pattern, action.clone());

View file

@ -56,13 +56,18 @@ where
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn deserialize_Keysym<'de, D>(deserializer: D) -> Result<Keysym, D::Error> pub fn deserialize_Keysym<'de, D>(deserializer: D) -> Result<Option<Keysym>, D::Error>
where where
D: serde::Deserializer<'de>, D: serde::Deserializer<'de>,
{ {
use serde::de::{Error, Unexpected}; use serde::de::{Error, Unexpected};
let name = String::deserialize(deserializer)?; let name: Option<String> = Option::deserialize(deserializer)?;
if name.is_none() {
return Ok(None);
}
let name = name.unwrap();
//let name = format!("KEY_{}", code); //let name = format!("KEY_{}", code);
match xkb::keysym_from_name(&name, xkb::KEYSYM_NO_FLAGS) { match xkb::keysym_from_name(&name, xkb::KEYSYM_NO_FLAGS) {
KeySyms::KEY_NoSymbol => match xkb::keysym_from_name(&name, xkb::KEYSYM_CASE_INSENSITIVE) { KeySyms::KEY_NoSymbol => match xkb::keysym_from_name(&name, xkb::KEYSYM_CASE_INSENSITIVE) {
@ -76,9 +81,9 @@ where
name, name,
xkb::keysym_get_name(x) xkb::keysym_get_name(x)
); );
Ok(x) Ok(Some(x))
} }
}, },
x => Ok(x), x => Ok(Some(x)),
} }
} }

View file

@ -67,6 +67,8 @@ pub struct SeatId(pub usize);
pub struct ActiveOutput(pub RefCell<Output>); pub struct ActiveOutput(pub RefCell<Output>);
#[derive(Default)] #[derive(Default)]
pub struct SupressedKeys(RefCell<Vec<(u32, Option<RegistrationToken>)>>); pub struct SupressedKeys(RefCell<Vec<(u32, Option<RegistrationToken>)>>);
#[derive(Default, Debug)]
pub struct ModifiersShortcutQueue(RefCell<Option<KeyPattern>>);
#[derive(Default)] #[derive(Default)]
pub struct Devices(RefCell<HashMap<String, Vec<DeviceCapability>>>); pub struct Devices(RefCell<HashMap<String, Vec<DeviceCapability>>>);
@ -107,6 +109,28 @@ impl SupressedKeys {
} }
} }
impl ModifiersShortcutQueue {
pub fn set(&self, binding: KeyPattern) {
let mut set = self.0.borrow_mut();
*set = Some(binding);
}
pub fn take(&self, binding: &KeyPattern) -> bool {
let mut set = self.0.borrow_mut();
if set.is_some() && set.as_ref().unwrap() == binding {
*set = None;
true
} else {
false
}
}
pub fn clear(&self) {
let mut set = self.0.borrow_mut();
*set = None;
}
}
impl Devices { impl Devices {
fn add_device<D: Device>(&self, device: &D) -> Vec<DeviceCapability> { fn add_device<D: Device>(&self, device: &D) -> Vec<DeviceCapability> {
let id = device.id(); let id = device.id();
@ -152,6 +176,7 @@ pub fn add_seat(
userdata.insert_if_missing(SeatId::default); userdata.insert_if_missing(SeatId::default);
userdata.insert_if_missing(Devices::default); userdata.insert_if_missing(Devices::default);
userdata.insert_if_missing(SupressedKeys::default); userdata.insert_if_missing(SupressedKeys::default);
userdata.insert_if_missing(ModifiersShortcutQueue::default);
userdata.insert_if_missing(SeatMoveGrabState::default); userdata.insert_if_missing(SeatMoveGrabState::default);
userdata.insert_if_missing(CursorState::default); userdata.insert_if_missing(CursorState::default);
userdata.insert_if_missing(|| ActiveOutput(RefCell::new(output.clone()))); userdata.insert_if_missing(|| ActiveOutput(RefCell::new(output.clone())));
@ -283,7 +308,7 @@ impl State {
|| (action_pattern.modifiers.alt && !modifiers.alt) || (action_pattern.modifiers.alt && !modifiers.alt)
|| (action_pattern.modifiers.logo && !modifiers.logo) || (action_pattern.modifiers.logo && !modifiers.logo)
|| (action_pattern.modifiers.shift && !modifiers.shift) || (action_pattern.modifiers.shift && !modifiers.shift)
|| (handle.raw_syms().contains(&action_pattern.key) && state == KeyState::Released) || (action_pattern.key.is_some() && handle.raw_syms().contains(&action_pattern.key.unwrap()) && state == KeyState::Released)
{ {
data.common.shell.set_overview_mode(None, data.common.event_loop_handle.clone()); data.common.shell.set_overview_mode(None, data.common.event_loop_handle.clone());
@ -344,8 +369,8 @@ impl State {
if let (ResizeMode::Started(action_pattern, _, _), _) = if let (ResizeMode::Started(action_pattern, _, _), _) =
data.common.shell.resize_mode() data.common.shell.resize_mode()
{ {
if state == KeyState::Released if action_pattern.key.is_some() && state == KeyState::Released
&& handle.raw_syms().contains(&action_pattern.key) && handle.raw_syms().contains(&action_pattern.key.unwrap())
{ {
data.common.shell.set_resize_mode(None, &data.common.config, data.common.event_loop_handle.clone()); data.common.shell.set_resize_mode(None, &data.common.config, data.common.event_loop_handle.clone());
} else if action_pattern.modifiers != *modifiers { } else if action_pattern.modifiers != *modifiers {
@ -390,7 +415,7 @@ impl State {
let action = Action::_ResizingInternal(direction, edge, state); let action = Action::_ResizingInternal(direction, edge, state);
let key_pattern = KeyPattern { let key_pattern = KeyPattern {
modifiers: modifiers.clone().into(), modifiers: modifiers.clone().into(),
key: handle.raw_code(), key: Some(handle.raw_code()),
}; };
if state == KeyState::Released { if state == KeyState::Released {
@ -412,7 +437,7 @@ impl State {
}).ok() }).ok()
} else { None }; } else { None };
userdata userdata
.get::<SupressedKeys>() .get::<SupressedKeys>()
.unwrap() .unwrap()
.add(&handle, token); .add(&handle, token);
@ -472,14 +497,30 @@ impl State {
} }
// handle the rest of the global shortcuts // handle the rest of the global shortcuts
let mut can_clear_modifiers_shortcut = true;
if !shortcuts_inhibited { if !shortcuts_inhibited {
let modifiers_queue = userdata.get::<ModifiersShortcutQueue>().unwrap();
for (binding, action) in for (binding, action) in
data.common.config.static_conf.key_bindings.iter() data.common.config.static_conf.key_bindings.iter()
{ {
if state == KeyState::Pressed let modifiers_bypass = binding.key.is_none()
&& binding.modifiers == *modifiers && state == KeyState::Released
&& handle.raw_syms().contains(&binding.key) && binding.modifiers != *modifiers
&& modifiers_queue.take(binding);
if !modifiers_bypass && binding.key.is_none() && state == KeyState::Pressed && binding.modifiers == *modifiers {
modifiers_queue.set(binding.clone());
can_clear_modifiers_shortcut = false;
}
if (
binding.key.is_some()
&& state == KeyState::Pressed
&& handle.raw_syms().contains(&binding.key.unwrap())
&& binding.modifiers == *modifiers
) || modifiers_bypass
{ {
modifiers_queue.clear();
userdata userdata
.get::<SupressedKeys>() .get::<SupressedKeys>()
.unwrap() .unwrap()
@ -492,6 +533,10 @@ impl State {
} }
} }
if can_clear_modifiers_shortcut {
userdata.get::<ModifiersShortcutQueue>().unwrap().clear();
}
// keys are passed through to apps // keys are passed through to apps
FilterResult::Forward FilterResult::Forward
}, },

View file

@ -62,7 +62,7 @@ impl KeyboardGrab<State> for SwapWindowGrab {
(pattern.key, *direction) (pattern.key, *direction)
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let Some(direction) = syms.iter().find_map(|sym| focus_bindings.iter().find_map(|(key, direction)| (sym == key).then_some(*direction))) else { return }; let Some(direction) = syms.iter().find_map(|sym| focus_bindings.iter().find_map(|(key, direction)| (key.is_some() && sym == key.as_ref().unwrap()).then_some(*direction))) else { return };
data.handle_action( data.handle_action(
Action::Focus(direction), Action::Focus(direction),
@ -71,7 +71,7 @@ impl KeyboardGrab<State> for SwapWindowGrab {
time, time,
KeyPattern { KeyPattern {
modifiers: modifiers.map(Into::into).unwrap_or_default(), modifiers: modifiers.map(Into::into).unwrap_or_default(),
key: keycode, key: Some(keycode),
}, },
None, None,
); );