obsidian/wiki/dotfiles/wezterm-mouse-bindings.md
2026-04-17 13:01:42 +01:00

5.6 KiB

title aliases tags sources created updated
WezTerm Mouse Bindings
wezterm-mouse
wezterm-mouse-config
wezterm
mouse
terminal
dotfiles
lua
raw/Mouse Binding - Wez's Terminal Emulator.md
2026-04-17 2026-04-17

Overview

WezTerm mouse bindings are fully configurable via Lua. By default, terminal applications can capture mouse events — WezTerm hands them through unless you intervene with a modifier key.

Mouse Reporting Bypass

When an app enables mouse tracking, WezTerm passes all mouse events to it rather than matching bindings. To force your bindings to fire anyway, hold SHIFT (default bypass modifier).

  • Change the bypass key via config.bypass_mouse_reporting_modifiers
  • Use mouse_reporting = true in a binding entry to target app-captured state (generally avoid this)

Default Mouse Assignments

Event Modifiers Action
Single Left Down NONE SelectTextAtMouseCursor("Cell")
Double Left Down NONE SelectTextAtMouseCursor("Word")
Triple Left Down NONE SelectTextAtMouseCursor("Line")
Single Left Down SHIFT ExtendSelectionToMouseCursor("Cell")
Single Left Down ALT SelectTextAtMouseCursor("Block")
Single Left Up NONE CompleteSelectionOrOpenLinkAtMouseCursor(...)
Single Left Up SHIFT CompleteSelectionOrOpenLinkAtMouseCursor(...)
Single Left Drag NONE ExtendSelectionToMouseCursor("Cell")
Single Left Drag ALT ExtendSelectionToMouseCursor("Block")
Double Left Drag NONE ExtendSelectionToMouseCursor("Word")
Triple Left Drag NONE ExtendSelectionToMouseCursor("Line")
Single Middle Down NONE PasteFrom("PrimarySelection")
Single Left Drag SUPER / CTRL+SHIFT StartWindowDrag

Run wezterm show-keys to inspect the effective bindings at runtime.

Disable all defaults with:

config.disable_default_mouse_bindings = true

Configuring Custom Mouse Bindings

local wezterm = require 'wezterm'
local act = wezterm.action

config.mouse_bindings = {
  -- Right click sends a string
  {
    event = { Down = { streak = 1, button = 'Right' } },
    mods = 'NONE',
    action = act.SendString 'woot',
  },
  -- CTRL-Click opens hyperlinks
  {
    event = { Up = { streak = 1, button = 'Left' } },
    mods = 'CTRL',
    action = act.OpenLinkAtMouseCursor,
  },
  -- Disable Down event to prevent leaking to app (see gotcha below)
  {
    event = { Down = { streak = 1, button = 'Left' } },
    mods = 'CTRL',
    action = act.Nop,
  },
}

Binding Entry Fields

Field Required Description
event yes Down, Up, or Drag + streak + button
mods yes Modifier keys (same syntax as key bindings)
action yes KeyAssignment action to perform
mouse_reporting no Match only when app mouse reporting is active (default false)
alt_screen no 'Any' (default), true, or false — match only in/out of alt screen

Event Lua Representation

-- Triple Left Down
event = { Down = { streak = 3, button = "Left" } }

-- Double Left Up
event = { Up = { streak = 2, button = "Left" } }

-- Single Left Drag
event = { Drag = { streak = 1, button = "Left" } }

Arbitrary click streaks are supported — streak = 4 for quadruple-click, etc.

Mouse Wheel Bindings

Wheel events use WheelUp / WheelDown as the button value:

-- CTRL+Scroll to resize font
{
  event = { Down = { streak = 1, button = { WheelUp = 1 } } },
  mods = 'CTRL',
  action = act.IncreaseFontSize,
},
{
  event = { Down = { streak = 1, button = { WheelDown = 1 } } },
  mods = 'CTRL',
  action = act.DecreaseFontSize,
},

streak and amount are fixed at 1 for wheel events in pattern matching. Use window:current_event inside a callback to get the actual delta.

Note: default scroll bindings use alt_screen = false — wheel maps to arrow keys in alt screen mode instead.

Gotcha: Binding Only the 'Up' Event

If you bind Up but not Down, the Down event is still forwarded to the running app (e.g. tmux, vim). This causes the app to see a Down without a matching Up — leading to stuck selection state or other glitches.

Fix: always pair an Up binding with a Down = act.Nop to suppress the Down event:

-- Good: suppress Down so app never sees it
{ event = { Up   = { streak = 1, button = 'Left' } }, mods = 'CTRL', action = act.OpenLinkAtMouseCursor },
{ event = { Down = { streak = 1, button = 'Left' } }, mods = 'CTRL', action = act.Nop },

Key Takeaways

  • Default bindings cover selection (cell/word/line/block), clipboard, link-open, and window drag
  • Apps can capture mouse events; hold SHIFT (or configured bypass mod) to force your bindings
  • Custom bindings go in config.mouse_bindings as a Lua table
  • Every entry needs event, mods, and action; mouse_reporting and alt_screen are optional filters
  • Wheel events use { WheelUp = 1 } / { WheelDown = 1 } as the button value
  • Always pair an Up binding with a Down = act.Nop to avoid leaking events to apps
  • wezterm show-keys shows the live effective binding table

Sources