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

[BUG] Cannot delete text in InputField #133

Open
jsergiu opened this issue Sep 15, 2023 · 11 comments
Open

[BUG] Cannot delete text in InputField #133

jsergiu opened this issue Sep 15, 2023 · 11 comments
Labels
Bug Something isn't working Needs help This issue has been recognized, but help is needed to fix it

Comments

@jsergiu
Copy link

jsergiu commented Sep 15, 2023

Cannot delete text in InputField

To Reproduce

import sys
from typing import List, Optional
import pytermgui as ptg

def main(argv: Optional[List[str]] = None) -> None:
    with ptg.WindowManager() as manager:
    layout = ptg.Layout()
    layout.add_slot("SiderBar", width=0.2)

    manager.layout = layout

    manager.add(
        ptg.Window("Testing...", ptg.InputField("default value", prompt="Name: "))
    )

if __name__ == "__main__":
    main(sys.argv[1:])

Expected behavior
Pressing backspace or delete should delete the text

System information
Windows 11, Powershell, Windows Terminal

    Python version: 3.8.18
    $TERM:          None
    $COLORTERM:     None
    Color support:  ColorSystem.STANDARD
    OS Platform:    Windows-10-10.0.22621-SP0
@jsergiu jsergiu added the Bug Something isn't working label Sep 15, 2023
@jsergiu
Copy link
Author

jsergiu commented Sep 15, 2023

Also when typing in the InputField, the letters or digits are added at the beginning of the input instead of the end.

@YoloWingPixie
Copy link

Windows 11/Powershell/Windows Terminal and also experiencing this issue

@efenatuyo
Copy link

20240102-2235-17.6046383.mp4

@jerrywcy
Copy link

jerrywcy commented Feb 5, 2024

Same error here, on windows 11 power shell

@bczsalba
Copy link
Owner

Could you show me the output of pressing backspace while running ptg -g? I suspect the character that gets input isn't what we were previously looking for.

@jyoung15
Copy link

I just ran into this issue as well.

Here is the output for backspace:

PyTermGUI - Getch

┌────────────────────────────────────────────────┐
│                   Your output                  │
│                                                │
│ key                                keys.CTRL_H │
│ value:                                  '\x08' │
│ len()                                        1 │
│ real_length()                               -1 │
└────────────────────────────────────────────────┘

And the output for delete:

PyTermGUI - Getch

┌────────────────────────────────────────────────┐
│                   Your output                  │
│                                                │
│ key                                    '\x1bS' │
│ value:                                 '\x1bS' │
│ len()                                        2 │
│ real_length()                               -1 │
└────────────────────────────────────────────────┘

Note the behavior of ptg -g is different on Windows versus Linux. On Linux, it brings up a "Press any key..." prompt and waits indefinitely for the user to press a key. On Windows, there is no prompt, and if you don't press a key immediately it will return with an empty result.

If I call msvcrt.getch directly, I get this:

backspace:

>python -c 'import msvcrt; print(ascii(msvcrt.getch()))'
b'\x08'

delete:

> python -c 'import msvcrt; print(ascii(msvcrt.getch()))'
b'\xe0'

@bczsalba
Copy link
Owner

Huh, that's interesting. The codes seem correct, so no idea why it doesn't behave properly. Maybe someone with a Windows machine could diagnose it further?

Note the behavior of ptg -g is different on Windows versus Linux.

Could you record a video of this as a separate issue? That's definitely not intended!

@bczsalba bczsalba added the Needs help This issue has been recognized, but help is needed to fix it label Feb 24, 2024
@jyoung15
Copy link

Sorry I don't have a video, but I did look into this further and tried to do some debugging with pdb. I set a breakpoint in the GetchWindow constructor and can see the "Press any key" prompt appears, but when running the program normally (not in a debugger) it is not visible, possibly because the screen refreshes so quickly.

The issue appears to be with the call to msvcrt.kbhit here:

if not msvcrt.kbhit(): # type: ignore
raise TimeoutException("No input available.")

If there is no pending keypress, kbhit will immediately return 0, and it will throw TimeoutException. So the get_chars (and therefore getch) method will immediately return if there is no pending keypress. There doesn't seem to be a mechanism to wait for the user to press a key. Here is an example calling getch with and without windows_raise_timeout:

