mirror of
https://github.com/rivo/tview.git
synced 2026-04-27 05:45:49 +03:00
[GH-ISSUE #1010] [Bug?] Terminal is not interactive. #732
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/tview#732
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @npxcomplete on GitHub (Jul 17, 2024).
Original GitHub issue: https://github.com/rivo/tview/issues/1010
Not sure if this is an environment bug or if I'm doing something horribly wrong. I've been working off the example code expecting the below program to let me tab between the 4 input fields and type into text boxes. However, when I start the program up the library paints the terminal and I love how easy that is, but there's no interactivity.
Linux 6.5.x / Ubuntu.
I've tested in ubuntu's default terminal, terminator, and embedded in tmux.
@npxcomplete commented on GitHub (Jul 17, 2024):
Trying out more of the examples (which have thus far all worked) I found
app.EnableMousewhich lets me set focus. The inputs all seem to be behaving as I'd hope for the moment :D@npxcomplete commented on GitHub (Jul 17, 2024):
Seems part of the reason that tab'n in the form demo works is that the form construct micro manages it. I suppose this makes sense as a form is a collection and the construction order defines the tab order then?
https://github.com/rivo/tview/blob/master/form.go#L706-L719
So I wonder then, can I embed the elements of the form in a separate layout, excluding the form entity from widget tree and still benefit from the form's logic?
@npxcomplete commented on GitHub (Jul 17, 2024):
Indeed, the use of
form.AddFormItemseems to work a treat. It still leaves me wondering whyapp.SetFocusseems to be falling short though....Ah, it's because
SetRootwas being called beforeSetFocus. I suppose it's hard to say "set the focus on this element" if the element is not yet part of the application.@npxcomplete commented on GitHub (Jul 17, 2024):
Alas,
form.AddFormItemdoes not support button types, and there's no way to extricate a button from a form if it's created inside.So far I'm really liking the library but I think maybe this is one area where two ideas have become overly coupled (form layout and form control logic). It it's all the same to you I'd settle for patching in an
AddFormButtonfunction that behaves likeAddFormItem.@rivo commented on GitHub (Jul 17, 2024):
A
Formis kind of a convenience type which gives you some features commonly found in entry forms, e.g. some input elements and a "submit" or "cancel" button at the bottom. This convenience comes with some limitations, too, however, as you noticed.If you want more flexibility, use
FlexorGrid. You were off to a good start. When you add your elements to theFlexcomponent, set thefocusparameter totruefor the element you want focused initially. All of these flags were set tofalsein your code so no interactive element was focused, that's why nothing happened.If you want to navigate between elements with Tab or Backtab, use
SetInputCapture()on yourFlexand listen for those events. You can then callapp.SetFocus()for your elements in the order you desire.@npxcomplete commented on GitHub (Jul 18, 2024):
Indeed, a simple enough function:
Invoked with the controls and provided to the
SeInputCapturefunction yield the desired behavior :DThere's plenty of work in the browser plugin space to define good keyboard navigation, as well as the more application specific implementations like vim and gmail. I can imagine slightly more complex apps using a modal system, something like press T to focus this text box, edit the contents, then press Esc or Enter to blur. I wonder how general or complicated a component can be and still be a welcome addition to your library? Is it worth trying to productionize the above and put up a pull request? If so, I can foresee making some other complicated but generalizable components for this little toy app I'm building:
@npxcomplete commented on GitHub (Jul 21, 2024):
Apologies if you want this ticket closed. While it's still here I'm tracking it as a bit of a dev diary as I hit other sticking points. Today's sticking point is a virtual crash caused by (what seems to be) a combination of input buffering and excessive drawing of the virtual table example.
Given a virtual table of ~100 elements the up/down arrows correctly scroll the table until the limit. However, it seems that
whatever internal counter is being used in the table construct is more than happy to allow the focus index to drift out of bound (i.e. into the negative when scrolling up). Combine this with the fact that Draw is slow, happens for every key input, and that input is buffered and what you get is a user that presses up to scroll to the first list, but when the first row becomes visible there are still thousands, maybe millions of inputs waiting to be processed. The input queue will then take minutes or longer to resolve the queue as Draw eats 100% of the CPU.There's a knock on effect too. While that input buffer is being resolved ctrl+c isn't registered. So naturally I try to kill the process. Here's where it gets fun, If you kill a tview process it doesn't hand input control back to the terminal properly, so the terminal sees tcell.Key codes printed out but no return to the shell prompt :D
I suppose there are a lot of remediations that could be attempted here.
I haven't dug in yet, so I'm assuming a bit about how much control the library has over input queuing. That last one presents an interesting option though. Something like a rate limiter on the draw function so any invocations of Draw are dropped after a limit is hit and then a full screen redraw is triggered and burst capacity restored.
@npxcomplete commented on GitHub (Jul 21, 2024):
Found the redraw pause (set to 50ms) and the event queue bounded to 100.
https://github.com/rivo/tview/blob/master/application.go#L11
Key-down repetition seems to work out at 32/sec or ~ 1 input per 32ms. Assuming input events are dropped if that channel is full then it would make sense to assume the limit is hit after ~8 seconds. And following key release it would take 5 seconds for the event buffer to clear.
Testing: 10 seconds of up-arrow took ~30sec to resolve following key-up. Suggesting the Draw function is taking ~128ms with no work to do.
Possibly my confusion. The event queue seems to be accepting only
QueueUpdateDrawstyle events, not device input. Negative, they're coming in from tcell.Screen, tcell's terminal screen uses a buffered channel with size 10https://github.com/rivo/tview/blob/master/application.go#L299
https://github.com/gdamore/tcell/blob/main/tscreen.go#L232
No events are dropped at this level. Looking around, tcell is pulling buffered bytes from the terminal and converting to runes.
https://github.com/gdamore/tcell/blob/main/tscreen.go#L1712
Seems there is room here for selective input dropping. But maybe skipping needless redraws would be the more valuable tactic. On second review the redraw pause behavior only applies to screen resize. So all events queue up, and every keyboard event triggers a redraw.
@rivo commented on GitHub (Jul 28, 2024):
The limits you linked to are for the buffered channels. Once the limit is reached, adding new channel elements will stall. No input gets dropped. If you want input to be dropped, use
Application.SetInputCapture().But I would suggest rather focusing on improving performance of your application. Virtual tables can be quite efficient. The demo exhausts the entire
Int64space, for example:https://github.com/rivo/tview/blob/master/demos/table/virtualtable/main.go
There have been some comments previously in the issues section regarding decoupling input from drawing. If you really need it, it can be done.
This already exists, by the way.