Hyprland 0.57 refuses a bind on a bare modifier and an empty input:scroll_method. The switcher's Super-release commit now binds Super_L and Super_R, which also brings back every bind below it in keybinds.lua. An empty scroll method is left unwritten, so libinput still picks per device.
180 lines
9.4 KiB
Lua
180 lines
9.4 KiB
Lua
-- ─────────────────────────────────────────────────────────────────────────────
|
|
-- Input
|
|
--
|
|
-- Deliberately GNOME-like: click-to-focus, no focus-follows-mouse, no mouse
|
|
-- acceleration changes. The goal is that muscle memory transfers untouched.
|
|
-- ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
local prefs = require("prefs")
|
|
local actions = require("actions")
|
|
|
|
-- Empty means "let libinput pick per device". Hyprland 0.57 rejects "" for
|
|
-- this option, so empty is expressed by not writing it at all: nil drops the
|
|
-- key from the table below and the option stays at its unset default.
|
|
local scroll_method = prefs.get("scrollMethod", "")
|
|
if scroll_method == "" then
|
|
scroll_method = nil
|
|
end
|
|
|
|
hl.config({
|
|
input = {
|
|
kb_layout = prefs.get("keyboardLayout", "us"),
|
|
kb_variant = prefs.get("keyboardVariant", ""),
|
|
kb_model = "",
|
|
kb_options = prefs.get("keyboardOptions", "caps:escape_shifted_capslock"),
|
|
kb_rules = "",
|
|
|
|
numlock_by_default = prefs.get("numlockByDefault", true),
|
|
|
|
-- GNOME's defaults are 500ms delay / 33Hz repeat.
|
|
repeat_delay = prefs.get("keyRepeatDelay", 500),
|
|
repeat_rate = prefs.get("keyRepeatRate", 33),
|
|
|
|
-- 1 = FOLLOW. The window under the pointer takes focus. This comment
|
|
-- previously claimed 1 was "click to focus, GNOME's behavior", which
|
|
-- is the opposite of what Hyprland does -- `hyprctl descriptions` gives
|
|
-- map: [{"separate":3},{"detached":2},{"follow":1},{"disabled":0}],
|
|
-- so click-to-focus is 0. Changing the shipped value is a behavior
|
|
-- decision rather than a correction, so the value is left alone and
|
|
-- only the description is fixed; Settings exposes all four.
|
|
follow_mouse = prefs.getInt("followMouse", 1),
|
|
|
|
-- Softens follow_mouse: with this off, focus changes only when the
|
|
-- pointer crosses a window boundary, not on every movement inside one.
|
|
-- Still focus-follows-pointer, just less twitchy.
|
|
mouse_refocus = false,
|
|
|
|
-- 0 = NEXT, the compositor's own default: focus goes to the next window
|
|
-- in the layout order. `hyprctl descriptions` publishes
|
|
-- map: [{"mru":2},{"cursor":1},{"next":0}], and Settings offers all
|
|
-- three; 0 is repeated here so nothing changes on a machine with no
|
|
-- settings file.
|
|
focus_on_close = prefs.getInt("focusOnClose", 0),
|
|
|
|
-- Flat pointer response by default, no acceleration. Matters for
|
|
-- gaming; Settings offers adaptive for people who want it back.
|
|
sensitivity = prefs.get("pointerSensitivity", 0),
|
|
accel_profile = prefs.get("accelProfile", "flat"),
|
|
|
|
natural_scroll = prefs.get("naturalScroll", false),
|
|
scroll_factor = prefs.get("scrollFactor", 1.0),
|
|
left_handed = prefs.get("leftHanded", false),
|
|
|
|
-- Empty (omitted, see above) is what `hyprctl getoption` reports as
|
|
-- "[[EMPTY]]": libinput picks per device -- two fingers on a touchpad,
|
|
-- the wheel on a mouse. Settings offers 2fg / edge / on_button_down /
|
|
-- no_scroll alongside it, the four words the option's own description
|
|
-- names (it publishes no map).
|
|
scroll_method = scroll_method,
|
|
|
|
-- Only consulted while scroll_method is on_button_down. 0 means the
|
|
-- device's own middle button.
|
|
scroll_button = prefs.get("scrollButton", 0),
|
|
|
|
-- Clicking a floating window raises and focuses it.
|
|
float_switch_override_focus = 2,
|
|
|
|
-- Every touchpad preference Settings offers is read here as well as
|
|
-- applied live: the live half (hyprctl eval) reaches a running
|
|
-- compositor, and THIS half is what survives `hyprctl reload` and the
|
|
-- gap before the shell starts. A schema `hypr:` entry without a
|
|
-- prefs.get() here is a control that quietly reverts -- the whole
|
|
-- Mouse & Touchpad page once had exactly that bug. Defaults must
|
|
-- match PreferenceSchema's; the hypr-prefs-contract checks both.
|
|
touchpad = {
|
|
tap_to_click = prefs.get("touchpadTapToClick", true),
|
|
natural_scroll = prefs.get("touchpadNaturalScroll", true),
|
|
disable_while_typing = prefs.get("touchpadDisableWhileTyping", true),
|
|
scroll_factor = prefs.get("touchpadScrollFactor", 1.0),
|
|
drag_lock = prefs.getInt("touchpadDragLock", 0),
|
|
middle_button_emulation = prefs.get("touchpadMiddleButtonEmulation", false),
|
|
clickfinger_behavior = prefs.get("touchpadClickfinger", false),
|
|
|
|
-- Underscores here, hyphens in the option name getoption answers to
|
|
-- (input:touchpad:tap-and-drag) -- the same split tap_to_click has
|
|
-- at the top of this table. Hyprland's own default is true; it is
|
|
-- repeated rather than omitted so the schema, the Lua, and the
|
|
-- compositor all state the same value.
|
|
tap_and_drag = prefs.get("touchpadTapAndDrag", true),
|
|
},
|
|
},
|
|
|
|
-- Pointer BEHAVIOUR, as opposed to pointer appearance: how the cursor reacts
|
|
-- to typing and to workspace switches. The cursor's looks -- theme, size,
|
|
-- hardware cursors, the inactivity fade -- are a separate cursor table in
|
|
-- looks.lua. hl.config calls are additive per option, so the two tables
|
|
-- coexist; they are split by what a person would go looking for, and these
|
|
-- two appear on Settings' Mouse & Touchpad page rather than in Appearance.
|
|
cursor = {
|
|
hide_on_key_press = prefs.get("cursorHideWhileTyping", false),
|
|
|
|
-- An integer with three states, written from a switch: disable = 0,
|
|
-- enable = 1, force = 2. Settings offers the first two, so getInt is
|
|
-- what bridges a stored boolean to the number Hyprland wants -- the same
|
|
-- pairing render.cm_auto_hdr uses in looks.lua.
|
|
warp_on_change_workspace = prefs.getInt("cursorWarpOnWorkspaceChange", 0),
|
|
},
|
|
|
|
-- Tuning for the three-finger gestures registered below.
|
|
gestures = {
|
|
workspace_swipe_distance = prefs.getInt("swipeDistance", 300),
|
|
workspace_swipe_invert = prefs.get("swipeInvert", true),
|
|
},
|
|
})
|
|
|
|
-- ── Touchpad gestures ───────────────────────────────────────────────────────
|
|
--
|
|
-- GNOME's gestures, reproduced: three fingers sideways moves between
|
|
-- workspaces, three fingers up opens the overview, three fingers down closes
|
|
-- it. That is the same muscle memory the keybinds were built to preserve.
|
|
--
|
|
-- Registered unconditionally rather than behind a preference. Hyprland 0.56
|
|
-- dropped `gestures:workspace_swipe` in favour of this `gesture` keyword, and a
|
|
-- registration is read at config time -- so a toggle would need a reload to
|
|
-- take effect, which is worse than the nothing these cost on a machine with no
|
|
-- touchpad. What IS tunable at runtime lives in Settings: how far a swipe has
|
|
-- to travel, and which way round it goes.
|
|
--
|
|
-- open and close rather than toggle twice: with a toggle on both directions,
|
|
-- swiping up from an already-open overview would close it, and swiping down
|
|
-- would reopen it. GNOME does not do that, and neither does this.
|
|
local overview = function(fn)
|
|
return function() hl.exec_cmd("qs ipc call overview " .. fn) end
|
|
end
|
|
|
|
hl.gesture({ fingers = 3, direction = "horizontal", action = "workspace" })
|
|
hl.gesture({ fingers = 3, direction = "up", action = overview("open") })
|
|
hl.gesture({ fingers = 3, direction = "down", action = overview("close") })
|
|
|
|
-- ── Four-finger gestures ────────────────────────────────────────────────────
|
|
--
|
|
-- The three above are the desktop's, fixed. These four are the user's: each
|
|
-- holds a named action from settings.json, or {} for unassigned, and the
|
|
-- vocabulary is exactly the one custom shortcuts use -- actions.lua resolves
|
|
-- both, through the same whitelist tables, so a gesture can no more introduce
|
|
-- a command than a keybind can.
|
|
--
|
|
-- Nothing is emitted for an unassigned direction. That matters more here than
|
|
-- it looks: a registration is read at config time and there is no way to
|
|
-- remove one afterwards, so emitting a no-op gesture for every direction would
|
|
-- consume the four-finger swipes permanently, including for whatever the
|
|
-- compositor might do with them later.
|
|
--
|
|
-- Four rather than three because three is spoken for, and because four fingers
|
|
-- is the largest number of them a touchpad this size can tell apart.
|
|
local custom_gestures = {
|
|
{ pref = "gestureFourUp", direction = "up" },
|
|
{ pref = "gestureFourDown", direction = "down" },
|
|
{ pref = "gestureFourLeft", direction = "left" },
|
|
{ pref = "gestureFourRight", direction = "right" },
|
|
}
|
|
|
|
for _, gesture in ipairs(custom_gestures) do
|
|
local action = actions.gesture(prefs.get(gesture.pref, {}))
|
|
if action ~= nil then
|
|
hl.gesture({ fingers = 4, direction = gesture.direction, action = action })
|
|
end
|
|
end
|
|
|
|
return true
|