zellij icon indicating copy to clipboard operation
zellij copied to clipboard

Feature request: mouse any-event Tracking (1003)

Open AutumnMeowMeow opened this issue 2 years ago • 14 comments

Reference: https://www.invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Any-event-tracking

This would round out mouse support, permitting 1) applications to know the mouse position always, and 2) implement focus-follows-mouse for panes.

AutumnMeowMeow avatar Aug 19 '22 13:08 AutumnMeowMeow

I really like the "focus follows mouse" part, though I think we'll have to give some thoughts about the UX here. I'm not sure it should be on by default, at least... I guess we'll have to play around with it and see how it feels.

Another point that I'm pretty certain about: I think it would be best to only send mouse movements to the focused pane (assuming of course the movements are over said pane).

But regardless - I'd very much love to see this feature in Zellij. I guess we'll also have to place ourselves in any-event tracking mode. I wonder how wide-spread support for this is in terminals?

If you're interested in working on this @AutumnMeowMeow - I'd be happy to point you to the relevant parts of the code-base to get what you need (if you want me to, ofc).

imsnif avatar Aug 19 '22 19:08 imsnif

Another point that I'm pretty certain about: I think it would be best to only send mouse movements to the focused pane (assuming of course the movements are over said pane).

I believe the most common implementation for terminals and embedded terminal panes/widgets is:

  • No button down - mouse motion events are only passed to the terminal if the mouse is over that pane.
    • Looking at a few terminals: xterm, mlterm, contour will report events even if the window is not focused; wezterm only reports if the window is focused. I think it would make sense to either follow xterm's example and always send any-event if the mouse is over a pane whether focused or not; or make it configurable with whatever default you want.
  • Button down - mouse motion events are passed to the focused terminal, with the coordinates clamped to the terminal dimensions. (So no negative coordinates when click-dragging off screen.) This is the click-and-drag scenario.

I guess we'll also have to place ourselves in any-event tracking mode.

zellij can activate both button-event and any-event in that order on startup, like: "\x1b[?1002;1003h", and then zellij will get any-event if the host supports that, and button-event if the host doesn't support any-event but does support button-event. Easy graceful fallback. (And a good test for terminals that don't loop on all the DECSET parameters. :-) )

I wonder how wide-spread support for this is in terminals?

It's pretty common. All of the terminals listed here with "yes" in the "Mouse Cursor" column support Any-Event, including screen and tmux when their host console supports it. (I believe konsole does now too, and maybe DomTerm -- I haven't updated that page in some time.)

I would be interested in doing this one. My mental model so far is:

  • zellij-utils/src/input/event/mouse.rs: add a Motion(Position) to MouseEvent . Follow the compiler messages to all the cases.
  • zellij-client/src/os_input_output.rs: modify ENABLE_MOUSE_SUPPORT / DISABLE_MOUSE_SUPPORT to include 1003.
  • zellij-server/src/tab/unit/tab_integration_tests.rs: add sgr_mouse_mode_any_event tests
  • zellij-client/src/input_handler.rs add MouseEvent::Motion case to handle_mouse_event
  • zellij-server-src/pane/terminal_pane.rs: add fn mouse_motion()
  • zellij-server-src/pane/grid.rs: add AnyEventTracking to MouseTracking. Follow the compiler messages to all the cases.
  • zellij-server-src/pane/grid.rs: add mouse_motion_signal. Looks like I also need to modify all of the click signals to send any-event appropriately too when hold is true and tracking is any-event. (It seems like Hold could be removed in favor of Motion, as a simplifying refactor. But initially I would leave it.)

I have no idea on:

  • Where the actual decoding of the host terminal stream into mouse events occurs.
  • If any other widgets/plugins/etc. need to be modified to handle a new mouse event.

AutumnMeowMeow avatar Aug 19 '22 21:08 AutumnMeowMeow

I believe the most common implementation for terminals and embedded terminal panes/widgets is:

* No button down - mouse motion events are only passed to the terminal if the mouse is over that pane.
  
  * Looking at a few terminals: xterm, mlterm, contour will report events even if the window is not focused; wezterm only reports if the window is focused.  I think it would make sense to either follow xterm's example and always send any-event if the mouse is over a pane whether focused or not; or make it configurable with whatever default you want.

* Button down - mouse motion events are passed to the focused terminal, with the coordinates clamped to the terminal dimensions.  (So no negative coordinates when click-dragging off screen.)  This is the click-and-drag scenario.

