tsprlng-nad-link/daemon.py

87 lines
3.0 KiB
Python
Executable File

#!/usr/bin/python
# Daemon to listen to keyboard-style events from my Bluetooth remote and trigger things (including NAD-link).
import struct
import sys
from subprocess import Popen as popen
import os.path
import itertools
import fcntl
def eviocgrab(file_descriptor): # linux call for super annoying exclusive access to input device
EVIOCGRAB = 1074021776
return fcntl.ioctl(file_descriptor, EVIOCGRAB, 1)
CommandScript = './nad-link.py'
def cmd(cmd):
return popen(['/usr/bin/python', CommandScript, cmd])
EventFilePath = "/dev/input/bt-remote"
EventStructFormat = 'llHHI' # long, long, unsigned short, unsigned short, unsigned int
EventStructSize = struct.calcsize(EventStructFormat)
HyperionSeqs = {
400: ['--color 222211', '--color 886633', '--color ffcc77', '--color 88ffcc'],
401: ['--color 000000', '--clearall']
}
hyperionLastKey = None
hyperionSeq = None
def hyperion(keycode):
global hyperionLastKey, hyperionSeq # why must statics be so annoying?
if keycode != hyperionLastKey:
hyperionSeq = itertools.cycle(HyperionSeqs[keycode])
hyperionLastKey = keycode
popen(itertools.chain(['hyperion-remote'], hyperionSeq.next().split(' '))).wait()
thing = None # holds the current invocation of the nad-link script (while there is one) for holdy commands like volume
def handle(type, code, value):
global thing
if (code < 113 or code > 115) and (code < 398 or code > 401): # disregard bizarre noise events
return
if thing:
# Pressing something else while already holding a volume key at once is unacceptable silliness.
# Therefore, this will quit the control script when that happens!
# As a happy accident it also covers the normal deliberate 'key up' (value = 0) events.
thing.send_signal(2) # SIGINT
thing.wait()
thing = None
elif value != 1:
return
elif code == 114: # volume down
thing = cmd('-')
elif code == 115: # volume up
thing = cmd('+')
elif code == 113: # mute
cmd('monitor').wait()
elif code == 398: # red button
cmd('off').wait()
elif code == 399: # green button
cmd('pi').wait() # switch source if on
cmd('on').wait() # or switch on if not
elif code >= 400 and code <= 401: # yellow and blue!
hyperion(code)
if len(sys.argv) >= 2 and sys.argv[1] == 'print': # i miss 'rescue nil'
def handle(*things): print(', '.join(str(thing) for thing in things))
# open the keyboard event file in binary mode (whatever the hell that is)
with open(EventFilePath, "rb") as in_file:
eviocgrab(in_file)
# exclusively grab the keyboard... so that XBMC can't exclusively grab the keyboard
# (thanks for that, XBMC.)
# remember to make sure this daemon starts before XBMC does!
while True:
event = in_file.read(EventStructSize)
if not event:
break
(tv_sec, tv_usec, type, code, value) = struct.unpack(EventStructFormat, event)
handle(type, code, value)