contents

Input devices#

carrot decodes evdev itself: no libinput, no libxkbcommon. Devices hotplug live, and pointer settings re-resolve per event, so a config reload applies instantly. Event timestamps ride the monotonic clock, the same base as the presentation clock, so nothing steps under ntp.

The input block#

input {
    keyboard {
        xkb { layout "us"; variant "colemak"; options "compose:ralt" }
        repeat-delay 600    // ms, 1..5000
        repeat-rate 25      // per second, 1..200
        numlock
    }
    touchpad { natural-scroll; accel-profile "flat"; accel-speed 0.2 }
    mouse { accel-profile "flat"; accel-speed 0.0 }
    device "name substring" { accel-speed -0.5; dpi 1600 }
    mod-key "super"
}

keyboard#

KeyTypeDefaultNotes
xkb { layout }stringunsetselects the keymap; needs xkeyboard-config on disk for non-US layouts
xkb { variant }, xkb { options }stringunsetparse today ahead of support; only layout is applied yet
repeat-rate1..20025repeats per second
repeat-delay1..5000600ms before repeat starts
numlockflagofflatch numlock at startup

With no layout set, carrot uses its embedded US keymap and never touches disk. A configured layout resolves against xkeyboard-config via XKB_CONFIG_ROOT or the standard system paths; if the data is missing, the error says which variable to set.

mouse and touchpad#

Both take accel-profile "flat"|"adaptive", accel-speed (-1.0..1.0), and natural-scroll. Touchpad tap and dwt are reserved and error with "not implemented yet"; gestures and touch are staged after the pointer work.

mod-key#

"super" or "alt": what Mod means in every bind chord. One config file works for both conventions by binding everything through Mod.

Per-device rules#

device "turtle-beach" {
    accel-speed -0.85
    accel-profile "flat"
    natural-scroll #false
    dpi 1600
}

Device names match loosely: the live name is lowercased with spaces and underscores turned to dashes, and a rule applies if its name is a substring of that. carrot input-probe lists your device names.

KeyDoes
accel-speedpointer speed, -1.0..1.0
accel-profileflat or adaptive, overriding the class setting
natural-scrolloverride per device
dpiyour mouse's real DPI (100..40000); deltas normalize to a 1000 DPI baseline so speed feels identical on any mouse

Without a dpi override, carrot reads DPI from udev's hardware database the same way libinput would.

Per-window key remaps#

Remap profiles rewrite keys for specific windows: give one stubborn game a different keyboard without touching the rest of the desktop. Minecraft speedrunners rebinding the F3 debug screen onto a reachable key, for example:

remap "mcsr" {
    match title="MCSR Ranked" workspace=6 is-xwayland=#false
    map "R" "F3"
}

While a window whose title contains MCSR Ranked sits focused on workspace 6, pressing R delivers F3; every other window sees the keyboard untouched.

Criteria on the match node AND together (app-id, title, is-xwayland, pid, workspace), and the first matching profile wins, in file order. app-id is an exact string, title a substring; workspace is 1-based. Each map "From" "To" uses the same key names as binds, and at least one is required. Find a window's matchable facts with burrow clients.

Cursor#

cursor { xcursor-theme "catppuccin-frappe-dark-cursors"; xcursor-size 24; software }

software forces the composited cursor. xcursor-theme and xcursor-size (1..512) pick the pointer theme; the config wins, and the XCURSOR_THEME/XCURSOR_SIZE environment variables keep working as the fallback.