diff options
| -rw-r--r-- | abs/core/powermate_myth/PKGBUILD | 16 | ||||
| -rw-r--r-- | abs/core/powermate_myth/powermate-myth.py | 214 | ||||
| -rw-r--r-- | abs/core/powermate_myth/powermate.py | 106 | 
3 files changed, 336 insertions, 0 deletions
diff --git a/abs/core/powermate_myth/PKGBUILD b/abs/core/powermate_myth/PKGBUILD new file mode 100644 index 0000000..1581477 --- /dev/null +++ b/abs/core/powermate_myth/PKGBUILD @@ -0,0 +1,16 @@ +pkgname=powermate_myth +pkgver=1.0 +pkgrel=1 +arch=('i686') +pkgdesc="Provides support and sample program for using the powermate with mtythv" +url="" +depends=(python2 xdotool) +source=(powermate-myth.py  powermate.py) + +build() { +  cd $startdir/src +  install -D -m0755 powermate.py  $startdir/pkg/usr/LH/bin/powermate.py +  install -D -m0755 powermate-myth.py  $startdir/pkg/usr/LH/bin/powermate-myth.py +} +md5sums=('44a03725355ed53d9f81099923d94329' +         '90bed7b80570ad6e63ebff827830e14b') diff --git a/abs/core/powermate_myth/powermate-myth.py b/abs/core/powermate_myth/powermate-myth.py new file mode 100644 index 0000000..85e5165 --- /dev/null +++ b/abs/core/powermate_myth/powermate-myth.py @@ -0,0 +1,214 @@ +#!/usr/bin/python2 + +import powermate +import time +import os + +EVENT_BUTTON_PRESS = 1 +EVENT_RELATIVE_MOTION = 2 + + +button_pressed = False +single_tap = False +mode = "nav" + +current_event=(0,0,time.time()) +last_event=current_event +skipped_event = 0 +pressed_time = 0 +button_held = False +led_brightness = 255 +#pm = powermate.PowerMate("/dev/powermate") + +pm = powermate.PowerMate() +pm.SetLEDState(led_brightness,0,0,0,0) + + +def runcmd(cmd): +#    print cmd +    os.system(cmd) + + +def volume_action(action): +    global mode +    global led_brightness +    if action == "L" : +        print "Volume down" + +    if action == "R" : +        print "Volume UP" + +    if action == "tap" : +        print "toggle mute" + +    if action == "double_tap" : +        mode = "nav" +        led_brightness = 500 +        print "mode is now nav" + +    return + + +def nav_action(action): +    global mode +    global led_brightness +    keycmd = '''xdotool search --name "Mythtv Frontend" key %s''' +    if action == "L" : +        #print "prev" +       cmd =  keycmd %"Up" +       runcmd(cmd) + +    if action == "R" : +        #print "next" +        cmd =  keycmd %"Down" +        runcmd(cmd) + +    if action == "LP" : +        #print "back" +        cmd =  keycmd %"Left" +        runcmd(cmd) + +    if action == "RP" : +        #print "tab" +        cmd =  keycmd %"Right" +        runcmd(cmd) + + +    if action == "tap" : +        #print "select" +        cmd =  keycmd %"Return" +        runcmd(cmd) + +    if action == "double_tap" : +        mode = "volume" +        led_brightness = 10 +        print "mode is now vol" + +    if action == "button_held" : +        cmd =  keycmd %"Escape" +        runcmd(cmd) + + + +    return + + + + +def act_on_event(action): + +    if mode == "volume": +        volume_action(action) + +    elif mode == "nav": +        nav_action(action) + + + + +event_stack=[current_event] +while 1: +        #process_events = True +        reset_lastevent = False +	event = pm.WaitForEvent(2) +       # print event +        if event: +            #event that happens after every button push, can be thrown away. +            if event[2] == 0: +                continue + + +        elif single_tap: +            pressed_diff = time.time() - pressed_time +            #This takes care of the holding down the button for X amount of time +            #print event,  button_pressed, pressed_diff, current_event +            #if pressed_diff >= 2 and button_pressed and current_event[0] == EVENT_BUTTON_PRESS: +            if pressed_diff >= 2 and button_pressed : +                act_on_event("button_held") +                single_tap = False +                pressed_time = 0 +                button_pressed = False +                last_event_time = time.time() +                last_event=(0,0,time.time()) +                pm.SetLEDState(led_brightness,0,0,0,0) +                #print "resetting last event:",  last_event + + +           #This handles a single press of the button. +            elif not button_pressed : +                act_on_event("tap") +                single_tap = False +                last_event_time = time.time() +                last_event=(0,0,time.time()) + +        if event: +            #print "processing:" , event +            current_event = event[2],event[4],time.time() + +            last_event_time = last_event[2] +            current_event_time = current_event[2] + +            last_event_only = last_event[0], last_event[1] +            current_event_only = current_event[0], current_event[1] + +            repeat_rate = 10 +            repeat_time = .50 + +            if last_event_only == current_event_only and  current_event[0] == EVENT_RELATIVE_MOTION : +                #check for time diff +                event_time_diff = current_event_time - last_event_time + +                if  skipped_event <= repeat_rate and event_time_diff <= repeat_time: +                    skipped_event = skipped_event + 1 +                    #print "skipped a repeat event : %s" %skipped_event +                    continue +            #event occured, reset skip counter +            skipped_event = 0 + +            #rotate dial +            if current_event[0] == EVENT_RELATIVE_MOTION: +                reset_lastevent = True +                single_tap = False +                if current_event[1] >= 0 : +                    if button_pressed : +                        #print "dial turned Counter clockwise and button is pressed" +                        act_on_event("RP") +                    else: +                        #print "dial turned Counter clockwise" +                        act_on_event("R") + +                if current_event[1]  <=0 : +                    if button_pressed : +                        #print "dial turned clockwise and button is pressed" +                        act_on_event("LP") +                    else: +                        #print "dial turned clockwise" +                        act_on_event("L") + + +            #button was pushed +            if current_event[0] == EVENT_BUTTON_PRESS : +                pm.SetLEDState(0,0,0,0,0) +                if current_event[1] == 1: +                    button_pressed = True +                    pressed_time = current_event_time +                    tap_diff = current_event_time - last_event_time +                    #double tap +                    if tap_diff < 0.2 and last_event[0] == EVENT_BUTTON_PRESS: +                        act_on_event("double_tap") +                        single_tap = False +                    else: +                        single_tap = True +                        reset_lastevent = True + +                #button was released +                elif current_event[1] == 0: +                    button_pressed = False +                    pressed_time  = 0 +                    pm.SetLEDState(led_brightness,0,0,0,0) + +        if reset_lastevent: +            last_event = current_event + + + diff --git a/abs/core/powermate_myth/powermate.py b/abs/core/powermate_myth/powermate.py new file mode 100644 index 0000000..8e40078 --- /dev/null +++ b/abs/core/powermate_myth/powermate.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python + +import select +import os +import fcntl +import struct +import exceptions + +#struct input_event { +#        struct timeval time; = {long seconds, long microseconds} +#        unsigned short type; +#        unsigned short code; +#        unsigned int value; +#}; + +input_event_struct = "@llHHi" +input_event_size = struct.calcsize(input_event_struct) + +EVENT_BUTTON_PRESS = 1 +EVENT_RELATIVE_MOTION = 2 +RELATIVE_AXES_DIAL = 7 +BUTTON_MISC = 0x100 + +def report(x): +    sys.stderr.write(x + "\n") + +class PowerMate: +    def __init__(self, filename = None): +        self.handle = -1 +        if filename: +            if not self.OpenDevice(filename): +                raise exceptions.RuntimeError, 'Unable to find powermate' +        else: +            ok = 0 +            for d in range(0, 16): +                if self.OpenDevice("/dev/input/event%d" % d): +                    ok = 1 +                    break +            if not ok: +                raise exceptions.RuntimeError, 'Unable to find powermate' +        self.poll = select.poll() +        self.poll.register(self.handle, select.POLLIN) +        self.event_queue = [] # queue used to reduce kernel/userspace context switching + +    def __del__(self): +        if self.handle >= 0: +            self.poll.unregister(self.handle) +            os.close(self.handle) +            self.handle = -1 +            del self.poll + +    def OpenDevice(self, filename): +        try: +            self.handle = os.open(filename, os.O_RDWR) +            if self.handle < 0: +                return 0 +            name = fcntl.ioctl(self.handle, 0x80ff4506, chr(0) * 256) # read device name +            name = name.replace(chr(0), '') +            if name == 'Griffin PowerMate' or name == 'Griffin SoundKnob': +                fcntl.fcntl(self.handle, fcntl.F_SETFL, os.O_NDELAY) +                return 1 +            os.close(self.handle) +            self.handle = -1 +            return 0 +        except exceptions.OSError: +            return 0 + +    def WaitForEvent(self, timeout): # timeout in seconds +        if len(self.event_queue) > 0: +            return self.event_queue.pop(0) +        if self.handle < 0: +            return None +        r = self.poll.poll(int(timeout*100)) +        if len(r) == 0: +            return None +        return self.GetEvent() + +    def GetEvent(self): # only call when descriptor is readable +        if self.handle < 0: +            return None +        try: +            data = os.read(self.handle, input_event_size * 32) +            while data != '': +                self.event_queue.append(struct.unpack(input_event_struct, data[0:input_event_size])) +                data = data[input_event_size:] +            return self.event_queue.pop(0) +        except exceptions.OSError, e: # Errno 11: Resource temporarily unavailable +            #if e.errno == 19: # device has been disconnected +            #    report("PowerMate disconnected! Urgent!"); +            return None + +    def SetLEDState(self, static_brightness, pulse_speed, pulse_table, pulse_on_sleep, pulse_on_wake): +        static_brightness &= 0xff; +        if pulse_speed < 0: +            pulse_speed = 0 +        if pulse_speed > 510: +            pulse_speed = 510 +        if pulse_table < 0: +            pulse_table = 0 +        if pulse_table > 2: +            pulse_table = 2 +        pulse_on_sleep = not not pulse_on_sleep # not not = convert to 0/1 +        pulse_on_wake  = not not pulse_on_wake +        magic = static_brightness | (pulse_speed << 8) | (pulse_table << 17) | (pulse_on_sleep << 19) | (pulse_on_wake << 20) +        data = struct.pack(input_event_struct, 0, 0, 0x04, 0x01, magic) +        os.write(self.handle, data)  | 
