import win32console, win32con
import traceback, time

virtual_keys={}
for k,v in list(win32con.__dict__.items()):
    if k.startswith('VK_'):
        virtual_keys[v]=k 

free_console=True
try:
    win32console.AllocConsole()
except win32console.error as exc:
    if exc.winerror!=5:
        raise
    ## only free console if one was created successfully
    free_console=False

stdout=win32console.GetStdHandle(win32console.STD_OUTPUT_HANDLE)
stdin=win32console.GetStdHandle(win32console.STD_INPUT_HANDLE)
newbuffer=win32console.CreateConsoleScreenBuffer()
newbuffer.SetConsoleActiveScreenBuffer()
newbuffer.SetConsoleTextAttribute(win32console.FOREGROUND_RED|win32console.FOREGROUND_INTENSITY
        |win32console.BACKGROUND_GREEN|win32console.BACKGROUND_INTENSITY)
newbuffer.WriteConsole('This is a new screen buffer\n')

## test setting screen buffer and window size
## screen buffer size cannot be smaller than window size
window_size=newbuffer.GetConsoleScreenBufferInfo()['Window']
coord=win32console.PyCOORDType(X=window_size.Right+20, Y=window_size.Bottom+20)
newbuffer.SetConsoleScreenBufferSize(coord)

window_size.Right+=10
window_size.Bottom+=10
newbuffer.SetConsoleWindowInfo(Absolute=True,ConsoleWindow=window_size)

## write some records to the input queue 
x=win32console.PyINPUT_RECORDType(win32console.KEY_EVENT)
x.Char='X'
x.KeyDown=True
x.RepeatCount=1
x.VirtualKeyCode=0x58
x.ControlKeyState=win32con.SHIFT_PRESSED

z=win32console.PyINPUT_RECORDType(win32console.KEY_EVENT)
z.Char='Z'
z.KeyDown=True
z.RepeatCount=1
z.VirtualKeyCode=0x5a
z.ControlKeyState=win32con.SHIFT_PRESSED

stdin.WriteConsoleInput([x,z,x])

newbuffer.SetConsoleTextAttribute(win32console.FOREGROUND_RED|win32console.FOREGROUND_INTENSITY
        |win32console.BACKGROUND_GREEN|win32console.BACKGROUND_INTENSITY)
newbuffer.WriteConsole('Press some keys, click some characters with the mouse\n')

newbuffer.SetConsoleTextAttribute(win32console.FOREGROUND_BLUE|win32console.FOREGROUND_INTENSITY
        |win32console.BACKGROUND_RED|win32console.BACKGROUND_INTENSITY)
newbuffer.WriteConsole('Hit "End" key to quit\n')
                    
breakout=False
while not breakout:
    input_records=stdin.ReadConsoleInput(10)
    for input_record in input_records:
        if input_record.EventType==win32console.KEY_EVENT:
            if input_record.KeyDown:
                if input_record.Char=='\0':
                    newbuffer.WriteConsole(virtual_keys.get(input_record.VirtualKeyCode, 'VirtualKeyCode: %s' %input_record.VirtualKeyCode))
                else:
                    newbuffer.WriteConsole(input_record.Char)
                if input_record.VirtualKeyCode==win32con.VK_END:
                    breakout=True
                    break
        elif input_record.EventType==win32console.MOUSE_EVENT:
            if input_record.EventFlags==0:  ## 0 indicates a button event
                if input_record.ButtonState!=0:   ## exclude button releases
                    pos=input_record.MousePosition
                    # switch the foreground and background colors of the character that was clicked
                    attr=newbuffer.ReadConsoleOutputAttribute(Length=1, ReadCoord=pos)[0]
                    new_attr=attr
                    if attr&win32console.FOREGROUND_BLUE:
                        new_attr=(new_attr&~win32console.FOREGROUND_BLUE)|win32console.BACKGROUND_BLUE
                    if attr&win32console.FOREGROUND_RED:
                        new_attr=(new_attr&~win32console.FOREGROUND_RED)|win32console.BACKGROUND_RED
                    if attr&win32console.FOREGROUND_GREEN:
                        new_attr=(new_attr&~win32console.FOREGROUND_GREEN)|win32console.BACKGROUND_GREEN

                    if attr&win32console.BACKGROUND_BLUE:
                        new_attr=(new_attr&~win32console.BACKGROUND_BLUE)|win32console.FOREGROUND_BLUE
                    if attr&win32console.BACKGROUND_RED:
                        new_attr=(new_attr&~win32console.BACKGROUND_RED)|win32console.FOREGROUND_RED
                    if attr&win32console.BACKGROUND_GREEN:
                        new_attr=(new_attr&~win32console.BACKGROUND_GREEN)|win32console.FOREGROUND_GREEN
                    newbuffer.WriteConsoleOutputAttribute((new_attr,),pos)
        else:
            newbuffer.WriteConsole(str(input_record))
    time.sleep(0.1)

stdout.SetConsoleActiveScreenBuffer()
newbuffer.Close()
if free_console:
     win32console.FreeConsole()

