pytermgui icon indicating copy to clipboard operation
pytermgui copied to clipboard

[Example] Quit only possible in linux via mouse

Open XenonR opened this issue 3 years ago • 1 comments
trafficstars

I was testing the example examples/simple_app.py and noticed that "quit" is only accessible in Linux. And even there only with mouse interaction. On windows (PowerShell) even mouse interaction does not work. For a new testing user of pytermgui this is very disorientating. Since the knowledge is lacking if this is an easy fix or a lacking implementation of the library.

That said I like what I see. Keep it up.💚

XenonR avatar Aug 31 '22 07:08 XenonR

Hey! This is probably due to the lack of mouse support on Windows (since they don't follow the standard terminal procedures completely yet). There is a form of tab-select going on for the framework, but it's not the most well implemented yet.

Will look into clarifying it more over time!

bczsalba avatar Aug 31 '22 13:08 bczsalba

@bczsalba @XenonR It is result of blockable read from the stdin. I've started work on switching to asyncio unblockable read in input reading thread. I currently made and released an async wrapper for an async logic support inside the pytermgui, but switch to an async read should be made in a PR to the original project - not in the wrapper.

FI-Mihej avatar Apr 30 '23 23:04 FI-Mihej

@FI-Mihej How do you know that's the cause? AFAIK our input is functionally non-blocking, so you should be able to bind "Q" to manager.stop it should work out just fine.

bczsalba avatar May 01 '23 07:05 bczsalba

@bczsalba WindowManager.stop() call is promoted in examples as a way to stop an app. It sets self._is_running to True. Later, it can be checked in a line while self._is_running: in order to stop loop of an input handling thread. At the same time the code has a loop blocking line char = os.read(sys.stdin.fileno(), 1). As result the while self._is_running: check and following exit from the loop can be made only after an additional keystroke or mouse move. Am I answered to your question?

FI-Mihej avatar May 01 '23 08:05 FI-Mihej

@bczsalba I'll clarify. There is no problem when you are using Linux, or WSL with your plain, synchronous approach from the button handler: Linux or GNU toolchain handles this for you when you are clicking to a button with a mouse (since mouse click generates an array of characters instead of the single character). However when you will try to exit from your app fully programmatically (from a macro handler or from an injected asyncio loop - doesn't matter) - you will see this issue.

FI-Mihej avatar May 01 '23 09:05 FI-Mihej

@bczsalba I'll clarify. There is no problem when you are using Linux, or WSL with your plain, synchronous approach of WindowManager.stop() call execution from the button handler: Linux or GNU toolchain handles this for you when you are clicking to a button with a mouse (since mouse click generates an array of characters instead of the single character). However when you will try to exit from your app fully programmatically (from a macro handler or from an injected asyncio loop - doesn't matter) - you will see this issue since there is no input from the user at this moment and your main input-reading thread is blocked by char = os.read(sys.stdin.fileno(), 1) call and still waits for next user input.

FI-Mihej avatar May 01 '23 09:05 FI-Mihej

Hi, not sure my problem is related to this issue, but with pytermgui 7.4.0 installed via pip, I'm unable to exit cleanly by calling for example manager.stop() from a keyboard binding callback. After calling stop(), the string "hover" is printed in the terminal, and nothing else happens until I press return or ctrl-c. It seems like pyterm gui gets stuck in the call to input in this function in context_managers.py:

@contextmanager
def mouse_handler(
    events: list[str], method: str = "decimal_xterm"
) -> Generator[MouseTranslator, None, None]:
    """Return a mouse handler function

    See `help(report_mouse)` for help about all of the methods.

    Args:
        events: A list of `pytermgui.ansi_interface.report_mouse` events.
        method: The method to use for reporting. Only `decimal_urxvt` and
            `decimal_xterm` are currently supported.

    Example use:

    ```python3
    import pytermgui as ptg

    with ptg.mouse_handler(["press", "hover"]) as mouse:
        while True:
          event = mouse(ptg.getch())
          print(type(event))
          print(event.action)
          print(event.position)

    'pytermgui.ansi_interface.MouseEvent'
    'pytermgui.ansi_interface.MouseAction.LEFT_CLICK'
    (33, 55)
    ```

    """

    event = None
    try:
        for event in events:
            report_mouse(event, method=method)

        yield lambda code: translate_mouse(code, method=method)

    finally:
        input(event) # <--- pytermgui blocks here at exit
        if event is not None:
            report_mouse(event, method=method, stop=True)

Removing the input(event) line solves my problem entirely. The strange thing is that I can't find any reference to this input statement in the git logs, and it's removed in current master. So I expect using the latest commit from the master branch will also solve my problem. My main question is, how did this input statement end up in the 7.4.0 pip release?

landersson avatar Jul 04 '23 13:07 landersson

@landersson Yep, that input statement has come up in a previous issue recently. No clue why it's there or how it made it there, but the next version won't have it :)

bczsalba avatar Jul 06 '23 11:07 bczsalba

@FI-Mihej The commit above introduced a way to do non-indefinitely-blocking getch calls for the WindowManager, which resolves your problem. Thanks for the help!

@XenonR A recent PR (#122) by @Tired-Fox introduced Windows-side support for mouse input, which should solve the issue that started this thread. Coming in the next update!

bczsalba avatar Jul 11 '23 12:07 bczsalba