Get mousebinds to work

This commit is contained in:
Ottatop 2024-01-14 20:25:57 -06:00
parent 2a342c8272
commit f7068a1146
5 changed files with 239 additions and 20 deletions

View file

@ -0,0 +1,115 @@
require("pinnacle").setup(function(Pinnacle)
local Input = Pinnacle.input
local Process = Pinnacle.process
local Output = Pinnacle.output
local Tag = Pinnacle.tag
local Window = Pinnacle.window
local key = Input.key
---@type Modifier
local mod_key = "ctrl"
local terminal = "alacritty"
Input:mousebind({ mod_key }, "btn_left", "press", function()
Window:begin_move("btn_left")
end)
Input:mousebind({ mod_key }, "btn_right", "press", function()
Window:begin_resize("btn_right")
end)
------
Input:keybind({ mod_key, "alt" }, "q", function()
Pinnacle:quit()
end)
Input:keybind({ mod_key, "alt" }, "c", function()
local focused = Window:get_focused()
if focused then
focused:close()
end
end)
Input:keybind({ mod_key }, key.Return, function()
Process:spawn(terminal)
end)
Input:keybind({ mod_key, "alt" }, key.space, function()
local focused = Window:get_focused()
if focused then
focused:toggle_floating()
end
end)
Input:keybind({ mod_key }, "f", function()
local focused = Window:get_focused()
if focused then
focused:toggle_fullscreen()
end
end)
Input:keybind({ mod_key }, "m", function()
local focused = Window:get_focused()
if focused then
focused:toggle_maximized()
end
end)
local tag_names = { "1", "2", "3", "4", "5" }
Output:connect_for_all(function(op)
local tags = Tag:add(op, tag_names)
tags[1]:set_active(true)
end)
Process:spawn_once("foot")
local layout_cycler = Tag:new_layout_cycler({
"master_stack",
"dwindle",
"spiral",
"corner_top_left",
"corner_top_right",
"corner_bottom_left",
"corner_bottom_right",
})
Input:keybind({ mod_key }, key.space, function()
local focused_op = Output:get_focused()
if focused_op then
layout_cycler.next(focused_op)
end
end)
Input:keybind({ mod_key, "shift" }, key.space, function()
local focused_op = Output:get_focused()
if focused_op then
layout_cycler.prev(focused_op)
end
end)
for _, tag_name in ipairs(tag_names) do
-- nil-safety: tags are guaranteed to be on the outputs due to connect_for_all above
Input:keybind({ mod_key }, tag_name, function()
Tag:get(tag_name):switch_to()
end)
Input:keybind({ mod_key, "shift" }, tag_name, function()
Tag:get(tag_name):toggle_active()
end)
Input:keybind({ mod_key, "alt" }, tag_name, function()
local focused = Window:get_focused()
if focused then
focused:move_to_tag(Tag:get(tag_name) --[[@as TagHandle]])
end
end)
Input:keybind({ mod_key, "shift", "alt" }, tag_name, function()
local focused = Window:get_focused()
if focused then
focused:toggle_tag(Tag:get(tag_name) --[[@as TagHandle]])
end
end)
end
end)

View file

