Skip to content

Commit

Permalink
fix: windows: enable mouse mode on demand
Browse files Browse the repository at this point in the history
This fixes an issue where mouse mode is always enabled on Windows. With
this patch, we enable mouse events only it is requested.

Needs: charmbracelet/x#386
Related: #1313
  • Loading branch information
aymanbagabas committed Feb 24, 2025
1 parent ac139a6 commit bbe1cb0
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 5 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/charmbracelet/x/ansi v0.8.0
github.com/charmbracelet/x/cellbuf v0.0.12-0.20250212155406-f75055277088
github.com/charmbracelet/x/exp/golden v0.0.0-20241212170349-ad4b7ae0f25f
github.com/charmbracelet/x/input v0.3.3
github.com/charmbracelet/x/input v0.3.4-0.20250224172324-3bbc6f7ae9d3
github.com/charmbracelet/x/term v0.2.1
github.com/muesli/cancelreader v0.2.2
golang.org/x/sync v0.11.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ github.com/charmbracelet/x/exp/golden v0.0.0-20241212170349-ad4b7ae0f25f h1:UytX
github.com/charmbracelet/x/exp/golden v0.0.0-20241212170349-ad4b7ae0f25f/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
github.com/charmbracelet/x/input v0.3.3 h1:JfLopDmw7pFy6Sezr42RkRfy1UPTh3xDR4sM3PXrrGw=
github.com/charmbracelet/x/input v0.3.3/go.mod h1:JI8RcvdZWQIhn09VzeK3hdp4lTz7+yhiEdpEQtZN+2c=
github.com/charmbracelet/x/input v0.3.4-0.20250224172324-3bbc6f7ae9d3 h1:ZLj8cla3PwZR8RIcnjxepmUwXiN3l+TNxFX19UxmE/4=
github.com/charmbracelet/x/input v0.3.4-0.20250224172324-3bbc6f7ae9d3/go.mod h1:JI8RcvdZWQIhn09VzeK3hdp4lTz7+yhiEdpEQtZN+2c=
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
github.com/charmbracelet/x/windows v0.2.0 h1:ilXA1GJjTNkgOm94CLPeSz7rar54jtFatdmoiONPuEw=
Expand Down
37 changes: 35 additions & 2 deletions tea.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ type Program struct {
inputReader *input.Reader
traceInput bool // true if input should be traced
readLoopDone chan struct{}
mouseMode bool // indicates whether we should enable mouse on Windows

// modes keeps track of terminal modes that have been enabled or disabled.
modes ansi.Modes
Expand Down Expand Up @@ -550,6 +551,20 @@ func (p *Program) eventLoop(model Model, cmds chan Cmd) (Model, error) {
// and get a response in the eventLoop.
p.execute(ansi.SetGraphemeClusteringMode + ansi.RequestGraphemeClusteringMode)
default:
if runtime.GOOS == "windows" {
if msg.Mode == ansi.ButtonEventMouseMode || msg.Mode == ansi.AnyEventMouseMode {
// XXX: This is used to enable mouse mode on Windows. We need
// to reinitialize the cancel reader to get the mouse events to
// work.
if !p.mouseMode {
p.mouseMode = true
p.initInputReader(true) //nolint:errcheck
}

// We don't need to send reset mouse mode sequence on Windows.
break
}
}
p.execute(ansi.SetMode(msg.Mode))
}

Expand All @@ -567,6 +582,20 @@ func (p *Program) eventLoop(model Model, cmds chan Cmd) (Model, error) {
case ansi.TextCursorEnableMode:
p.renderer.hideCursor()
default:
if runtime.GOOS == "windows" {
if msg.Mode == ansi.ButtonEventMouseMode || msg.Mode == ansi.AnyEventMouseMode {
// XXX: On Windows, mouse mode is enabled on the input reader
// level. We need to instruct the input reader to stop reading
// mouse events.
if p.mouseMode {
p.mouseMode = false
p.initInputReader(true) //nolint:errcheck
}

// We don't need to send reset mouse mode sequence on Windows.
break
}
}
p.execute(ansi.ResetMode(msg.Mode))
}

Expand Down Expand Up @@ -896,7 +925,7 @@ func (p *Program) Run() (Model, error) {
// Init the input reader and initial model.
model := p.initialModel
if p.input != nil {
if err := p.initInputReader(); err != nil {
if err := p.initInputReader(false); err != nil {
return model, err
}
}
Expand Down Expand Up @@ -934,6 +963,10 @@ func (p *Program) Run() (Model, error) {
p.modes.Set(ansi.AnyEventMouseMode, ansi.SgrExtMouseMode)
}

// XXX: Should we enable mouse mode on Windows?
// This needs to happen before initializing the cancel and input reader.
p.mouseMode = p.startupOptions&withMouseCellMotion != 0 || p.startupOptions&withMouseAllMotion != 0

if p.startupOptions&withReportFocus != 0 {
p.execute(ansi.SetFocusEventMode)
p.modes.Set(ansi.FocusEventMode)
Expand Down Expand Up @@ -1112,7 +1145,7 @@ func (p *Program) RestoreTerminal() error {
if err := p.initTerminal(); err != nil {
return err
}
if err := p.initInputReader(); err != nil {
if err := p.initInputReader(false); err != nil {
return err
}
if p.modes.IsReset(ansi.AltScreenSaveCursorMode) {
Expand Down
13 changes: 11 additions & 2 deletions tty.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,24 @@ func (p *Program) restoreInput() error {
}

// initInputReader (re)commences reading inputs.
func (p *Program) initInputReader() error {
func (p *Program) initInputReader(cancel bool) error {
if cancel && p.inputReader != nil {
p.inputReader.Cancel()
p.waitForReadLoop()
}

term := p.getenv("TERM")

// Initialize the input reader.
// This need to be done after the terminal has been initialized and set to
// raw mode.
// On Windows, this will change the console mode to enable mouse and window
// events.
var flags int // TODO: make configurable through environment variables?
var flags int
if p.mouseMode {
flags |= input.FlagMouseMode
}

drv, err := input.NewReader(p.input, term, flags)
if err != nil {
return err
Expand Down

0 comments on commit bbe1cb0

Please sign in to comment.