[GH-ISSUE #367] Mouse event dispatch #273

Closed
opened 2026-03-04 01:03:31 +03:00 by kerem · 6 comments
Owner

Originally created by @millerlogic on GitHub (Nov 12, 2019).
Original GitHub issue: https://github.com/rivo/tview/issues/367

Hi, I submitted pull request #363 with mouse support. This issue is a request for comments on how to handle mouse events across the application and widgets.

In my implementation of handling mouse events in DropDown, it takes the mouse capture temporarily while the dropdown is open, so that it can close it on click. Then I realized this is not using the mouse capture in the same way that the input capture is typically being used.
I used the mouse capture in a similar manner as other APIs have a mouse capture, this for example, these are intended to be ways to grab mouse events temporarily while the user is doing something that needs them, and then release it when completed. A real world example of using capture this way is a screenshot tool that lets you click the thing you want screenshot.
I see that the input (key) capture (app.SetInputCapture) is typically being used more like a long-term key event hook rather than temporary capture.

This use of key and mouse captures differently is somewhat unfortunate, so I'm putting it here for discussion.

It's also interesting to note that key and mouse events are typically used differently. For example, key events go to the focused widget, whereas mouse events go to the widget under the mouse.
It it possible that key and mouse events are inherently different enough that their captures can be treated differently?

I'd also like to show off a more elaborate demo of the mouse. This uses an experimental branch mouse-observe which optionally propagates mouse events inward* (a different use of the word "capture" for event propagation, the opposite of "bubble")
To see it you can use: ssh mouse-test@a.cmiller.me (code here).
This is a separate branch because I'm unclear if this is the best approach to "observe" events down the widget hierarchy. In brief, the branch will call an event method on all the parent widgets of the one under the mouse if they implement that particular interface method. In this demo allows it to activate the window when clicking anything within it. It could use the app capture, but then it's fighting with the dropdown and any other captures.

Considering all the above, I wonder if we can come up with a better solution for event dispatch, or if what I have is good.

I'm open to feedback on this or any of the mouse handling, thanks!

Originally created by @millerlogic on GitHub (Nov 12, 2019). Original GitHub issue: https://github.com/rivo/tview/issues/367 Hi, I submitted pull request #363 with mouse support. This issue is a request for comments on how to handle mouse events across the application and widgets. In my implementation of handling mouse events in DropDown, it takes the mouse capture temporarily while the dropdown is open, so that it can close it on click. Then I realized this is not using the mouse capture in the same way that the input capture is typically being used. I used the mouse capture in a similar manner as other APIs have a mouse capture, [this for example](https://docs.microsoft.com/en-us/dotnet/api/system.windows.input.mouse.capture?view=netframework-4.8), these are intended to be ways to grab mouse events temporarily while the user is doing something that needs them, and then release it when completed. A real world example of using capture this way is a screenshot tool that lets you click the thing you want screenshot. I see that the input (key) capture (app.SetInputCapture) is typically being used more like a long-term key event hook rather than temporary capture. This use of key and mouse captures differently is somewhat unfortunate, so I'm putting it here for discussion. It's also interesting to note that key and mouse events are typically used differently. For example, key events go to the focused widget, whereas mouse events go to the widget under the mouse. It it possible that key and mouse events are inherently different enough that their captures can be treated differently? I'd also like to show off a more elaborate demo of the mouse. This uses an experimental branch [mouse-observe](https://github.com/millerlogic/tview/tree/mouse-observe) which optionally propagates mouse events inward* (a different use of the word "capture" for event propagation, the opposite of "bubble") To see it you can use: ```ssh mouse-test@a.cmiller.me``` ([code here](https://github.com/millerlogic/tuix)). This is a separate branch because I'm unclear if this is the best approach to "observe" events down the widget hierarchy. In brief, the branch will call an event method on all the parent widgets of the one under the mouse if they implement that particular interface method. In this demo allows it to activate the window when clicking anything within it. It could use the app capture, but then it's fighting with the dropdown and any other captures. Considering all the above, I wonder if we can come up with a better solution for event dispatch, or if what I have is good. I'm open to feedback on this or any of the mouse handling, thanks!
kerem closed this issue 2026-03-04 01:03:31 +03:00
Author
Owner

@tslocum commented on GitHub (Jan 6, 2020):

Thanks for your work on this, @millerlogic.

After reviewing and merging your PR + mouse-observe branch into cview I tweaked how Dropdowns temporarily capture mouse input. I believe Application.SetMouseCapture should be reserved for use by application developers only, so I have added Application.SetTemporaryMouseCapture. This is a second capture function for widgets which avoids overwriting developers' capture functions. It is the responsibility of the calling widget to later clear this temporary capture.

Demo: ssh cview.rocketnine.space -p 20000

Files: application.go dropdown.go

<!-- gh-comment-id:571366697 --> @tslocum commented on GitHub (Jan 6, 2020): Thanks for your work on this, @millerlogic. After reviewing and merging your PR + mouse-observe branch into [cview](https://git.sr.ht/~tslocum/cview) I tweaked how Dropdowns temporarily capture mouse input. I believe Application.SetMouseCapture should be reserved for use by application developers only, so I have added Application.SetTemporaryMouseCapture. This is a second capture function for widgets which avoids overwriting developers' capture functions. It is the responsibility of the calling widget to later clear this temporary capture. Demo: ```ssh cview.rocketnine.space -p 20000``` Files: [application.go](https://git.sr.ht/~tslocum/cview/tree/master/application.go) [dropdown.go](https://git.sr.ht/~tslocum/cview/tree/master/dropdown.go)
Author
Owner

@millerlogic commented on GitHub (Jan 8, 2020):

@tslocum cool, that'll do it

<!-- gh-comment-id:572057827 --> @millerlogic commented on GitHub (Jan 8, 2020): @tslocum cool, that'll do it
Author
Owner

@rivo commented on GitHub (Jan 8, 2020):

Sorry for the late reply. This is probably the biggest PR I've received so there's a lot of new/changed code to go through. I'll have a first look and will let you know my feedback.

Obviously, cview already merged your PR so if you don't plan on following up on this PR over here in tview, please let me know as it could save me quite some time. (If I find that I would like tview to go down the route you took, it's likely that I will request a whole bunch of changes.)

<!-- gh-comment-id:572171864 --> @rivo commented on GitHub (Jan 8, 2020): Sorry for the late reply. This is probably the biggest PR I've received so there's a lot of new/changed code to go through. I'll have a first look and will let you know my feedback. Obviously, `cview` already merged your PR so if you don't plan on following up on this PR over here in `tview`, please let me know as it could save me quite some time. (If I find that I would like `tview` to go down the route you took, it's likely that I will request a whole bunch of changes.)
Author
Owner

@millerlogic commented on GitHub (Jan 9, 2020):

hi @rivo, I would be open to making changes.
Though admittedly, I am becoming a bit more attached to the current implementation the more time passes 🤔 but we can start with discussions.
Why don't you give it a look whenever you get a chance and give your initial thoughts, so then I can follow up and get more on the same page.

<!-- gh-comment-id:572515303 --> @millerlogic commented on GitHub (Jan 9, 2020): hi @rivo, I would be open to making changes. Though admittedly, I am becoming a bit more attached to the current implementation the more time passes 🤔 but we can start with discussions. Why don't you give it a look whenever you get a chance and give your initial thoughts, so then I can follow up and get more on the same page.
Author
Owner

@rivo commented on GitHub (Jan 10, 2020):

Cool, thanks. So before I send comments about specific parts in the code, here are some general remarks:

  • I think the general direction is good. This is similar to what I would have implemented myself. I like that you made this similar to the way tview handles keyboard events.
  • When I checked out the cview demo above, I noticed that text selections don't work anymore. Do you know if there are ways to pass events through to the default handler of the terminal? (I haven't looked into this much yet.) I don't think we should re-implement this on our side but if there's a way to keep text selections possible (personally, I use them all the time), it would be great.
  • I'll probably merge this into a separate branch first and release it finally once all primitives are supported, i.e. also TreeView and Table.

Next, I'll post some general comments regarding the code in the PR directly so we have it all in one place.

<!-- gh-comment-id:572969297 --> @rivo commented on GitHub (Jan 10, 2020): Cool, thanks. So before I send comments about specific parts in the code, here are some general remarks: - I think the general direction is good. This is similar to what I would have implemented myself. I like that you made this similar to the way `tview` handles keyboard events. - When I checked out the `cview` demo above, I noticed that text selections don't work anymore. Do you know if there are ways to pass events through to the default handler of the terminal? (I haven't looked into this much yet.) I don't think we should re-implement this on our side but if there's a way to keep text selections possible (personally, I use them all the time), it would be great. - I'll probably merge this into a separate branch first and release it finally once all primitives are supported, i.e. also `TreeView` and `Table`. Next, I'll post some general comments regarding the code in the PR directly so we have it all in one place.
Author
Owner

@rivo commented on GitHub (Jan 10, 2020):

Actually, ignore my comment on text selection. I had not seen your comments in the PR.

<!-- gh-comment-id:573019958 --> @rivo commented on GitHub (Jan 10, 2020): Actually, ignore my comment on text selection. I had not seen your comments in the PR.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/tview#273
No description provided.