Sweets
Configuration

Input Devices

Keyboard, cursor, and hardware-switch configuration

sweets.keyboard

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",
})
FieldTypeDefaultDescription
numlockbooleantrueTurn Num Lock on for each keyboard as it connects
repeat_rateinteger25Repeats per second, 0100; 0 disables repeat
repeat_delayinteger200Milliseconds before repeat starts, 05000
layoutstringXKB defaultLayout, or a list such as us,lv
variantstringXKB defaultVariant; leave an entry empty for none, as in ,apostrophe
optionsstringXKB defaultComma-separated XKB options; "" clears them
modelstringXKB defaultUsually pc105
rulesstringXKB defaultUsually evdev

For a faster backspace, try repeat_rate = 50 with repeat_delay = 250.

Omitted XKB fields keep the system default, normally from XKB_DEFAULT_*. Sweets compiles the keymap before accepting a reload, so a bad layout keeps the active configuration. Virtual keyboards keep their own keymap.

Switching layout

Bind keyboard_layout to switch between the layouts in layout. The argument is next, prev, or a position in the list starting at 1.

sweets.keyboard({ layout = "us,lv", variant = ",apostrophe" })

sweets.bind("MOD+space", "keyboard_layout", "next")
sweets.bind("MOD+F1", "keyboard_layout", 1)
sweets.bind("MOD+F2", "keyboard_layout", 2)

Your other bindings keep working in every layout. MOD+D still reaches its action while a non-Latin layout is active.

XKB compiles at most four layouts and drops any after the fourth, so an index above 4 is rejected.

A keyboard_layout binding does not work on the lock screen. Use an XKB option such as options = "grp:alt_shift_toggle" if you need to change layout while locked.

sweets.cursor

sweets.cursor({
  size = 24,
  theme = "Adwaita",
  hide_on_key_press = false,
  inactive_timeout = 0,
})
FieldTypeDefaultDescription
sizeinteger24Cursor size in logical pixels, 1256
themestringbackendInstalled xcursor theme name
hide_on_key_pressbooleanfalseHide the cursor while you type until you use the mouse
inactive_timeoutinteger0Seconds without mouse input before hiding; 0 never hides

All apply on reload. An unknown theme falls back to whatever xcursor resolves.

hide_on_key_press

Set this to keep the pointer out of the way while you type. Any key press on a real keyboard hides the cursor. Moving the mouse, clicking, or scrolling brings it back.

Typing does not move the pointer, so clicking where it was hidden still works.

Keys sent by a virtual keyboard, such as an on-screen keyboard or a remote-control tool, do not hide the cursor.

inactive_timeout

Set this to a number of seconds to hide a cursor you have left alone. Moving the mouse, clicking, or scrolling brings it back and restarts the countdown.

Typing does not count, so the cursor still disappears while you write even without hide_on_key_press. Use hide_on_key_press instead when you want it gone the moment you start typing.

Keys and pointer events sent by virtual devices do not restart the countdown.

pointer.hide_when_following hides the cursor for a third reason, after Sweets moves it for you. All three are independent, and turning one off leaves a cursor hidden by another alone.

How clients pick this up

Modern clients ask the compositor for a named cursor shape through cursor-shape-v1. Sweets draws those from your theme at the right size and per-monitor scale, so they always match and update on reload.

Clients that draw their own cursor read XCURSOR_SIZE and XCURSOR_THEME. Sweets exports both, but they are read at startup, so only newly launched programs see a change.

Some GTK, Electron, and Firefox builds read GSettings instead. Set the same values there if an application ignores both:

gsettings set org.gnome.desktop.interface cursor-theme 'breeze_cursors'
gsettings set org.gnome.desktop.interface cursor-size 24

Sweets does not write GSettings itself. A client drawing its own cursor on a fractionally scaled monitor may not scale XCURSOR_SIZE, so its cursor can look small. cursor-shape-v1 clients never have this problem.

sweets.bind_switch

Hardware switches do nothing by default. Bind a command to a transition:

sweets.bind_switch("lid:closed", "spawn", { "veila", "lock" })
sweets.bind_switch("lid:open", "spawn", { "notify-send", "Lid opened" })
sweets.bind_switch("tablet_mode:on", "spawn", { "wvkbd-mobintl" })
sweets.bind_switch("tablet_mode:off", "spawn", { "pkill", "wvkbd-mobintl" })
SelectorTrigger
lid:closed / lid:openThe laptop lid closes or opens
tablet_mode:on / tablet_mode:offThe tablet-mode switch changes

Only spawn is accepted, using the same no-shell argument array as a key binding. Several bindings may match one event and run in declaration order. They keep working while the session is locked, so a lid policy still applies.

The state at startup does not run a command, and repeated reports are ignored. A lid opened during suspend still runs lid:open when the laptop wakes. A reload affects later transitions only. sweets msg inputs shows the switches Sweets can see. The nested backend has no physical switches.

Sweets never locks, suspends, or powers off displays on its own. Use one locker or policy command so locking is established before the display changes.

Touchscreen, tablet tool, and tablet pad routing are not implemented yet.

On this page