import curses, sys, termios

# this is a huge map of ASCII keycode sequences it should include all
# the "standard" ones for a US 104 key keyboard. this module may need
# to support some kind of subclassing in order to be localizable.
#
# of course, i'd be crazy to try to localize a curses app
MAP = { 0: "C-@",
        1: "C-a",
        2: "C-b",
        3: "C-c",
        4: "C-d",
        5: "C-e",
        6: "C-f",
        7: "C-g",
        #8: "C-h",
        8: "BACKSPACE",
        #9: "C-i",
        9: "TAB",
        #10: "C-j",
        10: "RETURN",
        11: "C-k",
        12: "C-l",
        #13: "C-m",
        13: "RETURN",
        14: "C-n",
        15: "C-o",
        16: "C-p",
        17: "C-q",
        18: "C-r",
        19: "C-s",
        20: "C-t",
        21: "C-u",
        22: "C-v",
        23: "C-w",
        24: "C-x",
        25: "C-y",
        26: "C-z",
        27: { 79: { 80: "F1",
                    81: "F2",
                    82: "F3",
                    83: "F4" },
              91: { 49: { 49: { 126: "F1" },
                          50: { 126: "F2" },
                          51: { 126: "F3" },
                          52: { 126: "F4" },
                          53: { 126: "F5" },
                          55: { 126: "F6" },
                          56: { 126: "F7" },
                          57: { 126: "F8" },
                          126: "HOME" },
                    50: { 48: { 126: "F9" },
                          49: { 126: "F10" },
                          51: { 126: "F11" },
                          52: { 126: "F12" },
                          126: "INSERT" },
                    51: { 126: "DELETE" },
                    52: { 126: "END" },
                    53: { 126: "PG_UP" },
                    54: { 126: "PG_DN" },
                    65: "U_ARROW",
                    66: "D_ARROW",
                    67: "R_ARROW",
                    68: "L_ARROW",
                    90: "LEFT_TAB",
                    91: { 65: "F1",
                          66: "F2",
                          67: "F3",
                          68: "F4",
                          69: "F5" } } },
        28: "C-\\",
        29: "C-]",
        30: "C-30",
        31: "C-/",
        32: "SPACE",
        127: "DELETE" }

# add the meta/control-char combinations
for key in MAP.iterkeys():
    if key == 27:
        # we don't want to define ESC-ESC
        continue
    MAP[27][key] = "M-%s" % (MAP[key])

# add meta character stuff
for i in range(33, 126):
    if i == 79 or i == 91:
        # these keys are used in other sequences
        continue
    # 7bit meta sequences
    MAP[27][i] = "M-%s" % (chr(i))
    # 8bit meta characters
    MAP[128+i] = "M-%s" % (chr(i))

def disable_control_chars():
    #terminal settings are for chumps
    attr = termios.tcgetattr(sys.stdin)

    global OLD_ATTR
    OLD_ATTR = attr
    
    # don't listen to allow input START/STOP (C-s,C-q)
    attr[0] = attr[0] & ~(termios.IXON | termios.IXOFF)
    
    # remove as many signal handlers as we can; we want to
    # leave C-d and C-z probably
    for pos in range(0,len(attr[6])):
        if pos == termios.VEOF or pos == termios.VSUSP:
            continue
        attr[6][pos] = '\x00'
        
    # write the attributes back
    termios.tcsetattr(sys.stdin, termios.TCSANOW, attr)


class Handler(object):
    def __init__(self):
        self.tokens = []
        self.unset_meta()
    def unset_meta(self):
        self.meta = MAP
    def set_meta(self, d):
        self.meta = d

    def parse(self, i):
        if i == -1:
            # this means that no key was actually pressed
            return

        if i in self.meta:
            # we have a special "named" token (a control character or
            # a meta sequence)
            if type(self.meta[i]) == type({}):
                # ok, we need to keep traversing down to finish the
                # meta sequence
                self.set_meta(self.meta[i])
            else:
                # ok, we either got a control character or finished a
                # meta sequence
                self.tokens.append(self.meta[i])
                self.unset_meta()
        else:
            # we got a regular character 
            # we may have interrupted a meta sequence... so unset it
            self.unset_meta()

            if(32 < i and i < 127):
                # we got a "regular" keycode, so use it
                self.tokens.append(chr(i))
            else:
                # this shouldn't really happen
                raise Exception, "strange keycode recieved: %d" % (i)