#!/usr/bin/env python
# -*- coding: utf-8 -*-

### BEGIN INIT INFO
# Provides:          autokey
# Required-Start:    
# Required-Stop:     
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start AutoKey daemon.
# Description:       Enable AutoKey's EvDev interface daemon.
### END INIT INFO

import sys, os, socket, glob, shutil
from autokey import evdev, daemon
from autokey.interface import DOMAIN_SOCKET_PATH, PACKET_SIZE

PACKET_STRING = "%s,%s,%s"

class AutoKeyDaemon(daemon.Daemon):

    def __init__(self):
        logFile = "/var/log/autokey-daemon.log"
        if os.path.exists(logFile):
            shutil.move(logFile, logFile + '.old')
        daemon.Daemon.__init__(self, '/tmp/autokey-daemon.pid', stdout=logFile, stderr=logFile)

    def get_device_paths(self):
        keyboardLocations = glob.glob("/dev/input/by-path/*-event-kbd")
        mouseLocations = glob.glob("/dev/input/by-path/*-event-mouse")
    
        sys.stdout.write("Keyboards: %s\nMice: %s\n" % (repr(keyboardLocations), repr(mouseLocations)))
        return keyboardLocations + mouseLocations
    
    def run(self):
        print "AutoKey daemon starting"
        if os.path.exists(DOMAIN_SOCKET_PATH):
            os.remove(DOMAIN_SOCKET_PATH)
        s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        s.bind(DOMAIN_SOCKET_PATH)
        os.chmod(DOMAIN_SOCKET_PATH, 0777)
        print "Created domain socket"

        while True:
            s.listen(1)
            try:
                conn, addr = s.accept()
                print "Accepted connection"
            except:
                print "Fatal error while accepting connections - daemon shutting down"
                break
            
            devices = evdev.DeviceGroup(self.get_device_paths())
            sys.stdout.flush()
            sys.stderr.flush()
            
            while True:
                try:
                    event = devices.next_event()
                except OSError:
                    print "Unable to read from device(s). Connection will be closed and restarted"
                    break
                    
                if event is not None:
                    if event.type == "EV_KEY" and isinstance(event.code, str):
                        if event.code.startswith("KEY"):
                            # Keyboard event
                            code = event.scanCode
                            button = ''
                            state = event.value
                            
                            try:
                                self.send_packet(conn, code, button, state)
                            except:
                                break
    
                        elif event.code.startswith("BTN") and event.value == 1:
                            # Mouse event - only care about button press, not release
                            code = ''
                            button = event.code
                            state = event.value
    
                            try:
                                self.send_packet(conn, code, button, state)
                            except:
                                break

            conn.close()
            devices.close()
            print "Connection closed"
            sys.stdout.flush()
            sys.stderr.flush()
                       
    def send_packet(self, conn, code, button, state):
        if code:
            code = self.translate_keycode(code)
        sendData = PACKET_STRING % (code, button, state)
        sendData += (PACKET_SIZE - len(sendData)) * ' '
        conn.send(sendData)
    
    def translate_keycode(self, keyCode):
        if keyCode < 151:
            keyCode += 8
        else:
            print "Got untranslatable evdev keycode: %d\n" % keyCode
            keyCode = 0
        return keyCode
    

if __name__ == "__main__":
    #daemon = AutoKeyDaemon('/tmp/autokey-daemon.pid', stdout=sys.__stdout__, stderr=sys.__stderr__)
    daemon = AutoKeyDaemon()
    if len(sys.argv) == 2:
        if 'start' == sys.argv[1]:
            daemon.start()
        elif 'stop' == sys.argv[1]:
            daemon.stop()
        elif 'restart' == sys.argv[1]:
            daemon.restart()
        elif 'force-reload' == sys.argv[1]:
            # we don't support on-the-fly reloading,
            # so just restart the daemon per DPM 9.3.2
            daemon.restart()            
        else:
            print "Unknown command"
            sys.exit(2)
        sys.exit(0)
    else:
        print "usage: %s {start|stop|restart|force-reload}" % sys.argv[0]
        sys.exit(2)
    
    sys.exit(0)
            
    
