#!/usr/bin/env python #Listens for IR codes and sends the associated keystroke to the local system. #Must be run as a non-root user. import os from socket import socket,AF_INET,SOCK_STREAM,SOL_SOCKET,SO_REUSEADDR class IRListener: XTE = "/usr/bin/xte" LOG_FILE = "/var/log/ir.log" DISPLAY=":0" #Currently has entries for Sony, RC6 and NEC protocols KEY_CODES = { #Enter / OK 'Return' : { 'key_type' : 'key', 'code_list' : [ 'D0B92', '1045C', '45C', '482C807F' ] }, #Arrow left / skip backwards 'Left' : { 'key_type' : 'key', 'code_list' : [ 'DEB92', 'CB92', '1045A', '45A', '10421', '421', '482C20DF' ] }, #Arrow right / skip forwards 'Right' : { 'key_type' : 'key', 'code_list' : [ '3EB92', '8CB92', '1045B', '45B', '10420', '420', '482CA05F' ] }, #Arrow up 'Up' : { 'key_type' : 'key', 'code_list' : [ '9EB92', '10458', '458', '482C40BF' ] }, #Arrow down 'Down' : { 'key_type' : 'key', 'code_list' : [ '5EB92', '10459', '459', '482CC03F' ] }, #Previous screen, activated by either the 'Title' or 'Display' buttons 'Escape' : { 'key_type' : 'key', 'code_list' : [ '70B92', '58B92', '2AB92', '10483', '483', '1040F', '40F', '482CB847', '20DF50AF' ] }, #Volume up '+' : { 'key_type' : 'str', 'code_list' : [ '490', '482C609F', '20DF40BF' ] }, #Volume down '-' : { 'key_type' : 'str', 'code_list' : [ 'C90', '482CE01F', '20DFC03F' ] }, #Home screen, activated by the 'Menu' button 'H' : { 'key_type' : 'str', 'code_list' : [ 'D8B92', '104D1', '4D1', '482CD827' ] }, #Stop playback 'X' : { 'key_type' : 'str', 'code_list' : [ '1CB92', '10431', '431' ] }, #Play / pause ' ' : { 'key_type' : 'str', 'code_list' : [ '4CB92', '9CB92', '1042C', '42C' ] }, #Seek right, activated by the 'Search/Step Right' button '>' : { 'key_type' : 'str', 'code_list' : [ '84B92' ] }, #Seek left, activated by the 'Search/Step Left' button '<' : { 'key_type' : 'str', 'code_list' : [ '4B92' ] }, #1 '1' : { 'key_type' : 'str', 'code_list' : [ 'B92', '482C8877', '10401', '401' ] }, #2 '2' : { 'key_type' : 'str', 'code_list' : [ '80B92', '482C48B7', '10402', '402' ] }, #3 '3' : { 'key_type' : 'str', 'code_list' : [ '40B92', '482CC837', '10403', '403' ] }, #4 '4' : { 'key_type' : 'str', 'code_list' : [ 'C0B92', '482C28D7', '10404', '404' ] }, #5 '5' : { 'key_type' : 'str', 'code_list' : [ '20B92', '482CA857', '10405', '405' ] }, #6 '6' : { 'key_type' : 'str', 'code_list' : [ 'A0B92', '482C6897', '10406', '406' ] }, #7 '7' : { 'key_type' : 'str', 'code_list' : [ '60B92', '482CE817', '10407', '407' ] }, #8 '8' : { 'key_type' : 'str', 'code_list' : [ 'E0B92', '482C18E7', '10408', '408' ] }, #9 '9' : { 'key_type' : 'str', 'code_list' : [ '10B92', '482C9867', '10409', '409' ] }, #0 '0' : { 'key_type' : 'str', 'code_list' : [ '90B92', '482C08F7', '10400', '400' ] } } def __init__(self,port): self.socket = socket(AF_INET,SOCK_STREAM) self.socket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) self.socket.bind(('',port)) self.daemonize() self.serve_forever() def serve_forever(self): self.socket.listen(1) while True: csock,caddr = self.socket.accept() self.handle(csock.recv(1024)) csock.close() def daemonize(self): child = 0 process = os.fork() if process is child: os.setsid() process = os.fork() if process is not child: os._exit(0) else: os._exit(0) return def handle(self,data): valid_key = False buf = '' if ':' in data: (vendor,code) = data.strip().split(':',1) vendor = vendor.upper().strip() code = code.upper().strip() for key,key_info in self.KEY_CODES.iteritems(): if code in key_info['code_list']: self.execute(key,key_info['key_type']) valid_key = True break if not valid_key: self.log("Received unknown key code: '%s:%s'" % (vendor,code)) return def execute(self,key,key_type): if os.path.exists(self.XTE): os.system("export DISPLAY=%s && %s '%s %s'" % (self.DISPLAY,self.XTE,key_type,key)) else: self.log("Command %s does not exist!" % self.XTE) def log(self,strmsg): try: open(self.LOG_FILE,"a").write(strmsg + "\n") except Exception,e: print strmsg if __name__ == "__main__": port = 4919 irListener = IRListener(port)