@ -0,0 +1,51 @@
# This metaconfig.toml file dictates what config Pinnacle will run.
#
# When running Pinnacle, the compositor will look in the following directories for a metaconfig.toml file,
# in order from top to bottom:
# $PINNACLE_CONFIG_DIR
# $XDG_CONFIG_HOME/pinnacle/
# ~/.config/pinnacle/
#
# When Pinnacle finds a metaconfig.toml file, it will execute the command provided to `command`.
# For now, the only thing that should be here is `lua` with a path to the main config file.
# In the future, there will be a Rust API that can be run using `cargo run`.
#
# Because configuration is done using an external process, if it ever crashes, you lose all of your keybinds.
# In order prevent you from getting stuck in the compositor, you must define keybinds to reload your config
# and kill Pinnacle.
#
# More details on each setting can be found below.
# The command Pinnacle will run on startup and when you reload your config.
# Paths are relative to the directory the metaconfig.toml file is in.
# This must be an array.
command = ["lua", "init.lua"]
### Keybinds ###
# Each keybind takes in a table with two fields: `modifiers` and `key`.
# - `modifiers` can be one of "Ctrl", "Alt", "Shift", or "Super".
# - `key` can be a string of any lowercase letter, number,
# "numN" where N is a number for numpad keys, or "esc"/"escape".
# Support for any xkbcommon key is planned for a future update.
# The keybind that will reload your config.
reload_keybind = { modifiers = ["Ctrl", "Alt"], key = "r" }
# The keybind that will kill Pinnacle.
kill_keybind = { modifiers = ["Ctrl", "Alt", "Shift"], key = "escape" }
### Socket directory ###
# Pinnacle will open a Unix socket at `$XDG_RUNTIME_DIR` by default, falling back to `/tmp` if it doesn't exist.
# If you want/need to change this, use the `socket_dir` setting set to the directory of your choosing.
#
# socket_dir = "/your/dir/here/"
### Environment Variables ###
# You may need to specify to Lua where Pinnacle's Lua API library is.
# This is currently done using the `envs` table, with keys as the name of the environment variable and
# the value as the variable value. This supports $var expansion, and paths are relative to this metaconfig.toml file.
#
# Pinnacle will run your config with the additional PINNACLE_DIR environment variable.
#
# Here, LUA_PATH and LUA_CPATH are used to tell Lua the path to the library.
[envs]
LUA_PATH = "$PINNACLE_LUA_GRPC_DIR/?.lua;$PINNACLE_LUA_GRPC_DIR/?/init.lua;$LUA_PATH"

View file

@ -4,6 +4,7 @@ local h2_connection = require("http.h2_connection")
local pb = require("pb")
local inspect = require("inspect")
---@nodoc
---Create appropriate headers for a gRPC request.
---@param service string The desired service
---@param method string The desired method within the service

View file

@ -1,8 +1,11 @@
use std::{ffi::OsString, num::NonZeroU32, pin::Pin, process::Stdio};
use pinnacle_api_defs::pinnacle::{
input::libinput::v0alpha1::set_libinput_setting_request::{
AccelProfile, ClickMethod, ScrollMethod, TapButtonMap,
input::{
libinput::v0alpha1::set_libinput_setting_request::{
AccelProfile, ClickMethod, ScrollMethod, TapButtonMap,
},
v0alpha1::set_mousebind_request::MouseEdge,
},
output::v0alpha1::{ConnectForAllRequest, ConnectForAllResponse, SetLocationRequest},
process::v0alpha1::SetEnvRequest,
@ -184,6 +187,12 @@ impl pinnacle_api_defs::pinnacle::input::v0alpha1::input_service_server::InputSe
.button
.ok_or_else(|| Status::invalid_argument("no key specified"))?;
let edge = request.edge();
if let MouseEdge::Unspecified = edge {
return Err(Status::invalid_argument("press or release not specified"));
}
let (sender, receiver) = tokio::sync::mpsc::unbounded_channel();
self.sender
@ -191,7 +200,7 @@ impl pinnacle_api_defs::pinnacle::input::v0alpha1::input_service_server::InputSe
state
.input_state
.grpc_mousebinds
.insert((modifiers, button), sender);
.insert((modifiers, button, edge), sender);
}))
.map_err(|_| Status::internal("internal state was not running"))?;

View file

