From 18bc86d14f58068ed59d131306bffb4165eb6aee Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Mon, 15 Apr 2024 18:42:59 +0200 Subject: [PATCH] config: allow consuming/forwarding key events --- jay-config/src/_private/client.rs | 4 +++ jay-config/src/_private/ipc.rs | 4 +++ jay-config/src/input.rs | 20 +++++++++++++++ src/config/handler.rs | 9 +++++++ src/ifs/wl_seat.rs | 6 +++++ src/ifs/wl_seat/event_handling.rs | 32 ++++++++++++++---------- toml-config/src/config.rs | 1 + toml-config/src/config/parsers/action.rs | 2 ++ toml-config/src/lib.rs | 1 + toml-spec/spec/spec.generated.json | 2 ++ toml-spec/spec/spec.generated.md | 20 +++++++++++++++ toml-spec/spec/spec.yaml | 18 +++++++++++++ 12 files changed, 106 insertions(+), 13 deletions(-) diff --git a/jay-config/src/_private/client.rs b/jay-config/src/_private/client.rs index 462b48b4..61c8af6c 100644 --- a/jay-config/src/_private/client.rs +++ b/jay-config/src/_private/client.rs @@ -903,6 +903,10 @@ impl Client { (rate, delay) } + pub fn set_forward(&self, seat: Seat, forward: bool) { + self.send(&ClientMessage::SetForward { seat, forward }) + } + pub fn parse_keymap(&self, keymap: &str) -> Keymap { let res = self.send_with_response(&ClientMessage::ParseKeymap { keymap }); get_response!(res, Keymap(0), ParseKeymap { keymap }); diff --git a/jay-config/src/_private/ipc.rs b/jay-config/src/_private/ipc.rs index 844f9a47..17210fa2 100644 --- a/jay-config/src/_private/ipc.rs +++ b/jay-config/src/_private/ipc.rs @@ -436,6 +436,10 @@ pub enum ClientMessage<'a> { device: InputDevice, keymap: Keymap, }, + SetForward { + seat: Seat, + forward: bool, + }, } #[derive(Serialize, Deserialize, Debug)] diff --git a/jay-config/src/input.rs b/jay-config/src/input.rs index 08322e6d..9c031a5c 100644 --- a/jay-config/src/input.rs +++ b/jay-config/src/input.rs @@ -335,6 +335,26 @@ impl Seat { pub fn move_to_output(self, connector: Connector) { get!().move_to_output(WorkspaceSource::Seat(self), connector); } + + /// Set whether the current key event is forwarded to the focused client. + /// + /// This only has an effect if called from a keyboard shortcut. + /// + /// By default, release events are forwarded and press events are consumed. Note that + /// consuming release events can cause clients to get stuck in the pressed state. + pub fn set_forward(self, forward: bool) { + get!().set_forward(self, forward); + } + + /// This is a shorthand for `set_forward(true)`. + pub fn forward(self) { + self.set_forward(true) + } + + /// This is a shorthand for `set_forward(false)`. + pub fn consume(self) { + self.set_forward(false) + } } /// Returns all seats. diff --git a/src/config/handler.rs b/src/config/handler.rs index 79a47237..fe78a71c 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -318,6 +318,12 @@ impl ConfigProxyHandler { Ok(()) } + fn handle_set_forward(&self, seat: Seat, forward: bool) -> Result<(), CphError> { + let seat = self.get_seat(seat)?; + seat.set_forward(forward); + Ok(()) + } + fn handle_set_status(&self, status: &str) { self.state.set_status(status); } @@ -1764,6 +1770,9 @@ impl ConfigProxyHandler { ClientMessage::DeviceSetKeymap { device, keymap } => self .handle_set_device_keymap(device, keymap) .wrn("set_device_keymap")?, + ClientMessage::SetForward { seat, forward } => { + self.handle_set_forward(seat, forward).wrn("set_forward")? + } } Ok(()) } diff --git a/src/ifs/wl_seat.rs b/src/ifs/wl_seat.rs index 11831159..4d37ffc4 100644 --- a/src/ifs/wl_seat.rs +++ b/src/ifs/wl_seat.rs @@ -175,6 +175,7 @@ pub struct WlSeatGlobal { text_input: CloneCell>>, input_method: CloneCell>>, input_method_grab: CloneCell>>, + forward: Cell, } const CHANGE_CURSOR_MOVED: u32 = 1 << 0; @@ -243,6 +244,7 @@ impl WlSeatGlobal { text_input: Default::default(), input_method: Default::default(), input_method_grab: Default::default(), + forward: Cell::new(false), }); state.add_cursor_size(*DEFAULT_CURSOR_SIZE); let seat = slf.clone(); @@ -1146,6 +1148,10 @@ impl WlSeatGlobal { } } } + + pub fn set_forward(&self, forward: bool) { + self.forward.set(forward); + } } global_base!(WlSeatGlobal, WlSeat, WlSeatError); diff --git a/src/ifs/wl_seat/event_handling.rs b/src/ifs/wl_seat/event_handling.rs index fee45519..5d436797 100644 --- a/src/ifs/wl_seat/event_handling.rs +++ b/src/ifs/wl_seat/event_handling.rs @@ -35,7 +35,7 @@ use { wire::WlDataOfferId, xkbcommon::{KeyboardState, XkbState, XKB_KEY_DOWN, XKB_KEY_UP}, }, - isnt::std_1::primitive::IsntSlice2Ext, + isnt::std_1::primitive::{IsntSlice2Ext, IsntSliceExt}, jay_config::keyboard::{ mods::{Modifiers, CAPS, NUM, RELEASE}, syms::KeySym, @@ -397,22 +397,28 @@ impl WlSeatGlobal { }); let node = self.keyboard_node.get(); let input_method_grab = self.input_method_grab.get(); - if shortcuts.is_empty() { + let mut forward = true; + if shortcuts.is_not_empty() { + self.forward.set(state == wl_keyboard::RELEASED); + if let Some(config) = self.state.config.get() { + let id = xkb_state.kb_state.id; + drop(xkb_state); + for shortcut in shortcuts { + config.invoke_shortcut(self.id(), &shortcut); + } + xkb_state_rc = get_state(); + xkb_state = xkb_state_rc.borrow_mut(); + if id != xkb_state.kb_state.id { + return; + } + } + forward = self.forward.get(); + } + if forward { match &input_method_grab { Some(g) => g.on_key(time_usec, key, state, &xkb_state.kb_state), _ => node.node_on_key(self, time_usec, key, state, &xkb_state.kb_state), } - } else if let Some(config) = self.state.config.get() { - let id = xkb_state.kb_state.id; - drop(xkb_state); - for shortcut in shortcuts { - config.invoke_shortcut(self.id(), &shortcut); - } - xkb_state_rc = get_state(); - xkb_state = xkb_state_rc.borrow_mut(); - if id != xkb_state.kb_state.id { - return; - } } if new_mods { self.state.for_each_seat_tester(|t| { diff --git a/toml-config/src/config.rs b/toml-config/src/config.rs index d9b89760..61116c39 100644 --- a/toml-config/src/config.rs +++ b/toml-config/src/config.rs @@ -49,6 +49,7 @@ pub enum SimpleCommand { ToggleFullscreen, ToggleMono, ToggleSplit, + Forward(bool), } #[derive(Debug, Clone)] diff --git a/toml-config/src/config/parsers/action.rs b/toml-config/src/config/parsers/action.rs index 009e71ce..42b19df4 100644 --- a/toml-config/src/config/parsers/action.rs +++ b/toml-config/src/config/parsers/action.rs @@ -109,6 +109,8 @@ impl ActionParser<'_> { "reload-config-toml" => ReloadConfigToml, "reload-config-so" => ReloadConfigSo, "none" => None, + "forward" => Forward(true), + "consume" => Forward(false), _ => { return Err(ActionParserError::UnknownSimpleAction(string.to_string()).spanned(span)) } diff --git a/toml-config/src/lib.rs b/toml-config/src/lib.rs index fdabf3e1..3ef8988b 100644 --- a/toml-config/src/lib.rs +++ b/toml-config/src/lib.rs @@ -61,6 +61,7 @@ impl Action { } SimpleCommand::ReloadConfigSo => Box::new(reload), SimpleCommand::None => Box::new(|| ()), + SimpleCommand::Forward(bool) => Box::new(move || s.set_forward(bool)), }, Action::Multi { actions } => { let mut actions: Vec<_> = actions.into_iter().map(|a| a.into_fn(state)).collect(); diff --git a/toml-spec/spec/spec.generated.json b/toml-spec/spec/spec.generated.json index e1069ecc..4e7e30d9 100644 --- a/toml-spec/spec/spec.generated.json +++ b/toml-spec/spec/spec.generated.json @@ -1053,6 +1053,8 @@ "quit", "reload-config-toml", "reload-config-to", + "consume", + "forward", "none" ] }, diff --git a/toml-spec/spec/spec.generated.md b/toml-spec/spec/spec.generated.md index 15da4000..df621542 100644 --- a/toml-spec/spec/spec.generated.md +++ b/toml-spec/spec/spec.generated.md @@ -2224,6 +2224,26 @@ The string should have one of the following values: Reload the `config.so`. +- `consume`: + + Consume the current key event. Don't forward it to the focused application. + + This action only has an effect in shortcuts. + + Key-press events events that trigger shortcuts are consumed by default. + Key-release events events that trigger shortcuts are forwarded by default. + + Note that consuming key-release events can cause keys to get stuck in the focused + application. + + See the `forward` action to achieve the opposite effect. + +- `forward`: + + Forward the current key event to the focused application. + + See the `consume` action for more details. + - `none`: Perform no action. diff --git a/toml-spec/spec/spec.yaml b/toml-spec/spec/spec.yaml index 3bd8d1a2..67a4a929 100644 --- a/toml-spec/spec/spec.yaml +++ b/toml-spec/spec/spec.yaml @@ -668,6 +668,24 @@ SimpleActionName: description: Reload the `config.toml`. - value: reload-config-to description: Reload the `config.so`. + - value: consume + description: | + Consume the current key event. Don't forward it to the focused application. + + This action only has an effect in shortcuts. + + Key-press events events that trigger shortcuts are consumed by default. + Key-release events events that trigger shortcuts are forwarded by default. + + Note that consuming key-release events can cause keys to get stuck in the focused + application. + + See the `forward` action to achieve the opposite effect. + - value: forward + description: | + Forward the current key event to the focused application. + + See the `consume` action for more details. - value: none description: | Perform no action.