From 5b241a626b1c3e61b12fdc15fb325d6a5f139155 Mon Sep 17 00:00:00 2001 From: Ottatop Date: Sat, 15 Jun 2024 14:06:23 -0500 Subject: [PATCH] Add keybind descriptions --- api/lua/examples/default/default_config.lua | 65 ++++- api/lua/pinnacle/grpc/defs.lua | 21 ++ api/lua/pinnacle/input.lua | 34 ++- .../pinnacle/input/v0alpha1/input.proto | 18 ++ api/rust/examples/default_config/main.rs | 272 +++++++++++++----- api/rust/src/input.rs | 97 +++++-- api/rust/src/lib.rs | 1 + src/api.rs | 55 +++- src/input.rs | 15 +- 9 files changed, 456 insertions(+), 122 deletions(-) diff --git a/api/lua/examples/default/default_config.lua b/api/lua/examples/default/default_config.lua index 3d30773..07f6702 100644 --- a/api/lua/examples/default/default_config.lua +++ b/api/lua/examples/default/default_config.lua @@ -34,12 +34,18 @@ require("pinnacle").setup(function(Pinnacle) -- mod_key + alt + q = Quit Pinnacle Input.keybind({ mod_key, "alt" }, "q", function() Pinnacle.quit() - end) + end, { + group = "Compositor", + description = "Quit Pinnacle", + }) -- mod_key + alt + r = Reload config Input.keybind({ mod_key, "alt" }, "r", function() Pinnacle.reload_config() - end) + end, { + group = "Compositor", + description = "Reload the config", + }) -- mod_key + alt + c = Close window Input.keybind({ mod_key, "alt" }, "c", function() @@ -47,12 +53,18 @@ require("pinnacle").setup(function(Pinnacle) if focused then focused:close() end - end) + end, { + group = "Window", + description = "Close the focused window", + }) -- mod_key + alt + Return = Spawn `terminal` Input.keybind({ mod_key }, key.Return, function() Process.spawn(terminal) - end) + end, { + group = "Process", + description = "Spawn `alacritty`", + }) -- mod_key + alt + space = Toggle floating Input.keybind({ mod_key, "alt" }, key.space, function() @@ -61,7 +73,10 @@ require("pinnacle").setup(function(Pinnacle) focused:toggle_floating() focused:raise() end - end) + end, { + group = "Window", + description = "Toggle floating on the focused window", + }) -- mod_key + f = Toggle fullscreen Input.keybind({ mod_key }, "f", function() @@ -70,7 +85,10 @@ require("pinnacle").setup(function(Pinnacle) focused:toggle_fullscreen() focused:raise() end - end) + end, { + group = "Window", + description = "Toggle fullscreen on the focused window", + }) -- mod_key + m = Toggle maximized Input.keybind({ mod_key }, "m", function() @@ -79,7 +97,10 @@ require("pinnacle").setup(function(Pinnacle) focused:toggle_maximized() focused:raise() end - end) + end, { + group = "Window", + description = "Toggle maximized on the focused window", + }) ---------------------- -- Tags and Outputs -- @@ -109,12 +130,18 @@ require("pinnacle").setup(function(Pinnacle) -- mod_key + 1-5 = Switch to tags 1-5 Input.keybind({ mod_key }, tag_name, function() Tag.get(tag_name):switch_to() - end) + end, { + group = "Tag", + description = "Switch to tag " .. tag_name, + }) -- mod_key + shift + 1-5 = Toggle tags 1-5 Input.keybind({ mod_key, "shift" }, tag_name, function() Tag.get(tag_name):toggle_active() - end) + end, { + group = "Tag", + description = "Toggle tag " .. tag_name, + }) -- mod_key + alt + 1-5 = Move window to tags 1-5 Input.keybind({ mod_key, "alt" }, tag_name, function() @@ -122,7 +149,10 @@ require("pinnacle").setup(function(Pinnacle) if focused then focused:move_to_tag(Tag.get(tag_name) --[[@as TagHandle]]) end - end) + end, { + group = "Tag", + description = "Move the focused window to tag " .. tag_name, + }) -- mod_key + shift + alt + 1-5 = Toggle tags 1-5 on window Input.keybind({ mod_key, "shift", "alt" }, tag_name, function() @@ -130,7 +160,10 @@ require("pinnacle").setup(function(Pinnacle) if focused then focused:toggle_tag(Tag.get(tag_name) --[[@as TagHandle]]) end - end) + end, { + group = "Tag", + description = "Toggle tag " .. tag_name .. " on the focused window", + }) end -------------------- @@ -226,7 +259,10 @@ require("pinnacle").setup(function(Pinnacle) Layout.request_layout(focused_op) end end - end) + end, { + group = "Layout", + description = "Cycle the layout forward on the first active tag", + }) -- mod_key + shift + space = Cycle backward one layout on the focused output Input.keybind({ mod_key, "shift" }, key.space, function() @@ -257,7 +293,10 @@ require("pinnacle").setup(function(Pinnacle) Layout.request_layout(focused_op) end end - end) + end, { + group = "Layout", + description = "Cycle the layout backward on the first active tag", + }) Input.set_libinput_settings({ tap = true, diff --git a/api/lua/pinnacle/grpc/defs.lua b/api/lua/pinnacle/grpc/defs.lua index 4adb719..7c00f27 100644 --- a/api/lua/pinnacle/grpc/defs.lua +++ b/api/lua/pinnacle/grpc/defs.lua @@ -258,6 +258,8 @@ local pinnacle_input_v0alpha1_Modifier = { ---@field modifiers pinnacle.input.v0alpha1.Modifier[]? ---@field raw_code integer? ---@field xkb_name string? +---@field group string? +---@field description string? ---@class pinnacle.input.v0alpha1.SetKeybindResponse @@ -274,6 +276,18 @@ local pinnacle_input_v0alpha1_SetMousebindRequest_MouseEdge = { ---@class pinnacle.input.v0alpha1.SetMousebindResponse +---@class pinnacle.input.v0alpha1.KeybindDescriptionsRequest + +---@class pinnacle.input.v0alpha1.KeybindDescriptionsResponse +---@field descriptions pinnacle.input.v0alpha1.KeybindDescription[]? + +---@class pinnacle.input.v0alpha1.KeybindDescription +---@field modifiers pinnacle.input.v0alpha1.Modifier[]? +---@field raw_code integer? +---@field xkb_name string? +---@field group string? +---@field description string? + ---@class SetXkbConfigRequest ---@field rules string? ---@field variant string? @@ -729,6 +743,13 @@ defs.pinnacle = { response = "pinnacle.input.v0alpha1.SetMousebindResponse", }, ---@type GrpcRequestArgs + KeybindDescriptions = { + service = "pinnacle.input.v0alpha1.InputService", + method = "KeybindDescriptions", + request = "pinnacle.input.v0alpha1.KeybindDescriptionsRequest", + response = "pinnacle.input.v0alpha1.KeybindDescriptionsResponse", + }, + ---@type GrpcRequestArgs SetXkbConfig = { service = "pinnacle.input.v0alpha1.InputService", method = "SetXkbConfig", diff --git a/api/lua/pinnacle/input.lua b/api/lua/pinnacle/input.lua index e9fc539..e9e86d0 100644 --- a/api/lua/pinnacle/input.lua +++ b/api/lua/pinnacle/input.lua @@ -74,6 +74,10 @@ local input = { } input.mouse_button_values = mouse_button_values +---@class KeybindInfo +---@field group string? The group to place this keybind in. Used for the keybind list. +---@field description string? The description of this keybind. Used for the keybind list. + ---Set a keybind. If called with an already existing keybind, it gets replaced. --- ---You must provide three arguments: @@ -111,7 +115,8 @@ input.mouse_button_values = mouse_button_values ---@param mods Modifier[] The modifiers that need to be held down for the bind to trigger ---@param key Key | string The key used to trigger the bind ---@param action fun() The function to run when the bind is triggered -function input.keybind(mods, key, action) +---@param keybind_info KeybindInfo? +function input.keybind(mods, key, action, keybind_info) local raw_code = nil local xkb_name = nil @@ -130,6 +135,8 @@ function input.keybind(mods, key, action) modifiers = mod_values, raw_code = raw_code, xkb_name = xkb_name, + group = keybind_info and keybind_info.group, + description = keybind_info and keybind_info.description, }, action) end @@ -165,6 +172,31 @@ function input.mousebind(mods, button, edge, action) }, action) end +---@class KeybindDescription +---@field modifiers Modifier[] +---@field raw_code integer +---@field xkb_name string +---@field group string? +---@field description string? + +---Get all keybinds along with their descriptions +--- +---@return KeybindDescription[] +function input.keybind_descriptions() + ---@type pinnacle.input.v0alpha1.KeybindDescriptionsResponse + local descs = client.unary_request(input_service.KeybindDescriptions, {}) + local descs = descs.descriptions or {} + + local ret = {} + + for _, desc in ipairs(descs) do + desc.modifiers = desc.modifiers or {} + table.insert(ret, desc) + end + + return ret +end + ---@class XkbConfig ---@field rules string? ---@field model string? diff --git a/api/protocol/pinnacle/input/v0alpha1/input.proto b/api/protocol/pinnacle/input/v0alpha1/input.proto index 2c33e9b..0ad65d3 100644 --- a/api/protocol/pinnacle/input/v0alpha1/input.proto +++ b/api/protocol/pinnacle/input/v0alpha1/input.proto @@ -18,9 +18,25 @@ message SetKeybindRequest { uint32 raw_code = 2; string xkb_name = 3; } + optional string group = 4; + optional string description = 5; } message SetKeybindResponse {} +message KeybindDescriptionsRequest {} + +message KeybindDescriptionsResponse { + repeated KeybindDescription descriptions = 1; +} + +message KeybindDescription { + repeated Modifier modifiers = 1; + optional uint32 raw_code = 2; + optional string xkb_name = 3; + optional string group = 4; + optional string description = 5; +} + message SetMousebindRequest { repeated Modifier modifiers = 1; // A button code corresponding to one of the `BTN_` prefixed definitions in input-event-codes.h @@ -131,6 +147,8 @@ service InputService { rpc SetKeybind(SetKeybindRequest) returns (stream SetKeybindResponse); rpc SetMousebind(SetMousebindRequest) returns (stream SetMousebindResponse); + rpc KeybindDescriptions(KeybindDescriptionsRequest) returns (KeybindDescriptionsResponse); + rpc SetXkbConfig(SetXkbConfigRequest) returns (google.protobuf.Empty); rpc SetRepeatRate(SetRepeatRateRequest) returns (google.protobuf.Empty); diff --git a/api/rust/examples/default_config/main.rs b/api/rust/examples/default_config/main.rs index 815a8f5..cfe6f8d 100644 --- a/api/rust/examples/default_config/main.rs +++ b/api/rust/examples/default_config/main.rs @@ -1,4 +1,5 @@ use pinnacle_api::input::libinput::LibinputSetting; +use pinnacle_api::input::KeybindInfo; use pinnacle_api::layout::{ CornerLayout, CornerLocation, CyclingLayoutManager, DwindleLayout, FairLayout, MasterSide, MasterStackLayout, SpiralLayout, @@ -51,6 +52,15 @@ async fn main() { let terminal = "alacritty"; + input.keybind( + [mod_key], + 'i', + || { + dbg!(input.keybind_descriptions().collect::>()); + }, + None, + ); + //------------------------ // Mousebinds | //------------------------ @@ -70,54 +80,110 @@ async fn main() { //------------------------ // `mod_key + alt + q` quits Pinnacle - input.keybind([mod_key, Mod::Alt], 'q', || { - #[cfg(feature = "snowcap")] - snowcap.integration.quit_prompt().show(); + input.keybind( + [mod_key, Mod::Alt], + 'q', + || { + #[cfg(feature = "snowcap")] + snowcap.integration.quit_prompt().show(); - #[cfg(not(feature = "snowcap"))] - pinnacle.quit(); - }); + #[cfg(not(feature = "snowcap"))] + pinnacle.quit(); + }, + KeybindInfo { + group: Some("Compositor".into()), + description: Some("Quit Pinnacle".into()), + }, + ); // `mod_key + alt + r` reloads the config - input.keybind([mod_key, Mod::Alt], 'r', || { - pinnacle.reload_config(); - }); + input.keybind( + [mod_key, Mod::Alt], + 'r', + || { + pinnacle.reload_config(); + }, + KeybindInfo { + group: Some("Compositor".into()), + description: Some("Reload the config".into()), + }, + ); // `mod_key + alt + c` closes the focused window - input.keybind([mod_key, Mod::Alt], 'c', || { - if let Some(window) = window.get_focused() { - window.close(); - } - }); + input.keybind( + [mod_key, Mod::Alt], + 'c', + || { + if let Some(window) = window.get_focused() { + window.close(); + } + }, + KeybindInfo { + group: Some("Window".into()), + description: Some("Close the focused window".into()), + }, + ); // `mod_key + Return` spawns a terminal - input.keybind([mod_key], Keysym::Return, move || { - process.spawn([terminal]); - }); + input.keybind( + [mod_key], + Keysym::Return, + move || { + process.spawn([terminal]); + }, + KeybindInfo { + group: Some("Process".into()), + description: Some("Spawn `alacritty`".into()), + }, + ); // `mod_key + alt + space` toggles floating - input.keybind([mod_key, Mod::Alt], Keysym::space, || { - if let Some(window) = window.get_focused() { - window.toggle_floating(); - window.raise(); - } - }); + input.keybind( + [mod_key, Mod::Alt], + Keysym::space, + || { + if let Some(window) = window.get_focused() { + window.toggle_floating(); + window.raise(); + } + }, + KeybindInfo { + group: Some("Window".into()), + description: Some("Toggle floating on the focused window".into()), + }, + ); // `mod_key + f` toggles fullscreen - input.keybind([mod_key], 'f', || { - if let Some(window) = window.get_focused() { - window.toggle_fullscreen(); - window.raise(); - } - }); + input.keybind( + [mod_key], + 'f', + || { + if let Some(window) = window.get_focused() { + window.toggle_fullscreen(); + window.raise(); + } + }, + KeybindInfo { + group: Some("Window".into()), + description: Some("Toggle fullscreen on the focused window".into()), + }, + ); // `mod_key + m` toggles maximized - input.keybind([mod_key], 'm', || { - if let Some(window) = window.get_focused() { - window.toggle_maximized(); - window.raise(); - } - }); + input.keybind( + [mod_key], + 'm', + || { + if let Some(window) = window.get_focused() { + window.toggle_maximized(); + window.raise(); + } + }, + KeybindInfo { + group: Some("Window".into()), + description: Some("Toggle maximized on the focused window".into()), + }, + ); //------------------------ // Window rules | @@ -200,32 +266,48 @@ async fn main() { let mut layout_requester_clone = layout_requester.clone(); // `mod_key + space` cycles to the next layout - input.keybind([mod_key], Keysym::space, move || { - let Some(focused_op) = output.get_focused() else { return }; - let Some(first_active_tag) = focused_op.tags().batch_find( - |tg| Box::pin(tg.active_async()), - |active| active == &Some(true), - ) else { - return; - }; + input.keybind( + [mod_key], + Keysym::space, + move || { + let Some(focused_op) = output.get_focused() else { return }; + let Some(first_active_tag) = focused_op.tags().batch_find( + |tg| Box::pin(tg.active_async()), + |active| active == &Some(true), + ) else { + return; + }; - layout_requester.cycle_layout_forward(&first_active_tag); - layout_requester.request_layout_on_output(&focused_op); - }); + layout_requester.cycle_layout_forward(&first_active_tag); + layout_requester.request_layout_on_output(&focused_op); + }, + KeybindInfo { + group: Some("Layout".into()), + description: Some("Cycle the layout forward on the first active tag".into()), + }, + ); // `mod_key + shift + space` cycles to the previous layout - input.keybind([mod_key, Mod::Shift], Keysym::space, move || { - let Some(focused_op) = output.get_focused() else { return }; - let Some(first_active_tag) = focused_op.tags().batch_find( - |tg| Box::pin(tg.active_async()), - |active| active == &Some(true), - ) else { - return; - }; + input.keybind( + [mod_key, Mod::Shift], + Keysym::space, + move || { + let Some(focused_op) = output.get_focused() else { return }; + let Some(first_active_tag) = focused_op.tags().batch_find( + |tg| Box::pin(tg.active_async()), + |active| active == &Some(true), + ) else { + return; + }; - layout_requester_clone.cycle_layout_backward(&first_active_tag); - layout_requester_clone.request_layout_on_output(&focused_op); - }); + layout_requester_clone.cycle_layout_backward(&first_active_tag); + layout_requester_clone.request_layout_on_output(&focused_op); + }, + KeybindInfo { + group: Some("Layout".into()), + description: Some("Cycle the layout backward on the first active tag".into()), + }, + ); //------------------------ // Tags | @@ -238,36 +320,68 @@ async fn main() { for tag_name in tag_names { // `mod_key + 1-5` switches to tag "1" to "5" - input.keybind([mod_key], tag_name, move || { - if let Some(tg) = tag.get(tag_name) { - tg.switch_to(); - } - }); + input.keybind( + [mod_key], + tag_name, + move || { + if let Some(tg) = tag.get(tag_name) { + tg.switch_to(); + } + }, + KeybindInfo { + group: Some("Tag".into()), + description: Some(format!("Switch to tag {tag_name}")), + }, + ); // `mod_key + shift + 1-5` toggles tag "1" to "5" - input.keybind([mod_key, Mod::Shift], tag_name, move || { - if let Some(tg) = tag.get(tag_name) { - tg.toggle_active(); - } - }); + input.keybind( + [mod_key, Mod::Shift], + tag_name, + move || { + if let Some(tg) = tag.get(tag_name) { + tg.toggle_active(); + } + }, + KeybindInfo { + group: Some("Tag".into()), + description: Some(format!("Toggle tag {tag_name}")), + }, + ); // `mod_key + alt + 1-5` moves the focused window to tag "1" to "5" - input.keybind([mod_key, Mod::Alt], tag_name, move || { - if let Some(tg) = tag.get(tag_name) { - if let Some(win) = window.get_focused() { - win.move_to_tag(&tg); + input.keybind( + [mod_key, Mod::Alt], + tag_name, + move || { + if let Some(tg) = tag.get(tag_name) { + if let Some(win) = window.get_focused() { + win.move_to_tag(&tg); + } } - } - }); + }, + KeybindInfo { + group: Some("Tag".into()), + description: Some(format!("Move the focused window to tag {tag_name}")), + }, + ); // `mod_key + shift + alt + 1-5` toggles tag "1" to "5" on the focused window - input.keybind([mod_key, Mod::Shift, Mod::Alt], tag_name, move || { - if let Some(tg) = tag.get(tag_name) { - if let Some(win) = window.get_focused() { - win.toggle_tag(&tg); + input.keybind( + [mod_key, Mod::Shift, Mod::Alt], + tag_name, + move || { + if let Some(tg) = tag.get(tag_name) { + if let Some(win) = window.get_focused() { + win.toggle_tag(&tg); + } } - } - }); + }, + KeybindInfo { + group: Some("Tag".into()), + description: Some(format!("Toggle tag {tag_name} on the focused window")), + }, + ); } input.set_libinput_setting(LibinputSetting::Tap(true)); diff --git a/api/rust/src/input.rs b/api/rust/src/input.rs index 76830e5..0804499 100644 --- a/api/rust/src/input.rs +++ b/api/rust/src/input.rs @@ -15,8 +15,8 @@ use pinnacle_api_defs::pinnacle::input::{ v0alpha1::{ input_service_client::InputServiceClient, set_libinput_setting_request::{CalibrationMatrix, Setting}, - SetKeybindRequest, SetLibinputSettingRequest, SetMousebindRequest, SetRepeatRateRequest, - SetXkbConfigRequest, + KeybindDescriptionsRequest, SetKeybindRequest, SetLibinputSettingRequest, + SetMousebindRequest, SetRepeatRateRequest, SetXkbConfigRequest, }, }; use tokio::sync::mpsc::UnboundedSender; @@ -99,6 +99,32 @@ pub struct Input { fut_sender: UnboundedSender>, } +/// Keybind information. +/// +/// Mainly used for the keybind list. +#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] +pub struct KeybindInfo { + /// The group to place this keybind in. + pub group: Option, + /// The description of this keybind. + pub description: Option, +} + +/// The description of a keybind. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct KeybindDescription { + /// The keybind's modifiers. + pub modifiers: Vec, + /// The keysym code. + pub key_code: u32, + /// The name of the key. + pub xkb_name: String, + /// The group. + pub group: Option, + /// The description of the keybind. + pub description: Option, +} + impl Input { pub(crate) fn new( channel: Channel, @@ -157,25 +183,28 @@ impl Input { mods: impl IntoIterator, key: impl Key + Send + 'static, mut action: impl FnMut() + Send + 'static, + keybind_info: impl Into>, ) { let mut client = self.create_input_client(); let modifiers = mods.into_iter().map(|modif| modif as i32).collect(); + let keybind_info: Option = keybind_info.into(); + + let mut stream = block_on_tokio(client.set_keybind(SetKeybindRequest { + modifiers, + key: Some(input::v0alpha1::set_keybind_request::Key::RawCode( + key.into_keysym().raw(), + )), + group: keybind_info.clone().and_then(|info| info.group), + description: keybind_info.clone().and_then(|info| info.description), + })) + .unwrap() + .into_inner(); + self.fut_sender .send( async move { - let mut stream = client - .set_keybind(SetKeybindRequest { - modifiers, - key: Some(input::v0alpha1::set_keybind_request::Key::RawCode( - key.into_keysym().raw(), - )), - }) - .await - .unwrap() - .into_inner(); - while let Some(Ok(_response)) = stream.next().await { action(); tokio::task::yield_now().await; @@ -218,20 +247,17 @@ impl Input { let mut client = self.create_input_client(); let modifiers = mods.into_iter().map(|modif| modif as i32).collect(); + let mut stream = block_on_tokio(client.set_mousebind(SetMousebindRequest { + modifiers, + button: Some(button as u32), + edge: Some(edge as i32), + })) + .unwrap() + .into_inner(); self.fut_sender .send( async move { - let mut stream = client - .set_mousebind(SetMousebindRequest { - modifiers, - button: Some(button as u32), - edge: Some(edge as i32), - }) - .await - .unwrap() - .into_inner(); - while let Some(Ok(_response)) = stream.next().await { action(); tokio::task::yield_now().await; @@ -242,6 +268,31 @@ impl Input { .unwrap(); } + /// Get all keybinds and their information. + pub fn keybind_descriptions(&self) -> impl Iterator { + let mut client = self.create_input_client(); + let descriptions = + block_on_tokio(client.keybind_descriptions(KeybindDescriptionsRequest {})).unwrap(); + let descriptions = descriptions.into_inner(); + + descriptions.descriptions.into_iter().map(|desc| { + let mods = desc.modifiers().flat_map(|m| match m { + input::v0alpha1::Modifier::Unspecified => None, + input::v0alpha1::Modifier::Shift => Some(Mod::Shift), + input::v0alpha1::Modifier::Ctrl => Some(Mod::Ctrl), + input::v0alpha1::Modifier::Alt => Some(Mod::Alt), + input::v0alpha1::Modifier::Super => Some(Mod::Super), + }); + KeybindDescription { + modifiers: mods.collect(), + key_code: desc.raw_code(), + xkb_name: desc.xkb_name().to_string(), + group: desc.group, + description: desc.description, + } + }) + } + /// Set the xkeyboard config. /// /// This allows you to set several xkeyboard options like `layout` and `rules`. diff --git a/api/rust/src/lib.rs b/api/rust/src/lib.rs index a602be4..5839009 100644 --- a/api/rust/src/lib.rs +++ b/api/rust/src/lib.rs @@ -237,6 +237,7 @@ pub async fn connect() -> Result<(ApiModules, Receivers), Box, + ) -> Result, Status> { + run_unary(&self.sender, |state| { + let descriptions = + state + .pinnacle + .input_state + .keybinds + .iter() + .map(|((mods, key), data)| { + let mut modifiers = Vec::::new(); + if mods.contains(ModifierMask::CTRL) { + modifiers.push(Modifier::Ctrl as i32); + } + if mods.contains(ModifierMask::ALT) { + modifiers.push(Modifier::Alt as i32); + } + if mods.contains(ModifierMask::SUPER) { + modifiers.push(Modifier::Super as i32); + } + if mods.contains(ModifierMask::SHIFT) { + modifiers.push(Modifier::Shift as i32); + } + KeybindDescription { + modifiers, + raw_code: Some(key.raw()), + xkb_name: Some(xkbcommon::xkb::keysym_get_name(*key)), + group: data.group.clone(), + description: data.description.clone(), + } + }); + + KeybindDescriptionsResponse { + descriptions: descriptions.collect(), + } + }) + .await + } + async fn set_xkb_config( &self, request: Request, diff --git a/src/input.rs b/src/input.rs index dca03d2..208f439 100644 --- a/src/input.rs +++ b/src/input.rs @@ -13,6 +13,7 @@ use crate::{ state::{Pinnacle, WithState}, window::WindowElement, }; +use indexmap::IndexMap; use pinnacle_api_defs::pinnacle::input::v0alpha1::{ set_libinput_setting_request::Setting, set_mousebind_request, SetKeybindResponse, SetMousebindResponse, @@ -93,14 +94,20 @@ impl From<&ModifiersState> for ModifierMask { } } +#[derive(Debug)] +pub struct KeybindData { + pub sender: UnboundedSender>, + pub group: Option, + pub description: Option, +} + #[derive(Default)] pub struct InputState { // TODO: move all of these to config pub reload_keybind: Option<(ModifierMask, Keysym)>, pub kill_keybind: Option<(ModifierMask, Keysym)>, - pub keybinds: - HashMap<(ModifierMask, Keysym), UnboundedSender>>, + pub keybinds: IndexMap<(ModifierMask, Keysym), KeybindData>, pub mousebinds: HashMap< (ModifierMask, u32, set_mousebind_request::MouseEdge), UnboundedSender>, @@ -540,7 +547,7 @@ impl State { let raw_sym = keysym.raw_syms().iter().next(); let mod_sym = keysym.modified_sym(); - if let Some(sender) = state + if let Some(keybind_data) = state .pinnacle .input_state .keybinds @@ -557,7 +564,7 @@ impl State { { if state.pinnacle.lock_state.is_unlocked() { return FilterResult::Intercept(KeyAction::CallCallback( - sender.clone(), + keybind_data.sender.clone(), )); } }