Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ cliclack = "0.3.7"
drm-sys = "0.8.0"
gag = "1.0.0"
indexmap = { workspace = true }
input = { version = "0.9.1", features = ["libinput_1_21"] }
itertools = "0.14.0"
libdisplay-info = "0.3.0"
passfd = { workspace = true }
Expand Down
118 changes: 118 additions & 0 deletions api/lua/pinnacle/grpc/defs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,25 @@ local pinnacle_input_v1_Edge = {
EDGE_RELEASE = 2,
}

---@enum pinnacle.input.v1.GestureDirection
local pinnacle_input_v1_GestureDirection = {
DOWN = 0,
LEFT = 1,
RIGHT = 2,
UP = 3,
DOWN_AND_LEFT = 4,
DOWN_AND_RIGHT = 5,
UP_AND_LEFT = 6,
UP_AND_RIGHT = 7,
}

---@enum pinnacle.input.v1.GestureType
local pinnacle_input_v1_GestureType = {
HOLD = 0,
PINCH = 1,
SWIPE = 2,
}

---@enum pinnacle.input.v1.ClickMethod
local pinnacle_input_v1_ClickMethod = {
CLICK_METHOD_UNSPECIFIED = 0,
Expand Down Expand Up @@ -675,6 +694,7 @@ local pinnacle_v1_Backend = {
---@field properties pinnacle.input.v1.BindProperties?
---@field key pinnacle.input.v1.Keybind?
---@field mouse pinnacle.input.v1.Mousebind?
---@field gesture pinnacle.input.v1.Gesturebind?

---@class pinnacle.input.v1.BindRequest
---@field bind pinnacle.input.v1.Bind?
Expand Down Expand Up @@ -718,6 +738,26 @@ local pinnacle_v1_Backend = {
---@class pinnacle.input.v1.MousebindOnPressRequest
---@field bind_id integer?

---@class pinnacle.input.v1.Gesturebind
---@field direction pinnacle.input.v1.GestureDirection?
---@field fingers integer?
---@field gesture_type pinnacle.input.v1.GestureType?

---@class pinnacle.input.v1.GesturebindStreamRequest
---@field bind_id integer?

---@class pinnacle.input.v1.GesturebindStreamResponse
---@field edge pinnacle.input.v1.Edge?

---@class pinnacle.input.v1.GesturebindRequest
---@field bind_id integer?

---@class pinnacle.input.v1.GesturebindOnBeginRequest
---@field bind_id integer?

---@class pinnacle.input.v1.GesturebindOnFinishRequest
---@field bind_id integer?

---@class pinnacle.input.v1.GetBindInfosRequest

---@class pinnacle.input.v1.GetBindInfosResponse
Expand Down Expand Up @@ -1431,6 +1471,12 @@ pinnacle.input.v1.Mousebind = {}
pinnacle.input.v1.MousebindStreamRequest = {}
pinnacle.input.v1.MousebindStreamResponse = {}
pinnacle.input.v1.MousebindOnPressRequest = {}
pinnacle.input.v1.Gesturebind = {}
pinnacle.input.v1.GesturebindStreamRequest = {}
pinnacle.input.v1.GesturebindStreamResponse = {}
pinnacle.input.v1.GesturebindRequest = {}
pinnacle.input.v1.GesturebindOnBeginRequest = {}
pinnacle.input.v1.GesturebindOnFinishRequest = {}
pinnacle.input.v1.GetBindInfosRequest = {}
pinnacle.input.v1.GetBindInfosResponse = {}
pinnacle.input.v1.BindInfo = {}
Expand Down Expand Up @@ -1642,6 +1688,8 @@ pinnacle.util.v1.AbsOrRel = pinnacle_util_v1_AbsOrRel
pinnacle.util.v1.Dir = pinnacle_util_v1_Dir
pinnacle.input.v1.Modifier = pinnacle_input_v1_Modifier
pinnacle.input.v1.Edge = pinnacle_input_v1_Edge
pinnacle.input.v1.GestureDirection = pinnacle_input_v1_GestureDirection
pinnacle.input.v1.GestureType = pinnacle_input_v1_GestureType
pinnacle.input.v1.ClickMethod = pinnacle_input_v1_ClickMethod
pinnacle.input.v1.AccelProfile = pinnacle_input_v1_AccelProfile
pinnacle.input.v1.ScrollMethod = pinnacle_input_v1_ScrollMethod
Expand Down Expand Up @@ -1850,6 +1898,25 @@ pinnacle.input.v1.InputService.MousebindStream.response = ".pinnacle.input.v1.Mo
function Client:pinnacle_input_v1_InputService_MousebindStream(data, callback)
return self:server_streaming_request(pinnacle.input.v1.InputService.MousebindStream, data, callback)
end
pinnacle.input.v1.InputService.GesturebindStream = {}
pinnacle.input.v1.InputService.GesturebindStream.service = "pinnacle.input.v1.InputService"
pinnacle.input.v1.InputService.GesturebindStream.method = "GesturebindStream"
pinnacle.input.v1.InputService.GesturebindStream.request = ".pinnacle.input.v1.GesturebindStreamRequest"
pinnacle.input.v1.InputService.GesturebindStream.response = ".pinnacle.input.v1.GesturebindStreamResponse"

---Performs a server-streaming request.
---
---`callback` will be called with every streamed response.
---
---@nodiscard
---
---@param data pinnacle.input.v1.GesturebindStreamRequest
---@param callback fun(response: pinnacle.input.v1.GesturebindStreamResponse)
---
---@return string | nil An error string, if any
function Client:pinnacle_input_v1_InputService_GesturebindStream(data, callback)
return self:server_streaming_request(pinnacle.input.v1.InputService.GesturebindStream, data, callback)
end
pinnacle.input.v1.InputService.KeybindOnPress = {}
pinnacle.input.v1.InputService.KeybindOnPress.service = "pinnacle.input.v1.InputService"
pinnacle.input.v1.InputService.KeybindOnPress.method = "KeybindOnPress"
Expand Down Expand Up @@ -1884,6 +1951,57 @@ pinnacle.input.v1.InputService.MousebindOnPress.response = ".google.protobuf.Emp
function Client:pinnacle_input_v1_InputService_MousebindOnPress(data)
return self:unary_request(pinnacle.input.v1.InputService.MousebindOnPress, data)
end
pinnacle.input.v1.InputService.Gesturebind = {}
pinnacle.input.v1.InputService.Gesturebind.service = "pinnacle.input.v1.InputService"
pinnacle.input.v1.InputService.Gesturebind.method = "Gesturebind"
pinnacle.input.v1.InputService.Gesturebind.request = ".pinnacle.input.v1.GesturebindRequest"
pinnacle.input.v1.InputService.Gesturebind.response = ".google.protobuf.Empty"

---Performs a unary request.
---
---@nodiscard
---
---@param data pinnacle.input.v1.GesturebindRequest
---
---@return google.protobuf.Empty | nil response
---@return string | nil error An error string, if any
function Client:pinnacle_input_v1_InputService_Gesturebind(data)
return self:unary_request(pinnacle.input.v1.InputService.Gesturebind, data)
end
pinnacle.input.v1.InputService.GesturebindOnBegin = {}
pinnacle.input.v1.InputService.GesturebindOnBegin.service = "pinnacle.input.v1.InputService"
pinnacle.input.v1.InputService.GesturebindOnBegin.method = "GesturebindOnBegin"
pinnacle.input.v1.InputService.GesturebindOnBegin.request = ".pinnacle.input.v1.GesturebindOnBeginRequest"
pinnacle.input.v1.InputService.GesturebindOnBegin.response = ".google.protobuf.Empty"

---Performs a unary request.
---
---@nodiscard
---
---@param data pinnacle.input.v1.GesturebindOnBeginRequest
---
---@return google.protobuf.Empty | nil response
---@return string | nil error An error string, if any
function Client:pinnacle_input_v1_InputService_GesturebindOnBegin(data)
return self:unary_request(pinnacle.input.v1.InputService.GesturebindOnBegin, data)
end
pinnacle.input.v1.InputService.GesturebindOnFinish = {}
pinnacle.input.v1.InputService.GesturebindOnFinish.service = "pinnacle.input.v1.InputService"
pinnacle.input.v1.InputService.GesturebindOnFinish.method = "GesturebindOnFinish"
pinnacle.input.v1.InputService.GesturebindOnFinish.request = ".pinnacle.input.v1.GesturebindOnFinishRequest"
pinnacle.input.v1.InputService.GesturebindOnFinish.response = ".google.protobuf.Empty"

---Performs a unary request.
---
---@nodiscard
---
---@param data pinnacle.input.v1.GesturebindOnFinishRequest
---
---@return google.protobuf.Empty | nil response
---@return string | nil error An error string, if any
function Client:pinnacle_input_v1_InputService_GesturebindOnFinish(data)
return self:unary_request(pinnacle.input.v1.InputService.GesturebindOnFinish, data)
end
pinnacle.input.v1.InputService.SetXkbConfig = {}
pinnacle.input.v1.InputService.SetXkbConfig.service = "pinnacle.input.v1.InputService"
pinnacle.input.v1.InputService.SetXkbConfig.method = "SetXkbConfig"
Expand Down
136 changes: 136 additions & 0 deletions api/lua/pinnacle/input.lua
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,142 @@ function input.mousebind(mods, button, on_press, bind_info)
mousebind_inner(mb)
end

---A gesturebind.
---@class pinnacle.input.gesturebind : pinnacle.input.Bind
---The gesture button that will trigger this bind.
---@field button pinnacle.input.gestureButton
---An action that will be run when the gesturebind is started.
---@field on_begin fun()?
---An action that will be run when the gesturebind is finished.
---@field on_finish fun()?

---@param mb pinnacle.input.gesturebind
local function gesturebind_inner(gb)
local modifs = {}
local ignore_modifs = {}
for _, mod in ipairs(gb.mods) do
if string.match(mod, "ignore") then
table.insert(ignore_modifs, mods_with_ignore_values[mod])
else
table.insert(modifs, mods_with_ignore_values[mod])
end
end

local response, err = client:pinnacle_input_v1_InputService_Bind({
bind = {
mods = modifs,
ignore_mods = ignore_modifs,
layer_name = gb.bind_layer,
properties = {
group = gb.group,
description = gb.description,
quit = gb.quit,
reload_config = gb.reload_config,
allow_when_locked = gb.allow_when_locked,
},
gesture = {
button = gesture_button_values[gb.button],
},
},
})

if err then
log.error(err)
return
end

assert(response)

local bind_id = response.bind_id or 0

local err = client:pinnacle_input_v1_InputService_gesturebindStream({
bind_id = bind_id,
}, function(response)
if response.edge == edge_values.press then
if gb.on_press then
local success, error = pcall(gb.on_press)
if not success then
log.error("While handling `gesturebind:on_press`: " .. tostring(error))
end
end
elseif response.edge == edge_values.release then
if gb.on_release then
local success, error = pcall(gb.on_release)
if not success then
log.error("While handling `gesturebind:on_release`: " .. tostring(error))
end
end
end
end)

if gb.on_press then
local _, err = client:pinnacle_input_v1_InputService_gesturebindOnPress({
bind_id = bind_id,
})
end

if err then
log.error(err)
return
end
end

---Sets a gesturebind.
---
---This function can be called in two ways:
---1. As `Input.gesturebind(mods, button, on_press, bind_info?)`
---2. As `Input.gesturebind(<gesturebind table>)`
---
---Calling this with a `gesturebind` table gives you more options, including the ability to assign a bind layer
---to the keybind or set it to happen on release instead of press.
---
---When calling using the first way, you must provide three arguments:
---
--- - `mods`: An array of `Modifier`s. If you don't want any, provide an empty table.
--- - `button`: The gesture button.
--- - `on_press`: The function that will be run when the button is pressed.
---
---#### Ignoring Modifiers
---Normally, modifiers that are not specified will require the bind to not have them held down.
---You can ignore this by adding the corresponding `"ignore_*"` modifier.
---
---#### Descriptions
---You can specify a group and description for the bind.
---This will be used to categorize the bind in the bind overlay and provide a description.
---
---#### Example
---```lua
--- -- Set `super + left gesture button` to move a window on press
---Input.gesturebind({ "super" }, "btn_left", "press", function()
--- Window.begin_move("btn_left")
---end)
---```
---
---@param mods pinnacle.input.Mod[] The modifiers that need to be held down for the bind to trigger
---@param button pinnacle.input.gestureButton The gesture button used to trigger the bind
---@param on_press fun() The function to run when the bind is triggered
---@param bind_info { group: string?, description: string? }? An optional group and description that will be displayed in the bind overlay.
---
---@overload fun(gesturebind: pinnacle.input.gesturebind)
function input.gesturebind(mods, button, on_press, bind_info)
---@type pinnacle.input.gesturebind
local mb

if mods.button then
mb = mods
else
mb = {
mods = mods,
button = button,
on_press = on_press,
group = bind_info and bind_info.group,
description = bind_info and bind_info.description,
}
end

gesturebind_inner(mb)
end

---Enters the bind layer `layer`, or the default layer if `layer` is nil.
---
---@param layer string? The bind layer.
Expand Down
Loading
Loading