Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Attempt to add basic mouse support #1038

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft

Conversation

qsdrqs
Copy link

@qsdrqs qsdrqs commented May 15, 2024

Hi. Thanks for this amazing project! This is an attempt to add mouse support to yazi. I make it as a draft PR because I think it still needs tasks to be done before it can be merged. But I would appreciate it if I could get some early feedback from reviewing and help me to know what is the next step.

This PR tries to enable capturing MouseEvent in the terminal and spawn it to the App struct, then App will try to dispatch this event and route this event to the mouse method in different components (Header, Manager, and Status), based on coordination comparison between mouse event and Rect from Layout. The Manager is a special case. Because in LAYOUT, Manager is divided into Current, Parent and Preview. So I create a new enum ManagerComponent to indicate which specific component in Manager this MouseEvent belongs to and pass it as an argument. The mouse method will finally encapsulate the MouseEvent as lua object and invoke the corresponding mouse method in lua field.

In the lua field, I create a new type named MouseEvent, which contains the following attributes:

Field Description
x Column offset relative to the triggered component
y Row offset relative to the triggered component
kind Kind of mouse event
button Triggered button of mouse event, will be nil for events that are not Down, Up, and Drag
modifiers Key Modifiers of mouse event, passed as u8 value

The different kind and button are indicated as different numbers, specifically:

For kind:

Kind Value
Down 0
Up 1
Drag 2
Moved 3
ScrollDown 4
ScrollUp 5
ScrollLeft 6
ScrollRight 7

For button

Button Value
Left 0
Right 1
Middle 2

button will be nil for events other than Down, Up, and Drag.


Currently, only "left click to jump" is fully supported by lua script, which is implemented by ya.manager_emit("reveal", { f.url }). For scrolling, only Current window supports item-based scrolling. Scrolling in Preview will invoke the seek in the preview window.

Here are some potential things that people may like to see:

  • Support page-based scrolling like ranger
  • Support scrolling in Preview and Parent window

AFAIK, both of them need a new API for ya.manager_emit to invoke. If you think that's a good idea, I will try to implement these. Before that, it would be great if you could review the current implementation and provide some feedback.

@sxyazi
Copy link
Owner

sxyazi commented May 15, 2024

Thank you for the awesome work!

Mouse support is a feature I've been wanting to add for a while, and I'm very happy to see it implemented now! It definitely deserves a separate version to be released ;)

@sxyazi
Copy link
Owner

sxyazi commented May 15, 2024

Here are some change requests:

  • Dispatch Down(MouseButton) and Up(MouseButton) to the click method of each component, e.g.:

    function Current:click(event, up)
      -- event = MouseEvent { column = 10, row = 20, modifiers = 0 }
      -- up = true/false
    end
  • Dispatch ScrollDown, and ScrollUp to the scroll method of each component, e.g.:

    function Current:scroll(event, step)
      -- event = MouseEvent { column = 10, row = 20, modifiers = 0 }
      -- step = 1 (Down), step = -1 (Up)
    end
  • Dispatch ScrollLeft, and ScrollRight to the touch method of each component, e.g.:

    function Current:touch(event, step)
      -- event = MouseEvent { column = 10, row = 20, modifiers = 0 }
      -- step = 1 (Right), step = -1 (Left)
    end
  • Dispatch Moved to the move method of the Manager component:

    function Manager:move(event)
      -- event = MouseEvent { column = 10, row = 20, modifiers = 0 }
    end
  • Dispatch Drag(MouseButton) to the drag method of the Manager component:

    function Manager:drag(event, start)
      -- event = MouseEvent { column = 10, row = 20, modifiers = 0 }
      -- start = MouseEvent { column = 10, row = 20, modifiers = 0 }, we need to save the position of the last `Down(MouseButton)` here
    end

And the MouseEvent userdata contains 3 additional fields:

  • is_left (Boolean)
  • is_right (Boolean)
  • is_middle (Boolean)

When the event type is Moved, ScrollDown, ScrollUp, ScrollLeft, or ScrollRight, the values of these 3 fields are all false since these types do not support mouse buttons.

@qsdrqs
Copy link
Author

qsdrqs commented May 16, 2024

* Dispatch `ScrollDown`, `ScrollUp`, `ScrollLeft`, `ScrollRight` to the `scroll` method of _each_ component, e.g.:
  ```lua
  function Current:scroll(event, step)
    -- event = MouseEvent { column = 10, row = 20, modifiers = 0 }
    -- step = 1 (Down), step = -1 (Up)
  end
  ```

How to deal with ScrollLeft, ScrollRight in this scoll function?

@sxyazi
Copy link
Owner

sxyazi commented May 16, 2024

I've updated the comment

@qsdrqs
Copy link
Author

qsdrqs commented May 17, 2024

I've finished the requested change, could you have a look at it?

@@ -12,6 +12,7 @@ linemode = "none"
show_hidden = false
show_symlink = true
scrolloff = 5
mouse = true
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
mouse = true
mouse_events = [ "click", "scroll" ]

This allows us to selectively ignore certain minor events, such as touch, move, drag, which can be manually enabled by the user when needed. Due to the high frequency of move events, this would be a significant optimization.

@@ -20,6 +20,7 @@ pub struct Manager {
pub show_hidden: bool,
pub show_symlink: bool,
pub scrolloff: u8,
pub mouse: bool,
Copy link
Owner

@sxyazi sxyazi May 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub mouse: bool,
pub mouse: MouseEvents,

MouseEvents looks like:

bitflags! {
	#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
	#[serde(try_from = "Vec<String>")]
	pub struct MouseEvents: u8 {
		const CLICK  = 0b00001;
		const SCROLL = 0b00010;
		const TOUCH  = 0b00100;
		const MOVE   = 0b01000;
		const DRAG   = 0b10000;
	}
}

You can check out

impl TryFrom<Vec<i16>> for Offset {

for implementing it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants