In hindsight, building a small "minimalist" and focussed CLI in order to grade LLM responses for my thesis comfortably in curses has been a baffling (bad) experience. It still beats doing that stuff in a table though!
This might be a macOS-centric/exclusive post, but long story short: if you want to use buttons to iterate through a list of entries and disallow holding-down a button in curses using
```python
stdscr.nodelay(True)
```
You will probably just have to wait out the last keypress for up to half a second.
Timing the registered keypresses when holding down a button will make things clearer.
Let's say I use a very simple while-loop to register keypresses and registering them.
```python
while True:
key = stdscr.getch()
if key != -1:
logging.debug(f"Key pressed: {key}, {chr(key)}")
if chr(key) == 'q':
sys.exit(0)
continue
...
time.sleep(0.01)
```
For example, holding down the ARROW DOWN key gets initially registered at 0:0,000.
Then occurs an OS-dependent delay, just shy of 500ms by a handful.
Afterwards, the held-down key will register every around 90ms. In the case of ARROW DOWN, it will register a 3-key sequence of 27, 91, and 66 (that register at most 1ms apart in my naive testing).
Long story short: you will have to wait out (to be sure a bit over) 500ms to make sure you're not holding down the button to accept the input and continue. I could not get a better trivial working solution than just filtering by macOS' default key-hold values and I don't want to further waste time on it.
**Although this might have sounded definite, I am in no way speaking from a point of authority. I am very aware of my ignorance and I never intend this form of tone in my life in general. On this topic: this very well might be trivially possible, but I did not get it to work in a reasonable time. Should you have gotten it working, I would be thankful to hear from you!**
## Alternative way using thread: also broken
I quickly tried the following solution to no avail. Unfortunately curses is not thread-safe and when changing scenes, the outputs are simply broken. Some stay from the scene before, some are at odd places.
The idea is to use a thread to read the inputs. Whenever you are awaiting keypress - changing scenery - awaiting keypress, we have some form of key-handler reading in keypresses. In case of keypress being held, although we just switched scenes and are awaiting a keypress - we will have to ignore them as long as the KeyHandler is still in an active state. This would allow us to change scenes immediately, without the redundant delay.
Proof of concept - I am self-conscious enough, that the continues and ifs (not elifs, although this would be the same) are bad form. It's expressive though :).
```python
def keypress_reader(stdscr, keypress, key_held, lock, stop_event):
last_key = None
last_pressed = None # time of last keypress
while not stop_event.is_set():
try:
current_time = time.time()
key = stdscr.getch()
if key == -1:
if last_key is not None and current_time - last_pressed >= 0.5:
with lock:
last_key = None
keypress[0] = None
held = key_held[0]
key_held[0] = False
logging.debug(f"KPR: key stopped: {last_key}. Now: {key}. Held: {held} Time: {current_time - last_pressed}")
continue
if key == last_key:
if current_time - last_pressed >= 0.5:
with lock:
key_held[0] = True
last_pressed = current_time
logging.debug(f"KPR: key==last_key and now hold. Key held: {key}")
continue
if key != last_key:
logging.debug(f"KPR: key!=last_key. Key pressed: {key} Last key: {last_key}")
last_key = key
last_pressed = current_time
with lock:
keypress[0] = key
key_held[0] = False
continue
except curses.error:
pass
logging.debug("KPR: sleeping.")
time.sleep(0.01) # Small delay to prevent high CPU usage
```