File indexing completed on 2024-05-19 05:35:37

0001 # SPDX-License-Identifier: GPL-3.0-or-later
0002 # SPDX-FileCopyrightText: 2021 Aditya Mehra <aix.m@outlook.com>
0003 
0004 import os
0005 import time
0006 import cec
0007 import subprocess
0008 import threading
0009 
0010 from PySide2.QtCore import QUrl, Slot, Signal, QProcess, QByteArray, Property, QObject
0011 from PySide2.QtQml import qmlRegisterType
0012 
0013 from PicoWizard.module import Module
0014 from PicoWizard.utils.logger import Logger
0015 
0016 
0017 class Cec(Module):
0018     log = Logger.getLogger(__name__)
0019             
0020     def __init__(self, parent=None):
0021         super().__init__(__file__, parent)
0022         self.cec_available = False
0023         self.keystate = None
0024         
0025         # 0 = initializing, 1 = cec available, 2 = cec not available, 3 = key mapping stage, 4 = done
0026         self.setup_stage = 0
0027         self.key_stage = 0
0028         self.running = False
0029         self.threaded_cec = None
0030         
0031     @staticmethod
0032     def registerTypes() -> None:
0033         qmlRegisterType(Cec, 'PicoWizard', 1, 0, 'CecModule')
0034 
0035     @staticmethod
0036     def qmlPath() -> QUrl:
0037         return QUrl(os.path.join(os.path.dirname(os.path.realpath(__file__)), "Cec.qml"))
0038 
0039     @Slot(None, result=str)
0040     def moduleName(self) -> str:
0041         return self.tr("Cec")
0042     
0043     @Slot(None, result=int)
0044     def getCurrentSetupStage(self) -> str:
0045         self.log.info("getCurrentSetupStage requested")
0046         self.log.info("setup_stage: {}".format(self.setup_stage))
0047         return self.setup_stage
0048     
0049     @Slot(None, result=int)
0050     def getCurrentKeyStage(self) -> str:
0051         return self.key_stage
0052 
0053     @Slot(None, result=None)
0054     def initilize_cec(self):
0055         self.setup_stage = 0 # initializing
0056         self.setupStageChanged.emit()
0057 
0058         self.log.info("Initializing CEC")
0059 
0060         self.threaded_cec = threading.Thread(target=self.run_cec_in_thread)
0061         self.threaded_cec.start()
0062 
0063     # End cec mapping process successfully
0064     @Slot(None, result=None)
0065     def end_cec_mapping_success(self):
0066         process = QProcess(self)
0067         args = [os.path.join(os.path.dirname(os.path.realpath(__file__)), 'CopyConfig.sh')]
0068         process.start('/usr/bin/pkexec', args)
0069 
0070     # Restart cec mapping process
0071     @Slot(None, result=None)
0072     def restart_cec_mapping(self):
0073         self.log.info("Restarting CEC mapping")
0074         self.key_stage = 0
0075         self.keyStageChanged.emit()
0076         self.cleanUpConfig()
0077         self.appendStartToConfig()
0078 
0079     # cleanly close cec thread
0080     @Slot(None, result=None)
0081     def close_cec_thread(self):
0082         self.log.info("Closing CEC thread")
0083         self.running = False
0084         self.threaded_cec.join()
0085         self.threaded_cec = None
0086     
0087     # run cec in threaded mode
0088     def run_cec_in_thread(self):
0089         self.log.info("Running CEC in thread")
0090         try:
0091             cec.init()
0092             cec.add_callback(self.eventresponse, cec.EVENT_KEYPRESS)
0093             self.cec_available = True
0094             self.running = True
0095             self.setup_stage = 1
0096             self.setupStageChanged.emit()
0097             self.setup_stage = 3
0098             self.setupStageChanged.emit()
0099             self.keyStageChanged.emit()
0100             self.cleanUpConfig()
0101             self.appendStartToConfig()
0102             
0103             while self.running:
0104                 time.sleep(1)
0105         
0106         except Exception as e:
0107             self.log.error("Error: {}".format(e))
0108             self.cec_available = False
0109             self.setup_stage = 2
0110             self.setupStageChanged.emit()
0111 
0112     def eventresponse(self, event, key, state):
0113         if state > 0 and self.keystate == None:
0114             for x in range(1):
0115                 self.mapKeyToConfig(key)
0116 
0117     def cleanUpConfig(self):
0118         self.log.info("Cleaning up config")
0119         if os.path.exists("/tmp/plasma-remotecontrollersrc"):
0120             os.remove("/tmp/plasma-remotecontrollersrc")
0121 
0122     def appendStartToConfig(self):
0123         configFile = open("/tmp/plasma-remotecontrollersrc", "a")
0124         configFile.write("[General]\n")
0125         configFile.close()
0126 
0127     def mapKeyToConfig(self, key):
0128         if self.key_stage == 0:
0129             keyType = "ButtonLeft"
0130             self.key_stage = self.key_stage + 1
0131             self.keyStageChanged.emit()
0132         
0133         elif self.key_stage == 1:
0134             keyType = "ButtonRight"
0135             self.key_stage = self.key_stage + 1
0136             self.keyStageChanged.emit()
0137 
0138         elif self.key_stage == 2:
0139             keyType = "ButtonUp"
0140             self.key_stage = self.key_stage + 1
0141             self.keyStageChanged.emit()
0142 
0143         elif self.key_stage == 3:
0144             keyType = "ButtonDown"
0145             self.key_stage = self.key_stage + 1
0146             self.keyStageChanged.emit()
0147   
0148         elif self.key_stage == 4:
0149             keyType = "ButtonEnter"
0150             self.key_stage = self.key_stage + 1
0151             self.keyStageChanged.emit()
0152         
0153         elif self.key_stage == 5:
0154             keyType = "ButtonBack"
0155             self.key_stage = self.key_stage + 1
0156             self.keyStageChanged.emit()
0157 
0158         elif self.key_stage == 6:
0159             keyType = "ButtonHomepage"
0160             self.running = False
0161             self.setup_stage = 4
0162             self.setupStageChanged.emit()
0163             self.close_cec_thread()
0164 
0165         self.log.info("Mapping key {} to {}".format(key, keyType))
0166         
0167         configFile = open("/tmp/joyclickrc", "a")
0168         configFile.write("{}={}\n".format(keyType, key))
0169         configFile.close()
0170 
0171     @Signal
0172     def setupStageChanged(self):
0173         pass
0174 
0175     @Signal
0176     def keyStageChanged(self):
0177         pass