Input Devices
Keyboard, cursor, touch, tablet, and switch-device support.
These blocks configure the keyboards and the pointer cursor image. Sweets also routes touchscreen input, offers a pointer-compatible tablet fallback, and can run explicit commands for hardware switch events.
sweets.keyboard{ ... }
Keyboard settings apply to physical keyboards and re-apply on reload.
sweets.keyboard({
numlock = true,
repeat_rate = 25,
repeat_delay = 600,
layout = "us,lv",
variant = ",apostrophe",
options = "grp:alt_shift_toggle,caps:escape",
model = "pc105",
rules = "evdev",
})| Key | Type | Default | Description |
|---|---|---|---|
numlock | bool | true | Lock the numpad on at startup so the keypad types digits without pressing Num Lock; set false to leave it off |
repeat_rate | int | 25 | Held-key repeats per second (0–1000). Higher repeats faster; 0 disables key repeat |
repeat_delay | int | 600 | Milliseconds a key is held before repeating begins (0–10000). Lower starts repeating sooner |
layout | string | XKB default | XKB layout, or comma-separated layouts such as us,lv |
variant | string | XKB default | XKB variant, using an empty entry for a layout with no variant, e.g. ,apostrophe |
options | string | XKB default | Comma-separated XKB options such as grp:alt_shift_toggle,caps:escape; "" explicitly clears them |
model | string | XKB default | XKB model, normally pc105 |
rules | string | XKB default | XKB rules file, normally evdev |
Sweets locks Num Lock on for each keyboard as it connects, so the numpad works
from the start of a session. Set numlock = false to keep the previous behavior
where Num Lock starts off.
repeat_rate and repeat_delay control held-key repeat, sent to clients over
the Wayland keyboard protocol. To make backspace (or any key) clear faster, raise
repeat_rate and/or lower repeat_delay, e.g. repeat_rate = 50 and
repeat_delay = 250. Both re-apply to every connected keyboard on reload.
layout, variant, options, model, and rules use standard XKB names.
Omit a field to retain the system XKB default, normally derived from
XKB_DEFAULT_*. Sweets validates that the complete keymap can compile before
accepting a reload, so an invalid layout keeps the active configuration and
keymap. Virtual keyboards retain the keymap supplied by their client or input
method.
sweets.cursor{ ... }
Cursor settings control the pointer image size and xcursor theme.
sweets.cursor({
size = 24,
-- theme = "Adwaita",
})| Key | Type | Default | Description |
|---|---|---|---|
size | integer | 24 | Cursor size in logical pixels (1–256) |
theme | string | backend | Installed xcursor theme name; omit to use the backend default theme |
Changes apply on automatic or manual hot reload. An unknown theme name falls back to whatever the xcursor library resolves.
How client cursors follow
size and theme set the compositor-drawn cursor (empty desktop, window
borders). They also drive client cursors through two mechanisms:
cursor-shape-v1(preferred). Modern clients (Zed, recent GTK and Qt, SDL3, …) ask for a named cursor shape and Sweets draws it from the configured theme at the correct size and per-output scale. These clients always match the compositor cursor, including on fractionally scaled outputs, and update live on hot reload.XCURSOR_SIZE/XCURSOR_THEMEenv vars (fallback). Clients that draw their own xcursor instead of usingcursor-shape-v1read these. Sweets exports them so spawned programs inherit a matching cursor. They are read at startup, so only programs launched afterward pick up a change — already running clients keep their cursor until they restart.
A few GTK/Electron/Firefox builds still take the cursor theme and size from
GSettings (org.gnome.desktop.interface cursor-theme / cursor-size) via the
desktop portal. If such an app does not follow the mechanisms above, set the same
values there too:
gsettings set org.gnome.desktop.interface cursor-theme 'breeze_cursors'
gsettings set org.gnome.desktop.interface cursor-size 24Sweets does not write GSettings itself, to avoid mutating global desktop
state. Clients drawing their own xcursor on a fractionally scaled output may
not multiply XCURSOR_SIZE by the scale, so their cursor can look small;
cursor-shape-v1 avoids this because the compositor does the scaling.
Touchscreens and tablet tools
Touchscreen contacts are delivered natively through the Wayland touch protocol. They keep their initial target surface until release, support multiple contacts, and update idle activity like pointer and keyboard input. Tapping an XDG window focuses it.
Sweets advertises tablet-v2 for tablet-aware Wayland applications. Pen motion,
tip and stylus buttons, pressure, distance, tilt, rotation, slider, and wheel
axes are delivered through the native tablet protocol. Tablet pads attached to
the same libinput device group forward pad buttons, rings, and strips to that
application too.
On surfaces that do not bind tablet-v2, a tablet remains useful through the
pointer fallback: pen motion moves the cursor and tip/button events become
regular pointer events. sweetctl inputs lists a separate tablet_pad entry
when the hardware exposes one.
sweets.bindswitch(selector, command)
Hardware switch events do nothing by default. Bind an explicit command when a device changes state:
sweets.bindswitch("lid:closed", "veila")
sweets.bindswitch("lid:closed", "sweetctl output all power off")
sweets.bindswitch("lid:open", "sweetctl output all power on")| Selector | Trigger |
|---|---|
lid:closed / lid:open | Laptop lid closes or opens |
tablet_mode:on / tablet_mode:off | Convertible/tablet-mode switch changes |
keypad_slide:on / keypad_slide:off | Hardware keypad-slide switch changes |
on and off are accepted as aliases for every switch state. Multiple commands
can match the same event and run in config order. Commands are spawned detached,
just like sweets.bind(..., "spawn", command).