PS E:\tmp> python -c 'import pytermgui; print(ascii(pytermgui.input.getch()))'
''
PS E:\tmp> python -c 'import pytermgui; print(ascii(pytermgui.input.getch(windows_raise_timeout=True)))'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\Users\user\.virtualenvs\ptg-test--GZ1WdmM\Lib\site-packages\pytermgui\input.py", line 441, in getch
    key = _getch()
          ^^^^^^^^
  File "C:\Users\user\.virtualenvs\ptg-test--GZ1WdmM\Lib\site-packages\pytermgui\input.py", line 209, in __call__
    buff = self.get_chars()
           ^^^^^^^^^^^^^^^^
  File "C:\Users\user\.virtualenvs\ptg-test--GZ1WdmM\Lib\site-packages\pytermgui\input.py", line 185, in get_chars
    raise TimeoutException("No input available.")
pytermgui.exceptions.TimeoutException: No input available.
PS E:\tmp>

Most examples I have seen of msvcrt.kbhit() place it inside a while True: loop. Maybe it's worth rewriting this to place it in a loop with an actual timeout mechanism (break after x seconds).

Anyhow, I realize this doesn't address the original problem regarding backspace and delete. I am still not sure what is causing that issue.

@bczsalba
Copy link
Owner

Could you try commenting out:

# We need to type: ignore these on non-windows machines,
# as the library does not exist.
if not msvcrt.kbhit(): # type: ignore
raise TimeoutException("No input available.")

Looking at it again, it seems that not checking up front would be the more accurate algorithm when compared to the UNIX implementation.

@jyoung15
Copy link

With the following changes, ptg -g seems to work as expected. I included a timeout option as well:

--- a/pytermgui/input.py
+++ b/pytermgui/input.py
@@ -23,6 +23,7 @@
 from codecs import getincrementaldecoder
 from contextlib import contextmanager
 from select import select
+from time import time
 from typing import (
     IO,
     Any,
@@ -172,7 +173,7 @@

         return string

-    def get_chars(self) -> str:
+    def get_chars(self, timeout: int = 3) -> str:
         """Reads characters from sys.stdin.

         Returns:
@@ -181,14 +182,17 @@

         # We need to type: ignore these on non-windows machines,
         # as the library does not exist.
-        if not msvcrt.kbhit():  # type: ignore
-            raise TimeoutException("No input available.")
-
-        char = msvcrt.getch()  # type: ignore
-        if char == b"\xe0":
-            char = "\x1b"
-
-        buff = self._ensure_str(char)
+        start = time()
+        while True:
+            if msvcrt.kbhit():  # type: ignore
+                char = msvcrt.getch()  # type: ignore
+                if char == b"\xe0":
+                    char = "\x1b"
+
+                buff = self._ensure_str(char)
+                break
+            if time() - start > timeout:
+                raise TimeoutException("No input available.")

         while msvcrt.kbhit():  # type: ignore
             char = msvcrt.getch()  # type: ignore

The first loop waits for the initial key-press (within 3 seconds by default). The second loop collects any remaining buffered key-presses. However the original problem still exists. I have been using the second example in the README for testing. With the patch above, CTRL-H works for backspace, but the actual backspace key still doesn't work.

Unfortunately there are additional issues as well when comparing Windows and Linux. For example, the arrow keys do not work on Windows either, and the text on the submit button is not visible in the Windows version. While PyTermGUI may be great for non-Windows platforms, I think it needs a dedicated maintainer/tester for Windows to be considered cross-platform. Unfortunately I do not have the time to do so, and have discovered another project (Textual) that seems to better fit my needs.

@bczsalba
Copy link
Owner

I think it needs a dedicated maintainer/tester for Windows to be considered cross-platform.

Unfortunately I'm just one guy, so this is the best I can do :(

I think the problem here is PowerShell, and its many incompatibilities with pretty much every other shell ever. Since the $TERM and $COLORTERM env vars don't seem to be set, a lot of our compatibility shims don't really work in this configuration.

Your changes are good, but they further distance the UNIX and Windows implementations unfortunately. I believe my suggestion above should be enough to fix the divergence in ptg -g at least.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Something isn't working Needs help This issue has been recognized, but help is needed to fix it
Projects
None yet
Development

No branches or pull requests

6 participants