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