[GH-ISSUE #446] Redraw after each key event slows down the main loop #320

Closed
opened 2026-03-04 01:03:56 +03:00 by kerem · 11 comments
Owner

Originally created by @gnojus on GitHub (May 14, 2020).
Original GitHub issue: https://github.com/rivo/tview/issues/446

Current implementation performs a draw after each handled key event. While this behavior does make sense (because the primitive probably has adjusted it's content), it also creates its own problems.

The key events may be sent very rapidly on a quick scroll or a paste action. If application screen is large enough, the draw operation takes significant time to complete. This makes the main loop go out of sync with key input, resulting in delayed handling of continuous events, even after the user has finished his action (scroll/paste).

This creates noticeable lag that cannot be avoided with current implementation.

I don't see any nice solution to this. I was thinking of asynchronous draw or stacked events, but these of course creates their own problems. Anyway, I felt that this should be addressed as it is not a very pleasant experience on user end in some cases.

Originally created by @gnojus on GitHub (May 14, 2020). Original GitHub issue: https://github.com/rivo/tview/issues/446 Current implementation performs a draw after each handled key event. While this behavior does make sense (because the primitive probably has adjusted it's content), it also creates its own problems. The key events may be sent very rapidly on a quick scroll or a paste action. If application screen is large enough, the draw operation takes significant time to complete. This makes the main loop go out of sync with key input, resulting in delayed handling of continuous events, even after the user has finished his action (scroll/paste). This creates noticeable lag that cannot be avoided with current implementation. I don't see any nice solution to this. I was thinking of asynchronous draw or stacked events, but these of course creates their own problems. Anyway, I felt that this should be addressed as it is not a very pleasant experience on user end in some cases.
kerem closed this issue 2026-03-04 01:03:57 +03:00
Author
Owner

@rivo commented on GitHub (Jun 28, 2020):

I understand that. Immediate redrawing after a key press is a property of tview so I can't just make it asynchronous as it will break a lot of applications.

I could add ways to temporarily suspend redrawing. But it would require us (or the app) to determine when this is appropriate. I don't think you can easily find out whether something is pasted, for example. You could measure the time between successive events, I guess. It would be messy. And it would introduce lag because you don't know what the last event of that sequence is so you'll have to wait a bit and then redraw.

We could try, though.

<!-- gh-comment-id:650715689 --> @rivo commented on GitHub (Jun 28, 2020): I understand that. Immediate redrawing after a key press is a property of `tview` so I can't just make it asynchronous as it will break a lot of applications. I could add ways to temporarily suspend redrawing. But it would require us (or the app) to determine when this is appropriate. I don't think you can easily find out whether something is pasted, for example. You could measure the time between successive events, I guess. It would be messy. And it would introduce lag because you don't know what the last event of that sequence is so you'll have to wait a bit and then redraw. We could try, though.
Author
Owner

@gnojus commented on GitHub (Jun 28, 2020):

I'm not a fan with measuring delays. I'm pretty sure that this could be easily broken by a quick swipe with that Apple magic mouse, because it has some dynamics if I recall correctly.

Another idea I had was to stack key events asynchronously and then process all that stack at once after a draw finishes. This however might result in a lot of lag if the user defined key handlers takes a lot of time to complete. Probably it would be necessary to redraw after certain amount of time even if the key stack is still not completed. While this wouldn't completely remove the lag, processing of the actions should end exactly after the actual stream of key events.
Maybe this way it would be better, I don't know.

<!-- gh-comment-id:650802117 --> @gnojus commented on GitHub (Jun 28, 2020): I'm not a fan with measuring delays. I'm pretty sure that this could be easily broken by a quick swipe with that Apple _magic mouse_, because it has some dynamics if I recall correctly. Another idea I had was to stack key events asynchronously and then process all that stack at once after a draw finishes. This however might result in a lot of lag if the user defined key handlers takes a lot of time to complete. Probably it would be necessary to redraw after certain amount of time even if the key stack is still not completed. While this wouldn't completely remove the lag, processing of the actions should end exactly after the actual stream of key events. Maybe this way it would be better, I don't know.
Author
Owner

@rivo commented on GitHub (Jul 12, 2020):

The question is, what are the situations where we have to process a lot of characters at once? Is it only when text is pasted? And if so, can that be recognized? Or have you had situations where you were just typing really fast?

<!-- gh-comment-id:657211112 --> @rivo commented on GitHub (Jul 12, 2020): The question is, what are the situations where we have to process a lot of characters at once? Is it only when text is pasted? And if so, can that be recognized? Or have you had situations where you were just typing really fast?
Author
Owner

@gnojus commented on GitHub (Jul 12, 2020):

No, I’m not a fast typer. However, the lag was visible when quickly scrolling with a large terminal screen.

<!-- gh-comment-id:657217799 --> @gnojus commented on GitHub (Jul 12, 2020): No, I’m not a fast typer. However, the lag was visible when quickly scrolling with a large terminal screen.
Author
Owner

@rivo commented on GitHub (Jul 12, 2020):

You mean this wasn't so much about entering text but rather holding down an arrow key or similar to scroll?

<!-- gh-comment-id:657231137 --> @rivo commented on GitHub (Jul 12, 2020): You mean this wasn't so much about entering text but rather holding down an arrow key or similar to scroll?
Author
Owner

@gnojus commented on GitHub (Jul 12, 2020):

It was by swiping with two fingers on a touch-pad vertically, that is quite fast scrolling. And if I'm not mistaken, scrolling on my terminal emulator results in UP/DOWN key events from tcell (at least when not in mouse-mode).

<!-- gh-comment-id:657249038 --> @gnojus commented on GitHub (Jul 12, 2020): It was by swiping with two fingers on a touch-pad vertically, that is quite fast scrolling. And if I'm not mistaken, scrolling on my terminal emulator results in UP/DOWN key events from `tcell` (at least when not in mouse-mode).
Author
Owner

@abitrolly commented on GitHub (Jul 13, 2020):

I wonder if https://github.com/vadimdemedes/ink has the same problem?

<!-- gh-comment-id:657339869 --> @abitrolly commented on GitHub (Jul 13, 2020): I wonder if https://github.com/vadimdemedes/ink has the same problem?
Author
Owner

@rivo commented on GitHub (Jul 13, 2020):

That's interesting. In this case, the question would be how the touchpad translates the swipe gesture into keystrokes. In graphical user interfaces, you would get a new screen position or the "traveled" distance so you can calculate the scrolling offset. But we don't get that here.

So even if keystroke processing was faster, I don't know if would behave the way you would expect.

<!-- gh-comment-id:657436484 --> @rivo commented on GitHub (Jul 13, 2020): That's interesting. In this case, the question would be how the touchpad translates the swipe gesture into keystrokes. In graphical user interfaces, you would get a new screen position or the "traveled" distance so you can calculate the scrolling offset. But we don't get that here. So even if keystroke processing was faster, I don't know if would behave the way you would expect.
Author
Owner

@gnojus commented on GitHub (Jul 13, 2020):

Well, if we would process the key event backlog without redrawing after each one, maybe we could keep up with the speed of incoming events and not have the widget still scrolling after the user has ended the scroll gesture?

<!-- gh-comment-id:657488804 --> @gnojus commented on GitHub (Jul 13, 2020): Well, if we would process the key event backlog without redrawing after each one, maybe we could keep up with the speed of incoming events and not have the widget still scrolling after the user has ended the scroll gesture?
Author
Owner

@rivo commented on GitHub (Sep 15, 2020):

So you're suggesting that we keep a separate (asynchronous) buffer for key events and then track if there's a backlog. The question is, how can we catch up with the backlog? Is it enough to simply not redraw the screen? I haven't run any performance tests. I wonder if the bottleneck is the drawing or the actual processing of events.

<!-- gh-comment-id:692619631 --> @rivo commented on GitHub (Sep 15, 2020): So you're suggesting that we keep a separate (asynchronous) buffer for key events and then track if there's a backlog. The question is, how can we catch up with the backlog? Is it enough to simply not redraw the screen? I haven't run any performance tests. I wonder if the bottleneck is the drawing or the actual processing of events.
Author
Owner

@rivo commented on GitHub (Jun 24, 2021):

I will close this for now. We can reopen when other people are having the same problem. At the moment, it doesn't look very urgent to me and I don't see a good solution.

<!-- gh-comment-id:867809926 --> @rivo commented on GitHub (Jun 24, 2021): I will close this for now. We can reopen when other people are having the same problem. At the moment, it doesn't look very urgent to me and I don't see a good solution.
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#320
No description provided.