diff --git a/Cargo.toml b/Cargo.toml index 4f6a041..a5d7e1b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ shellexpand = "3.1.0" toml = "0.7.7" anyhow = { version = "1.0.75", features = ["backtrace"] } clap = { version = "4.4.2", features = ["derive"] } +xkbcommon = "0.6.0" [features] default = ["egl", "winit", "udev", "xwayland"] diff --git a/api/lua/example_config.lua b/api/lua/example_config.lua index 68679b3..b9e8b37 100644 --- a/api/lua/example_config.lua +++ b/api/lua/example_config.lua @@ -85,10 +85,12 @@ require("pinnacle").setup(function(pinnacle) -- Tags --------------------------------------------------------------------------- + local tags = { "1", "2", "3", "4", "5" } + output.connect_for_all(function(op) -- Add tags 1, 2, 3, 4 and 5 on all monitors, and toggle tag 1 active by default - op:add_tags("1", "2", "3", "4", "5") + op:add_tags(tags) -- Same as tag.add(op, "1", "2", "3", "4", "5") tag.toggle({ name = "1", output = op }) @@ -135,68 +137,18 @@ require("pinnacle").setup(function(pinnacle) -- Tag manipulation - input.keybind({ mod_key }, keys.KEY_1, function() - tag.switch_to("1") - end) - input.keybind({ mod_key }, keys.KEY_2, function() - tag.switch_to("2") - end) - input.keybind({ mod_key }, keys.KEY_3, function() - tag.switch_to("3") - end) - input.keybind({ mod_key }, keys.KEY_4, function() - tag.switch_to("4") - end) - input.keybind({ mod_key }, keys.KEY_5, function() - tag.switch_to("5") - end) - - input.keybind({ mod_key, "Shift" }, keys.KEY_1, function() - tag.toggle("1") - end) - input.keybind({ mod_key, "Shift" }, keys.KEY_2, function() - tag.toggle("2") - end) - input.keybind({ mod_key, "Shift" }, keys.KEY_3, function() - tag.toggle("3") - end) - input.keybind({ mod_key, "Shift" }, keys.KEY_4, function() - tag.toggle("4") - end) - input.keybind({ mod_key, "Shift" }, keys.KEY_5, function() - tag.toggle("5") - end) - - -- I check for nil this way because I don't want stylua to take up like 80 lines on `if win ~= nil` - input.keybind({ mod_key, "Alt" }, keys.KEY_1, function() - local _ = window.get_focused() and window:get_focused():move_to_tag("1") - end) - input.keybind({ mod_key, "Alt" }, keys.KEY_2, function() - local _ = window.get_focused() and window:get_focused():move_to_tag("2") - end) - input.keybind({ mod_key, "Alt" }, keys.KEY_3, function() - local _ = window.get_focused() and window:get_focused():move_to_tag("3") - end) - input.keybind({ mod_key, "Alt" }, keys.KEY_4, function() - local _ = window.get_focused() and window:get_focused():move_to_tag("4") - end) - input.keybind({ mod_key, "Alt" }, keys.KEY_5, function() - local _ = window.get_focused() and window:get_focused():move_to_tag("5") - end) - - input.keybind({ mod_key, "Shift", "Alt" }, keys.KEY_1, function() - local _ = window.get_focused() and window.get_focused():toggle_tag("1") - end) - input.keybind({ mod_key, "Shift", "Alt" }, keys.KEY_2, function() - local _ = window.get_focused() and window.get_focused():toggle_tag("2") - end) - input.keybind({ mod_key, "Shift", "Alt" }, keys.KEY_3, function() - local _ = window.get_focused() and window.get_focused():toggle_tag("3") - end) - input.keybind({ mod_key, "Shift", "Alt" }, keys.KEY_4, function() - local _ = window.get_focused() and window.get_focused():toggle_tag("4") - end) - input.keybind({ mod_key, "Shift", "Alt" }, keys.KEY_5, function() - local _ = window.get_focused() and window.get_focused():toggle_tag("5") - end) + for _, tag_name in pairs(tags) do + input.keybind({ mod_key }, tag_name, function() + tag.switch_to(tag_name) + end) + input.keybind({ mod_key, "Shift" }, tag_name, function() + tag.toggle(tag_name) + end) + input.keybind({ mod_key, "Alt" }, tag_name, function() + local _ = window.get_focused() and window:get_focused():move_to_tag(tag_name) + end) + input.keybind({ mod_key, "Shift", "Alt" }, tag_name, function() + local _ = window.get_focused() and window.get_focused():toggle_tag(tag_name) + end) + end end) diff --git a/api/lua/input.lua b/api/lua/input.lua index c486eea..820b7f3 100644 --- a/api/lua/input.lua +++ b/api/lua/input.lua @@ -15,15 +15,24 @@ local input_module = { --- process.spawn("Alacritty") ---end) ---``` ----@param key Keys The key for the keybind. +---@param key Keys|string The key for the keybind. ---@param modifiers (Modifier)[] Which modifiers need to be pressed for the keybind to trigger. ---@param action fun() What to do. function input_module.keybind(modifiers, key, action) table.insert(CallbackTable, action) + + local k = {} + + if type(key) == "string" then + k.String = key + else + k.Int = key + end + SendMsg({ SetKeybind = { modifiers = modifiers, - key = key, + key = k, callback_id = #CallbackTable, }, }) diff --git a/api/lua/msg.lua b/api/lua/msg.lua index 66138b5..c3c2ff9 100644 --- a/api/lua/msg.lua +++ b/api/lua/msg.lua @@ -3,7 +3,7 @@ ---@meta _ ---@class _Msg ----@field SetKeybind { key: Keys, modifiers: Modifier[], callback_id: integer }? +---@field SetKeybind { key: { Int: Keys?, String: string? }, modifiers: Modifier[], callback_id: integer }? ---@field SetMousebind { button: integer }? --Windows ---@field CloseWindow { window_id: WindowId }? diff --git a/api/lua/stylua.toml b/api/lua/stylua.toml index 2e04cdc..66ae018 100644 --- a/api/lua/stylua.toml +++ b/api/lua/stylua.toml @@ -1,2 +1,2 @@ indent_type = "Spaces" -column_width = 80 +column_width = 120 diff --git a/src/api/msg.rs b/src/api/msg.rs index 98005c1..75627f5 100644 --- a/src/api/msg.rs +++ b/src/api/msg.rs @@ -17,11 +17,17 @@ use self::window_rules::{WindowRule, WindowRuleCondition}; #[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Copy)] pub struct CallbackId(pub u32); +#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)] +pub enum KeyIntOrString { + Int(u32), + String(String), +} + #[derive(Debug, serde::Serialize, serde::Deserialize)] pub enum Msg { // Input SetKeybind { - key: u32, + key: KeyIntOrString, modifiers: Vec, callback_id: CallbackId, }, diff --git a/src/input.rs b/src/input.rs index d7b2482..2fc2c30 100644 --- a/src/input.rs +++ b/src/input.rs @@ -183,21 +183,17 @@ impl State { modifier_mask.push(Modifier::Super); } let modifier_mask = ModifierMask::from(modifier_mask); - let raw_sym = if keysym.raw_syms().len() == 1 { - keysym.raw_syms()[0] - } else { - keysyms::KEY_NoSymbol - }; + let sym = keysym.modified_sym(); if let Some(callback_id) = state .input_state .keybinds - .get(&(modifier_mask, raw_sym)) + .get(&(modifier_mask, sym)) { return FilterResult::Intercept(KeyAction::CallCallback(*callback_id)); - } else if (modifier_mask, raw_sym) == kill_keybind { + } else if (modifier_mask, sym) == kill_keybind { return FilterResult::Intercept(KeyAction::Quit); - } else if (modifier_mask, raw_sym) == reload_keybind { + } else if (modifier_mask, sym) == reload_keybind { return FilterResult::Intercept(KeyAction::ReloadConfig); } else if let mut vt @ keysyms::KEY_XF86Switch_VT_1..=keysyms::KEY_XF86Switch_VT_12 = keysym.modified_sym() { diff --git a/src/state/api_handlers.rs b/src/state/api_handlers.rs index 29f9c6b..31ce6df 100644 --- a/src/state/api_handlers.rs +++ b/src/state/api_handlers.rs @@ -9,7 +9,9 @@ use smithay::{ }; use crate::{ - api::msg::{Args, CallbackId, Msg, OutgoingMsg, Request, RequestId, RequestResponse}, + api::msg::{ + Args, CallbackId, KeyIntOrString, Msg, OutgoingMsg, Request, RequestId, RequestResponse, + }, tag::Tag, window::WindowElement, }; @@ -25,7 +27,25 @@ impl State { modifiers, callback_id, } => { - tracing::info!("set keybind: {:?}, {}", modifiers, key); + let key = match key { + KeyIntOrString::Int(num) => num, + KeyIntOrString::String(s) => { + if s.chars().count() == 1 { + let Some(ch) = s.chars().next() else { unreachable!() }; + tracing::info!("set keybind: {:?}, {:?}", modifiers, ch); + xkbcommon::xkb::Keysym::from_char(ch).raw() + } else { + let raw = xkbcommon::xkb::keysym_from_name( + &s, + xkbcommon::xkb::KEYSYM_NO_FLAGS, + ) + .raw(); + tracing::info!("set keybind: {:?}, {:?}", modifiers, raw); + raw + } + } + }; + self.input_state .keybinds .insert((modifiers.into(), key), callback_id);