@ -12,7 +12,7 @@ use crate::{
};
use pinnacle_api_defs::pinnacle::input::{
libinput::v0alpha1::set_libinput_setting_request::Setting,
v0alpha1::{SetKeybindResponse, SetMousebindResponse},
v0alpha1::{set_mousebind_request, SetKeybindResponse, SetMousebindResponse},
};
use smithay::{
backend::input::{
@ -21,7 +21,7 @@ use smithay::{
},
desktop::{layer_map_for_output, space::SpaceElement},
input::{
keyboard::{keysyms, FilterResult},
keyboard::{keysyms, FilterResult, ModifiersState},
pointer::{AxisFrame, ButtonEvent, MotionEvent, RelativeMotionEvent},
},
reexports::input::{self, Led},
@ -45,6 +45,44 @@ bitflags::bitflags! {
}
}
impl From<ModifiersState> for ModifierMask {
fn from(modifiers: ModifiersState) -> Self {
let mut mask = ModifierMask::empty();
if modifiers.alt {
mask |= ModifierMask::ALT;
}
if modifiers.shift {
mask |= ModifierMask::SHIFT;
}
if modifiers.ctrl {
mask |= ModifierMask::CTRL;
}
if modifiers.logo {
mask |= ModifierMask::SUPER;
}
mask
}
}
impl From<&ModifiersState> for ModifierMask {
fn from(modifiers: &ModifiersState) -> Self {
let mut mask = ModifierMask::empty();
if modifiers.alt {
mask |= ModifierMask::ALT;
}
if modifiers.shift {
mask |= ModifierMask::SHIFT;
}
if modifiers.ctrl {
mask |= ModifierMask::CTRL;
}
if modifiers.logo {
mask |= ModifierMask::SUPER;
}
mask
}
}
#[derive(Default)]
pub struct InputState {
/// A hashmap of modifier keys and keycodes to callback IDs
@ -60,8 +98,10 @@ pub struct InputState {
pub grpc_keybinds:
HashMap<(ModifierMask, Keysym), UnboundedSender<Result<SetKeybindResponse, tonic::Status>>>,
pub grpc_mousebinds:
HashMap<(ModifierMask, u32), UnboundedSender<Result<SetMousebindResponse, tonic::Status>>>,
pub grpc_mousebinds: HashMap<
(ModifierMask, u32, set_mousebind_request::MouseEdge),
UnboundedSender<Result<SetMousebindResponse, tonic::Status>>,
>,
pub grpc_libinput_settings:
HashMap<Discriminant<Setting>, Box<dyn Fn(&mut input::Device) + Send>>,
}
@ -231,19 +271,7 @@ impl State {
}
let modifier_mask = crate::api::msg::ModifierMask::from(modifier_mask);
let mut grpc_modifiers = ModifierMask::empty();
if modifiers.alt {
grpc_modifiers |= ModifierMask::ALT;
}
if modifiers.shift {
grpc_modifiers |= ModifierMask::SHIFT;
}
if modifiers.ctrl {
grpc_modifiers |= ModifierMask::CTRL;
}
if modifiers.logo {
grpc_modifiers |= ModifierMask::SUPER;
}
let grpc_modifiers = ModifierMask::from(modifiers);
let raw_sym = keysym.raw_syms().iter().next();
let mod_sym = keysym.modified_sym();
@ -344,6 +372,8 @@ impl State {
};
let modifier_mask = crate::api::msg::ModifierMask::from(keyboard.modifier_state());
let grpc_modifier_mask = ModifierMask::from(keyboard.modifier_state());
// If any mousebinds are detected, call the config's callback and return.
if let Some(&callback_id) =
self.input_state
@ -363,6 +393,19 @@ impl State {
return;
}
let grpc_mouse_edge = match button_state {
ButtonState::Released => set_mousebind_request::MouseEdge::Release,
ButtonState::Pressed => set_mousebind_request::MouseEdge::Press,
};
if let Some(stream) =
self.input_state
.grpc_mousebinds
.get(&(grpc_modifier_mask, button, grpc_mouse_edge))
{
let _ = stream.send(Ok(SetMousebindResponse {}));
}
// If the button was clicked, focus on the window below if exists, else
// unfocus on windows.
if button_state == ButtonState::Pressed {