#!/usr/bin/python
import socket
import pygtk
pygtk.require("2.0")
import gtk
import time
import sys

class Keyboard:
    def __init__(self):
        self.layout = [
            [
            ("kurp", [0x7e,0xf0,0x7e,0x7e,0xf0,0x7e,0x16,0xf0,0x16]),
            ("colosseum", [0x7e,0xf0,0x7e,0x7e,0xf0,0x7e,0x2e,0xf0,0x2e]),
            ("apps1", [0x7e,0xf0,0x7e,0x7e,0xf0,0x7e,0x36,0xf0,0x36]),
            ("apps2", [0x7e,0xf0,0x7e,0x7e,0xf0,0x7e,0x3d,0xf0,0x3d])
            ],
            [
            ("1", 0x16),
            ("2", 0x1e),
            ("3", 0x26),
            ("4", 0x25),
            ("5", 0x2e),
            ("6", 0x36),
            ("7", 0x3d),
            ("8", 0x3e),
            ("9", 0x46),
            ("0", 0x45)
            ],
            [
            ("q", 0x15),
            ("w", 0x1d),
            ("e", 0x24),
            ("r", 0x2d),
            ("t", 0x2c),
            ("y", 0x35),
            ("u", 0x3c),
            ("i", 0x43),
            ("o", 0x44),
            ("p", 0x4d)
            ],
            [
            ("a", 0x1c),
            ("s", 0x1b),
            ("d", 0x23),
            ("f", 0x2b),
            ("g", 0x34),
            ("h", 0x33),
            ("j", 0x3b),
            ("k", 0x42),
            ("l", 0x4b)
            ],
            [
            ("z", 0x1a),
            ("x", 0x22),
            ("c", 0x21),
            ("v", 0x2a),
            ("b", 0x32),
            ("n", 0x31),
            ("m", 0x3a),
            (",", 0x41),
            (".", 0x49),
            ("-", 0x4a)
            ],
            [
            ("Escape", 0x76),
            ("Tab", 0x0d),
            ("Control_L", 0x14),
            ("Alt_L", 0x11),
            ("Shift_L", 0x12),
            ("space", 0x29),
            ("Return", 0x5a),
            ("BackSpace", 0x66),
            ("Scroll_Lock", 0x7e)
            ]]
        
        self.keymap = {}
        for row in self.layout:
            for (key,code) in row:
                self.keymap[key] = code
        
    def connect(self, host, port):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.connect((host, port))

    def get_layout(self):
        return self.layout
    
    def count_ones(self, w):
        ret = 0
        while w:
            if w & 1:
                ret = 1-ret
            w = w >> 1
        return ret
        
    def send_scancode(self, scancode):
        while True:
            s = "s0"
            for i in range(0,8):
                if (scancode >> i) & 1:
                    s += "1"
                else:
                    s += "0"
            if self.count_ones(scancode):
                s += "0"
            else:
                s += "1"
            s += "1"
            #print("send_scancode %02x %s" % (scancode, s))
            self.sock.send(s)
            ret = self.sock.recv(1)
            if ret == 'E':
                time.sleep(0.001);
            elif ret == 'O':
                return
            else:
                print("unexpected reply %s" % repr(ret))

    def press_key(self, key):
        if key in self.keymap:
            self.send_scancode(self.keymap[key])
#            time.sleep(0.1)
        else:
            print("key \"%s\" is unknown" % key)

    def release_key(self, key):
        if key in self.keymap:
            self.send_scancode(0xf0)
#            time.sleep(0.02)
            self.send_scancode(self.keymap[key])
#            time.sleep(0.1)
        else:
            print("key \"%s\" is unknown" % key)

class GUI:
    def delete_event(self, widget, event, data=None):
        return False
    def destroy(self, widget, data=None):
        gtk.main_quit()

    def press_key(self, widget, key):
        self.keyboard.press_key(key)
    def release_key(self, widget, key):
        self.keyboard.release_key(key)
    def toggle_key(self, togglebutton, key):
        if togglebutton.get_active():
            self.keyboard.press_key(key)
        else:
            self.keyboard.release_key(key)

    def send_raw(self, widget, codes):
        for code in codes:
            self.keyboard.send_scancode(code)
            
    def __init__(self, keyboard):
        self.keyboard = keyboard
        
        w = gtk.Window(gtk.WINDOW_TOPLEVEL)
        w.connect("delete_event", self.delete_event)
        w.connect("destroy", self.destroy)
        w.set_default_size(640, 90)
        w.set_border_width(10)
        w.show()

        vbox = gtk.VBox(False, 0)
        w.add(vbox)
        vbox.show()

        for row in self.keyboard.get_layout():
            hbox = gtk.HBox(False, 0)
            vbox.pack_start(hbox)
            hbox.show()

            for (key,code) in row:
                button = 0
                if key in ["Shift_L", "Control_L", "Alt_L"]:
                    button = gtk.ToggleButton(key)
                    button.connect("toggled", self.toggle_key, key)
                elif isinstance(code, list):
                    button = gtk.Button(key)
                    button.connect("clicked", self.send_raw, code)
                else:
                    button = gtk.Button(key)
                    button.connect("pressed", self.press_key, key)
                    button.connect("released", self.release_key, key)
                button.set_focus_on_click(False)
                button.show()
                hbox.pack_start(button)

    def main(self):
        gtk.main()

if __name__ == "__main__":
    if len(sys.argv) < 3:
        print("usage: %s hostname port [scancode]" % sys.argv[0])
        sys.exit(1)
    keyboard = Keyboard()
    keyboard.connect(sys.argv[1], int(sys.argv[2]))
    if len(sys.argv) == 3:
        GUI(keyboard).main()
    else:
        for code in sys.argv[3:]:
            keyboard.send_scancode(int(code, 16))
            time.sleep(0.01)
