1
k = stdscr.getch()
if k == curses.KEY_UP:
    sys.stdout.write('KEY_UP')
elif k == curses.KEY_F1:
    sys.stdout.write('KEY_F1')
elif k == 113:
    break
else:
    pass

https://docs.python.org/2/library/curses.html

The above code can be used to detect 'q' and arrow_up. However, it cannot be used to detect F1.

Question> Is there a way in python curses that I can use to detect the special function keys?

[Update]

My terminal type is xterm.

elif k == 269: # 'F5'
elif k == 270: # 'F6'
elif k == 271: # 'F7'
elif k == 272: # 'F8'
elif k == 273: # 'F9'
elif k == 27: # 'ESC'
    special_keys = [stdscr.getch(), stdscr.getch(), stdscr.getch(), stdscr.getch()]
    if special_keys == [91, 49, 49, 126]:
        sys.stdout.write('F1\n')
    if special_keys == [91, 49, 50, 126]:
        sys.stdout.write('F2\n')
    if special_keys == [91, 49, 51, 126]:
        sys.stdout.write('F3\n')
    if special_keys == [91, 49, 52, 126]:
        sys.stdout.write('F4\n')

Based on the suggestions from @pbuck, I tested my terminal and listed the results above. I am not sure whether this solution is portable or not. Since @pbuck only suggested that I should use the next two keys after ESC. For my case, I have to extract the next four keys.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
q0987
  • 34,938
  • 69
  • 242
  • 387

2 Answers2

0

Function keys are mapped by your terminal. For example, when you press the F1 key, your terminal (may) be actually sending a sequence like Esc-OP (or ^[OP if you prefer). So, on stdscr.getch(), if it is Esc, grab the next few characters to determine with FKEY.

Hard coding the particular escape sequence isn't great, but function key sequences are dependent upon the interface (i.e., your xterm, console, terminal window, etc). For *nix, that usually means terminfo database. On some interfaces (like my emacs shell), nothing is sent because the terminal driver intercepts it!

You can determine what is being sent for a particular interface using tput and cat -A, because:

$ tput kp1 | cat -A
^[OP
$ tput kp10 | cat -A
^[[21~

However, in my case with same computer, using console window yields:

$ tput kp1 | cat -A
^[[21~
$ tput kp10 | cat -A
^[[[A
pbuck
  • 4,291
  • 2
  • 24
  • 36
0

Does this way satisfy your need?

nKey = stdscr.getch()
sKeys = "%d" % nKey
if nKey == 27 :
    stdscr.nodelay(True)
    for n in range(0,10):
        nKey = stdscr.getch()
        if nKey == curses.ERR :
            break
        sKeys += " %d" % nKey
    stdscr.nodelay(False)
print ( "Key : %s" % sKeys )

It will show like as below:

[F1]    "27 91 49 49 126"
[F2]    "27 91 49 50 126"
[HOME]  "27 91 49 126"
[END]   "27 91 52 126"

This is an easy way to see the result visibly but using list variable may be easy for if statements later. It delays for [ESC] key. I found this post for changing its behaviour.

--Append-- We can avoid [ESC]'s delay with this, but it affects many key-codes and mouse input.

stdscr.keypad(False)