I just have this feeling that with multiple panes open, having the cursor change the internal cursor location of panes I happen to pass over when trying to focus on a pane beyond them might be a little annoying. I'm definitely on board with having this configurable. Let's try out both options and see what we feel works better as a default?

zellij can activate both button-event and any-event in that order on startup, like: "\x1b[?1002;1003h", and then zellij will get any-event if the host supports that, and button-event if the host doesn't support any-event but does support button-event. Easy graceful fallback. (And a good test for terminals that don't loop on all the DECSET parameters. :-) )

:D

I would be interested in doing this one. My mental model so far is:

* zellij-utils/src/input/event/mouse.rs: add a Motion(Position) to MouseEvent .  Follow the compiler messages to all the cases.

* zellij-client/src/os_input_output.rs: modify ENABLE_MOUSE_SUPPORT / DISABLE_MOUSE_SUPPORT to include 1003.

* zellij-server/src/tab/unit/tab_integration_tests.rs: add sgr_mouse_mode_any_event tests

* zellij-client/src/input_handler.rs add MouseEvent::Motion case to handle_mouse_event

* zellij-server-src/pane/terminal_pane.rs: add fn mouse_motion()

* zellij-server-src/pane/grid.rs: add AnyEventTracking to MouseTracking.  Follow the compiler messages to all the cases.

* zellij-server-src/pane/grid.rs: add mouse_motion_signal.  Looks like I also need to modify all of the click signals to send any-event appropriately too when hold is true and tracking is any-event.  (It seems like Hold could be removed in favor of Motion, as a simplifying refactor.  But initially I would leave it.)

This all seems correct. Also @tlinford rightfully mentioned that we can probably do away with a lot of boilerplate by just passing a MouseEvent around instead of having separate methods of doing it. But we can leave things as they are for now I think.

I have no idea on:

* Where the actual decoding of the host terminal stream into mouse events occurs.

We use Wezterm's input parser here: https://github.com/zellij-org/zellij/blob/main/zellij-client/src/stdin_handler.rs#L47 Here we convert from the above lib's event to our own: https://github.com/zellij-org/zellij/blob/main/zellij-utils/src/input/mouse.rs#L22 - this happens here: https://github.com/zellij-org/zellij/blob/main/zellij-client/src/input_handler.rs#L96

* If any other widgets/plugins/etc. need to be modified to handle a new mouse event.

For now I don't think so. It would be cool to add this as a plugin capability, but I'm overhauling the plugin system soon, so I'd rather wait until that's done with.

imsnif avatar Aug 20 '22 17:08 imsnif

A question to think about for after any-event is in: Will zellij later support an optional floating text mouse cursor? Like this?

https://user-images.githubusercontent.com/99296476/185799572-70b98db6-a159-4618-8f75-6de93b3be199.mp4

In the video above, we have a demo running inside its own terminal window, analogous to how zellij-inside-zellij in a floating window might go. Since both outside demo and demo-inside-terminal are in any-event mode, and each inverts the cell where the mouse is, then when the mouse goes over the inside terminal with being double-inverted the mouse could disappear entirely.

My solution is for an "inner" window to notify the outside world that it will be drawing a text cursor, so the outside shouldn't draw one, via a privacy message:

ESC ^ hideMousePointer ESC \
ESC ^ showMousePointer ESC \

You can see both the implementation and the flaw: when not over the inner terminal, there are two mouse cursors.

Should zellij later on do floating mouse cursor, let me know if you do a different solution for this. zellij has a much larger user base, so I would change mine to match zellij.

AutumnMeowMeow avatar Aug 21 '22 16:08 AutumnMeowMeow

Sure @AutumnMeowMeow. IMO this is not a piece of UI I'd like to have - but we can keep this in mind if this changes.

imsnif avatar Aug 22 '22 07:08 imsnif

@AutumnMeowMeow any progress on this? I'm forever missing pane-resizing with the mouse #1262 and would need this to impl I believe.

jondo2010 avatar Jun 13 '23 09:06 jondo2010

@AutumnMeowMeow any progress on this? I'm forever missing pane-resizing with the mouse #1262 and would need this to impl I believe.

@jondo2010

Sorry, no progress to report. I have been mostly unable to code for the last year (again). :(

AutumnMeowMeow avatar Jun 21 '23 22:06 AutumnMeowMeow

I hope you are well @AutumnMeowMeow !

imsnif avatar Jun 22 '23 08:06 imsnif

sr, but would love to able to resize pane with mouse :)

with only this addition is what i really needed.

tmpm697 avatar Sep 04 '23 06:09 tmpm697