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

class Keyboard:
    def __init__(self):
        pass
    def connect(self, host, port):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.connect((host, port))

    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))
                exit(1)

    def generate_keyboard_event(self, key, t):
        assert t == "break" or t == "make"
        if key in scancodes.set2:
            for i in scancodes.set2[key][t]:
                self.send_scancode(i)
        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.generate_keyboard_event(key, "make")
    def release_key(self, widget, key):
        self.keyboard.generate_keyboard_event(key, "break")
    def toggle_key(self, togglebutton, key):
        t = ""
        if togglebutton.get_active():
            t = "make"
        else:
            t = "break"
        self.keyboard.generate_keyboard_event(key, t)

    def send_button_event(self, widget, t):
        if t == "make-break":
            self.keyboard.generate_keyboard_event(self.combo.entry.get_text(), t)
        self.keyboard.generate_keyboard_event(self.combo.entry.get_text(), t)
        
    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()

        hbox = gtk.HBox(False, 0)
        vbox.pack_start(hbox)
        hbox.show()
        
        self.combo = gtk.Combo()
        hbox.pack_start(self.combo)
        keys = scancodes.set2.keys()
        keys.sort()
        self.combo.set_popdown_strings(keys)
        self.combo.show()
        sendButton = gtk.Button("Press")
        sendButton.connect("pressed", self.send_button_event, "make")
        sendButton.show()
        releaseButton = gtk.Button("Release")
        releaseButton.connect("pressed", self.send_button_event, "break")
        releaseButton.show()
        hbox.pack_start(sendButton)
        hbox.pack_start(releaseButton)
        
        for row in scancodes.simplelayout:
            hbox = gtk.HBox(False, 0)
            vbox.pack_start(hbox)
            hbox.show()

            for key in row:
                button = 0
                if key in scancodes.stickykeys:
                    button = gtk.ToggleButton(key)
                    button.connect("toggled", self.toggle_key, key)
                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)
