Merge pull request #187 from PixelDoted/master_jammy
Modifier-only keybindings
This commit is contained in:
commit
4f3a682564
5 changed files with 70 additions and 19 deletions
|
|
@ -75,6 +75,7 @@
|
||||||
(modifiers: [Super], key: "a"): Spawn("busctl --user call com.system76.CosmicAppLibrary /com/system76/CosmicAppLibrary com.system76.CosmicAppLibrary Toggle"),
|
(modifiers: [Super], key: "a"): Spawn("busctl --user call com.system76.CosmicAppLibrary /com/system76/CosmicAppLibrary com.system76.CosmicAppLibrary Toggle"),
|
||||||
(modifiers: [Super], key: "w"): Spawn("busctl --user call com.system76.CosmicWorkspaces /com/system76/CosmicWorkspaces com.system76.CosmicWorkspaces Toggle"),
|
(modifiers: [Super], key: "w"): Spawn("busctl --user call com.system76.CosmicWorkspaces /com/system76/CosmicWorkspaces com.system76.CosmicWorkspaces Toggle"),
|
||||||
(modifiers: [Super], key: "slash"): Spawn("busctl --user call com.system76.CosmicLauncher /com/system76/CosmicLauncher com.system76.CosmicLauncher Toggle"),
|
(modifiers: [Super], key: "slash"): Spawn("busctl --user call com.system76.CosmicLauncher /com/system76/CosmicLauncher com.system76.CosmicLauncher Toggle"),
|
||||||
|
(modifiers: [Super]): Spawn("busctl --user call com.system76.CosmicLauncher /com/system76/CosmicLauncher com.system76.CosmicLauncher Toggle"),
|
||||||
|
|
||||||
(modifiers: [], key: "XF86AudioRaiseVolume"): Spawn("amixer sset Master 5%+"),
|
(modifiers: [], key: "XF86AudioRaiseVolume"): Spawn("amixer sset Master 5%+"),
|
||||||
(modifiers: [], key: "XF86AudioLowerVolume"): Spawn("amixer sset Master 5%-"),
|
(modifiers: [], key: "XF86AudioLowerVolume"): Spawn("amixer sset Master 5%-"),
|
||||||
|
|
|
||||||
|
|
@ -89,12 +89,12 @@ pub struct KeyPattern {
|
||||||
#[serde(deserialize_with = "deserialize_KeyModifiers")]
|
#[serde(deserialize_with = "deserialize_KeyModifiers")]
|
||||||
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", default)]
|
||||||
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());
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ 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>,
|
||||||
{
|
{
|
||||||
|
|
@ -76,9 +76,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)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue