class MainWnd(QWidget): def __init__(self, p_parent=None): super().__init__(p_parent) self.ui = Ui_MainWidget() self.ui.setupUi(self) self.m_profileExecutor = ProfileExecutor() self.ui.profileCbx.currentIndexChanged.connect(self.slotProfileChanged) self.ui.addBut.clicked.connect(self.slotAddNewProfile) self.ui.editBut.clicked.connect(self.slotEditProfile) self.ui.removeBut.clicked.connect(self.slotRemoveProfile) self.ui.listeningChk.stateChanged.connect(self.slotListeningEnabled) self.ui.ok.clicked.connect(self.slotOK) self.ui.cancel.clicked.connect(self.slotCancel) signal.signal(signal.SIGINT, signal.SIG_DFL) if self.loadFromDatabase() > 0: # if self.loadTestProfiles() > 0: w_jsonProfile = self.ui.profileCbx.itemData(0) if w_jsonProfile != None: self.m_activeProfile = json.loads(w_jsonProfile) self.m_profileExecutor.setProfile(self.m_activeProfile) self.m_profileExecutor.start() def saveToDatabase(self): w_profiles = [] w_profileCnt = self.ui.profileCbx.count() for w_idx in range(w_profileCnt): w_jsonProfile = self.ui.profileCbx.itemData(w_idx) if w_jsonProfile == None: continue w_profile = json.loads(w_jsonProfile) w_profiles.append(w_profile) with open(self.getSettingsPath("profiles.dat"), "wb") as f: pickle.dump(w_profiles, f, pickle.HIGHEST_PROTOCOL) def loadFromDatabase(self): w_profiles = [] with open(self.getSettingsPath("profiles.dat"), "rb") as f: w_profiles = pickle.load(f) for w_profile in w_profiles: self.ui.profileCbx.addItem(w_profile['name']) w_jsonProfile = json.dumps(w_profile) self.ui.profileCbx.setItemData(self.ui.profileCbx.count() - 1, w_jsonProfile) return len(w_profiles) def getSettingsPath(self, setting): home = os.path.expanduser("~") + '/.linvam/' if not os.path.exists(home): os.mkdir(home) if not os.path.exists(home + setting): shutil.copyfile(setting, home + setting) return home + setting def loadTestProfiles(self): w_carProfileDict = { "name": "car game", "commands": [{ 'name': 'forward', 'actions': [{ 'name': 'key action', 'key': 'up', 'type': 1 }], 'repeat': 1, 'async': False, 'threshold': 12 }, { 'name': 'back', 'actions': [{ 'name': 'key action', 'key': 'down', 'type': 1 }], 'repeat': 1, 'async': False, 'threshold': 3 }, { 'name': 'left', 'actions': [ { 'name': 'key action', 'key': 'right', 'type': 0 }, { 'name': 'key action', 'key': 'left', 'type': 1 }, ], 'repeat': 1, 'async': False, 'threshold': 10 }, { 'name': 'right', 'actions': [ { 'name': 'key action', 'key': 'left', 'type': 0 }, { 'name': 'key action', 'key': 'right', 'type': 1 }, ], 'repeat': 1, 'async': False, 'threshold': 3 }, { 'name': 'stop', 'actions': [{ 'name': 'key action', 'key': 'left', 'type': 0 }, { 'name': 'key action', 'key': 'right', 'type': 0 }, { 'name': 'key action', 'key': 'up', 'type': 0 }, { 'name': 'key action', 'key': 'down', 'type': 0 }], 'repeat': 1, 'async': False, 'threshold': 8 }] } w_airplaneProfileDict = { "name": "airplane game", "commands": [{ 'name': 'up', 'actions': [{ 'name': 'command stop action', 'command name': 'down' }, { 'name': 'mouse move action', 'x': 0, 'y': -5, 'absolute': False }, { 'name': 'pause action', 'time': 0.01 }], 'repeat': -1, 'async': True, 'threshold': 3 }, { 'name': 'left', 'actions': [{ 'name': 'command stop action', 'command name': 'right' }, { 'name': 'mouse move action', 'x': -5, 'y': 0, 'absolute': False }, { 'name': 'pause action', 'time': 0.005 }], 'repeat': -1, 'async': True, 'threshold': 3 }, { 'name': 'right', 'actions': [{ 'name': 'command stop action', 'command name': 'left' }, { 'name': 'mouse move action', 'x': 5, 'y': 0, 'absolute': False }, { 'name': 'pause action', 'time': 0.005 }], 'repeat': -1, 'async': True, 'threshold': 3 }, { 'name': 'down', 'actions': [{ 'name': 'command stop action', 'command name': 'up' }, { 'name': 'mouse move action', 'x': 0, 'y': 5, 'absolute': False }, { 'name': 'pause action', 'time': 0.005 }], 'repeat': -1, 'async': True, 'threshold': 3 }, { 'name': 'shoot', 'actions': [{ 'name': 'mouse click action', 'button': 'left', 'type': 1 }, { 'name': 'pause action', 'time': 0.03 }], 'repeat': 1, 'async': False, 'threshold': 3 }, { 'name': 'stop', 'actions': [{ 'name': 'command stop action', 'command name': 'up' }, { 'name': 'command stop action', 'command name': 'left' }, { 'name': 'command stop action', 'command name': 'right' }, { 'name': 'command stop action', 'command name': 'down' }, { 'name': 'mouse click action', 'button': 'left', 'type': 0 }], 'repeat': 1, 'async': False, 'threshold': 3 }] } w_profiles = [] w_profiles.append(w_carProfileDict) w_profiles.append(w_airplaneProfileDict) i = 0 for w_profile in w_profiles: self.ui.profileCbx.addItem(w_profile['name']) w_jsonProfile = json.dumps(w_profile) self.ui.profileCbx.setItemData(i, w_jsonProfile) i = i + 1 return i def slotProfileChanged(self, p_idx): w_jsonProfile = self.ui.profileCbx.itemData(p_idx) if w_jsonProfile != None: self.m_activeProfile = json.loads(w_jsonProfile) self.m_profileExecutor.setProfile(self.m_activeProfile) def slotAddNewProfile(self): w_profileEditWnd = ProfileEditWnd(None, self) if w_profileEditWnd.exec() == QDialog.Accepted: w_profile = w_profileEditWnd.m_profile self.m_profileExecutor.setProfile(w_profile) self.ui.profileCbx.addItem(w_profile['name']) w_jsonProfile = json.dumps(w_profile) self.ui.profileCbx.setItemData(self.ui.profileCbx.count() - 1, w_jsonProfile) def slotEditProfile(self): w_idx = self.ui.profileCbx.currentIndex() w_jsonProfile = self.ui.profileCbx.itemData(w_idx) w_profile = json.loads(w_jsonProfile) w_profileEditWnd = ProfileEditWnd(w_profile, self) if w_profileEditWnd.exec() == QDialog.Accepted: w_profile = w_profileEditWnd.m_profile self.m_profileExecutor.setProfile(w_profile) self.ui.profileCbx.setItemText(w_idx, w_profile['name']) w_jsonProfile = json.dumps(w_profile) self.ui.profileCbx.setItemData(w_idx, w_jsonProfile) def slotRemoveProfile(self): w_curIdx = self.ui.profileCbx.currentIndex() if w_curIdx >= 0: self.ui.profileCbx.removeItem(w_curIdx) w_curIdx = self.ui.profileCbx.currentIndex() if w_curIdx >= 0: w_jsonProfile = self.ui.profileCbx.itemData(w_curIdx) w_profile = json.loads(w_jsonProfile) self.m_profileExecutor.setProfile(w_profile) def slotListeningEnabled(self, p_enabled): if p_enabled: self.m_profileExecutor.setEnableListening(True) else: self.m_profileExecutor.setEnableListening(False) def slotOK(self): self.saveToDatabase() self.m_profileExecutor.stop() self.close() def slotCancel(self): self.m_profileExecutor.stop() self.close() exit()
class MainWnd(QWidget): def __init__(self, p_parent = None): super().__init__(p_parent) self.ui = Ui_MainWidget() self.ui.setupUi(self) self.handleArgs() self.m_sound = SoundFiles() self.m_profileExecutor = ProfileExecutor(None, self) if not os.geteuid() == 0 and not self.m_config['noroot'] == 1: print("\033[93m\nWARNING: no root privileges, unable to send key strokes to the system.\nConsider running this as root.\nFor that you might need to install some python modules for the root user. \n\033[0m") self.ui.profileCbx.currentIndexChanged.connect(self.slotProfileChanged) self.ui.addBut.clicked.connect(self.slotAddNewProfile) self.ui.editBut.clicked.connect(self.slotEditProfile) self.ui.copyBut.clicked.connect(self.slotCopyProfile) self.ui.removeBut.clicked.connect(self.slotRemoveProfile) self.ui.listeningChk.stateChanged.connect(self.slotListeningEnabled) self.ui.ok.clicked.connect(self.slotOK) self.ui.cancel.clicked.connect(self.slotCancel) self.ui.sliderVolume.valueChanged.connect(lambda: self.m_sound.setVolume(self.ui.sliderVolume.value())) signal.signal(signal.SIGINT, signal.SIG_DFL) if self.loadFromDatabase() > 0 : # if self.loadTestProfiles() > 0: w_jsonProfile = self.ui.profileCbx.itemData(0) if w_jsonProfile != None: self.m_activeProfile = json.loads(w_jsonProfile) self.m_profileExecutor.setProfile(self.m_activeProfile) #self.m_profileExecutor.start() def saveToDatabase(self): w_profiles = [] w_profileCnt = self.ui.profileCbx.count() for w_idx in range(w_profileCnt): w_jsonProfile = self.ui.profileCbx.itemData(w_idx) if w_jsonProfile == None: continue w_profile = json.loads(w_jsonProfile) w_profiles.append(w_profile) with open(self.getSettingsPath("profiles.dat"), "wb") as f: pickle.dump(w_profiles, f, pickle.HIGHEST_PROTOCOL) def loadFromDatabase(self): w_profiles = [] with open(self.getSettingsPath("profiles.dat"), "rb") as f: w_profiles = pickle.load(f) for w_profile in w_profiles: self.ui.profileCbx.addItem(w_profile['name']) w_jsonProfile = json.dumps(w_profile) self.ui.profileCbx.setItemData(self.ui.profileCbx.count() - 1, w_jsonProfile) return len(w_profiles) def getSettingsPath(self, setting): home = os.path.expanduser("~") + '/.linvam/' if not os.path.exists(home): os.mkdir(home) if not os.path.exists(home + setting): shutil.copyfile(setting, home + setting) return home + setting def loadTestProfiles(self): w_carProfileDict = { "name": "car game", "commands": [ {'name': 'forward', 'actions': [ {'name': 'key action', 'key': 'up', 'type': 1} ], 'repeat': 1, 'async': False, 'threshold': 12 }, {'name': 'back', 'actions': [ {'name': 'key action', 'key': 'down', 'type': 1} ], 'repeat': 1, 'async': False, 'threshold': 3 }, {'name': 'left', 'actions': [{'name': 'key action', 'key': 'right', 'type': 0}, {'name': 'key action', 'key': 'left', 'type': 1}, ], 'repeat': 1, 'async': False, 'threshold': 10 }, {'name': 'right', 'actions': [{'name': 'key action', 'key': 'left', 'type': 0}, {'name': 'key action', 'key': 'right', 'type': 1}, ], 'repeat': 1, 'async': False, 'threshold': 3 }, {'name': 'stop', 'actions': [ {'name': 'key action', 'key': 'left', 'type': 0}, {'name': 'key action', 'key': 'right', 'type': 0}, {'name': 'key action', 'key': 'up', 'type': 0}, {'name': 'key action', 'key': 'down', 'type': 0} ], 'repeat': 1, 'async': False, 'threshold': 8 } ] } w_airplaneProfileDict = { "name": "airplane game", "commands": [ {'name': 'up', 'actions': [ {'name': 'command stop action', 'command name': 'down'}, {'name': 'mouse move action', 'x': 0, 'y': -5, 'absolute': False}, {'name': 'pause action', 'time': 0.01} ], 'repeat': -1, 'async': True, 'threshold': 3 }, {'name': 'left', 'actions': [ {'name': 'command stop action', 'command name': 'right'}, {'name': 'mouse move action', 'x': -5, 'y': 0, 'absolute': False}, {'name': 'pause action', 'time': 0.005} ], 'repeat': -1, 'async': True, 'threshold': 3 }, {'name': 'right', 'actions': [ {'name': 'command stop action', 'command name': 'left'}, {'name': 'mouse move action', 'x': 5, 'y': 0, 'absolute': False}, {'name': 'pause action', 'time': 0.005} ], 'repeat': -1, 'async': True, 'threshold': 3 }, {'name': 'down', 'actions': [ {'name': 'command stop action', 'command name': 'up'}, {'name': 'mouse move action', 'x': 0, 'y': 5, 'absolute': False}, {'name': 'pause action', 'time': 0.005} ], 'repeat': -1, 'async': True, 'threshold': 3 }, {'name': 'shoot', 'actions': [ {'name': 'mouse click action', 'button': 'left', 'type': 1}, {'name': 'pause action', 'time': 0.03} ], 'repeat': 1, 'async': False, 'threshold': 3 }, {'name': 'stop', 'actions': [ {'name': 'command stop action', 'command name': 'up'}, {'name': 'command stop action', 'command name': 'left'}, {'name': 'command stop action', 'command name': 'right'}, {'name': 'command stop action', 'command name': 'down'}, {'name': 'mouse click action', 'button': 'left', 'type': 0} ], 'repeat': 1, 'async': False, 'threshold': 3 } ] } w_profiles = [] w_profiles.append(w_carProfileDict) w_profiles.append(w_airplaneProfileDict) i = 0 for w_profile in w_profiles: self.ui.profileCbx.addItem(w_profile['name']) w_jsonProfile = json.dumps(w_profile) self.ui.profileCbx.setItemData(i, w_jsonProfile) i = i + 1 return i def slotProfileChanged(self, p_idx): w_jsonProfile = self.ui.profileCbx.itemData(p_idx) if w_jsonProfile != None: self.m_activeProfile = json.loads(w_jsonProfile) self.m_profileExecutor.setProfile(self.m_activeProfile) def slotAddNewProfile(self): w_profileEditWnd = ProfileEditWnd(None, self) if w_profileEditWnd.exec() == QDialog.Accepted: w_profile = w_profileEditWnd.m_profile self.m_profileExecutor.setProfile(w_profile) self.ui.profileCbx.addItem(w_profile['name']) w_jsonProfile = json.dumps(w_profile) self.ui.profileCbx.setItemData(self.ui.profileCbx.count()-1, w_jsonProfile) def slotEditProfile(self): w_idx = self.ui.profileCbx.currentIndex() w_jsonProfile = self.ui.profileCbx.itemData(w_idx) w_profile = json.loads(w_jsonProfile) w_profileEditWnd = ProfileEditWnd(w_profile, self) if w_profileEditWnd.exec() == QDialog.Accepted: w_profile = w_profileEditWnd.m_profile self.m_profileExecutor.setProfile(w_profile) self.ui.profileCbx.setItemText(w_idx, w_profile['name']) w_jsonProfile = json.dumps(w_profile) self.ui.profileCbx.setItemData(w_idx, w_jsonProfile) def slotCopyProfile(self): text, okPressed = QInputDialog.getText(self, "Copy profile", "Enter new profile name:", QLineEdit.Normal, "") if okPressed and text != '': # todo: check if name not already in use w_idx = self.ui.profileCbx.currentIndex() w_jsonProfile = self.ui.profileCbx.itemData(w_idx) w_profile = json.loads(w_jsonProfile) w_profile_copy = w_profile w_profile_copy['name'] = text self.ui.profileCbx.addItem(w_profile_copy['name']) w_jsonProfile = json.dumps(w_profile_copy) self.ui.profileCbx.setItemData(self.ui.profileCbx.count()-1, w_jsonProfile) def slotRemoveProfile(self): buttonReply = QMessageBox.question(self, 'Remove Profile', "Do you really want to delete this profile?", QMessageBox.No | QMessageBox.Yes, QMessageBox.No) if buttonReply == QMessageBox.No: return w_curIdx = self.ui.profileCbx.currentIndex() if w_curIdx >= 0: self.ui.profileCbx.removeItem(w_curIdx) w_curIdx = self.ui.profileCbx.currentIndex() if w_curIdx >= 0: w_jsonProfile = self.ui.profileCbx.itemData(w_curIdx) w_profile = json.loads(w_jsonProfile) self.m_profileExecutor.setProfile(w_profile) def slotListeningEnabled(self, p_enabled): if p_enabled: self.m_profileExecutor.setEnableListening(True) else: self.m_profileExecutor.setEnableListening(False) def slotOK(self): self.saveToDatabase() self.m_profileExecutor.shutdown() self.close() def slotCancel(self): self.m_profileExecutor.shutdown() self.close() exit() def handleArgs(self): self.m_config = { 'noroot' : 0, 'xdowindowid' : None } if len(sys.argv) == 1: return for i in range(1,len(sys.argv)): if sys.argv[i] == '-noroot': self.m_config['noroot'] = 1 elif sys.argv[i] == '-xdowindowid' and (i+1 < len(sys.argv)): self.m_config['xdowindowid'] = sys.argv[i+1] i = i+1 # try to help: if -noroot is supplied, but no xdowindowid, try to determine the id # Elite Dangerous only try: args = shlex.split('xdotool search --name "\(CLIENT\)"') window_id = str(subprocess.check_output(args)) window_id = window_id.replace('b\'', '') window_id = window_id.replace('\\n\'','') except subprocess.CalledProcessError: window_id = None pass if not window_id == None: # check if it's really the Client we want try: window_name = subprocess.check_output(['xdotool', 'getwindowname', str(window_id)]) except subprocess.CalledProcessError: window_name = None pass if not window_name == None: if not str(window_name).find('Elite - Dangerous') == -1: print("Window ID: ", str(window_id), ", window name: ", window_name) print("Auto-detected window id of ED Client: ", window_id) self.m_config['xdowindowid'] = window_id