How do I accept input from arrow keys, or accept directional input?
This may be an xy problem, but I'm trying to to build a kernel based text editor, similar to vim
or nano
, and I know how to use the escape chars to clear the screen, then reprint, I can have it accept characters, but I'm not sure how to get it to accept arrow inputs for navigation. I thought there were ASCII values for them, but apparently not. Is there a way to use the arrows, or do I have to make a navigation mode and insert mode like vim
?
I've also briefly played with curses
, but that was prohibitive because, as I understood, a whole new window had to be opened for it and this is not compatible with the vision of a single terminal window that I had.
Please note that curses
does not work because it cleares the window, which I don't want.
curses
is exactly what you want. In fact I believe vim implements its interface with curses.
Try to put the following code into a file called test_curses.py
:
import curses
screen = curses.initscr()
screen.addstr("Hello World!!!")
screen.refresh()
screen.getch()
curses.endwin()
Now open a terminal (not IDLE! a real terminal!) and run it via:
python test_curses.py
You should see that the terminal was cleared and an Hello World!!!
writing appeared. Press any key and the program will stop, restoring the old terminal contents.
Note that the curses
library isn't as easy and "user-friendly" as you may be accustomed to. I suggest reading the tutorial (unfortunately for the C language, but the python interface is mostly the same)
I wound up using the code from this question, and modifying the __init__
statement so that it accepted up to 3 characters in a list.
import sys
class _Getch:
"""Gets a single character from standard input. Does not echo to the
screen."""
def __init__(self):
self.impl = _GetchUnix()
def __call__(self):# return self.impl()
charlist = []
counter = 0
for i in range(3):
try:charlist.append(self.impl())
except:pass
if charlist[i] not in [chr(27),chr(91)]:#TODO sort out escape vs arrow duh use len()
break
if len(charlist) > 1:
if charlist == [chr(27),chr(27)]:
break
if len(charlist) == 3:
if charlist[2] == 'a'
return 'u-arr'
if charlist[2] == 'b'
return 'd-arr'
if charlist[2] == 'c'
return 'r-arr'
if charlist[2] == 'd'
return 'l-arr'
if len(charlist == 2):
if charlist == [chr(27),chr(27)]
return chr(27)
if len(charlist == 1)
return charlist[0]
return ''
class _GetchUnix:
def __init__(self):
import tty, sys
def __call__(self):
import sys, tty, termios
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
This allowed me to get arrow keys as well as all other characters and escape sequences from the keyboard for the editor. It made the "Getch" class not strictly a get char
clone because it returns a string, but it wound up being much more useful.