1

So I am making a program that requires arrow keys but cannot use curses or chr funtion. Is there any simple and easy way to do this?

BTW I have already tried inp.key_UP but this does not seem to work. Also I am on mac so gtsrc wont work.

  • Why can't you use the `chr` function? I assume that restriction is part of some assignment from a teacher; otherwise it makes very little sense. So, can you give us the full assignment description? – abarnert Jul 11 '18 at 01:10
  • Also, what is `inp.key_UP`? I assume that's from some third-party library? what's `glsrc`? – abarnert Jul 11 '18 at 01:11
  • I can't use the chr funtion because I already have w, a, s, and d as inputs from the user and I can't change the variable of that input to include chr because then w, a, s, and d won't work since they are not numbers. –  Jul 11 '18 at 01:15
  • I'm sorry, I don't understand what you mean by that. `chr(119)` is `'w'`. – abarnert Jul 11 '18 at 01:16
  • But then what are all the ord of arrow keys –  Jul 11 '18 at 01:19
  • The arrow keys are usually not characters, but sequences of multiple character: Escape, `[`, then optionally `1`, then one of the letters from `A` to `D`. I don't think `chr` is going to _help_ anywhere, but I don't see why it's a _problem_ anywhere either. More importantly: you still haven't said what `inp` and `glsrc` are, or _why_ you can't use `curses` (and whether that applies to other high-level modules). – abarnert Jul 11 '18 at 02:12

2 Answers2

0

When the user presses a key (unless you're reading at a very low level, like a Cocoa system event hook), the terminal program (usually Terminal.app) processes that and sends your program a sequence of bytes, which you can read off sys.stdin or /dev/tty.

Assuming default settings:

  • For ASCII letters, numbers, etc., that sequence of bytes is just one byte, with the ord of the character.
  • For non-ASCII characters, that sequence of bytes is the UTF-8 encoding of the character. (On other *nix you can't depend on it being UTF-8, but on macOS, you can.)
  • For special keys like arrows, that sequence is an ANSI standard escape sequences. For example, for up arrow, you'll get Cursor Up (\x1b[A), or maybe Cursor Up 1 (\x1b[1A). (You really shouldn't assume an ANSI-compatible terminal—and you can even configure Terminal.app to send different things—but rather reading $TERM and looking up the termcaps entry, but if you only care about Mac, you'll almost certainly get away with this.)

So, now you just have to open stdin or /dev/tty as an unbuffered raw binary file, put it into raw mode (and make sure to restore it at the end of your program), read bytes off it, and recognize ANSI control sequences. Oh, and if the user's keyboard has any keys that aren't ASCII, they'll also show up as multiple bytes that you'll have to decode as UTF-8.

Here's something that should demonstrate it:

import termios
import tty

with open('/dev/tty', 'rb', buffering=0) as f:
    stashed = termios.tcgetattr(f.fileno())
    try:
        tty.setraw(f.fileno())
        while True:
            key = f.read(1)
            if key == b'\x03': # Control-C
                break
            if key == b'\x1b': # Escape
                buf = key
                while True:
                    key = f.read(1)
                    buf += key
                    # Cheating a bit; most sequences go until the first letter
                    if key.isalpha():
                        break
                if buf == b'\x1b[A':
                    print('Up arrow!')
                else:
                    print('Some other control sequence:', buf)
            # punting on UTF-8 decoding, treating non-ASCII as control chars
            elif b' ' <= key < b'\x80':
                print(key.decode())
            else:
                print('Some control or non-ASCII key', key)
    finally:
        termios.tcsetattr(f.fileno(), termios.TCSADRAIN, stashed)

If this doesn't demonstrate why people usually use higher-level libraries like curses, then look for some code that actually does the termcap and locale stuff right instead of assuming. :)

abarnert
  • 354,177
  • 51
  • 601
  • 671
-1

I tried to... However you need to press enter for it to return the value. Good Luck!

import sys

def get():
    x = sys.stdin.read(1)
    return x
while True: 

    key = get()
    print key