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",
})| Field | Type | Default | Description |
|---|---|---|---|
numlock | boolean | true | Turn Num Lock on for each keyboard as it connects |
repeat_rate | integer | 25 | Repeats per second, 0–100; 0 disables repeat |
repeat_delay | integer | 200 | Milliseconds before repeat starts, 0–5000 |
layout | string | XKB default | Layout, or a list such as us,lv |
variant | string | XKB default | Variant; leave an entry empty for none, as in ,apostrophe |
options | string | XKB default | Comma-separated XKB options; "" clears them |
model | string | XKB default | Usually pc105 |
rules | string | XKB default | Usually 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,
})| Field | Type | Default | Description |
|---|---|---|---|
size | integer | 24 | Cursor size in logical pixels, 1–256 |
theme | string | backend | Installed xcursor theme name |
hide_on_key_press | boolean | false | Hide the cursor while you type until you use the mouse |
inactive_timeout | integer | 0 | Seconds 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 24Sweets 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" })| Selector | Trigger |
|---|---|
lid:closed / lid:open | The laptop lid closes or opens |
tablet_mode:on / tablet_mode:off | The 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.