#!/usr/bin/env python # # Razer device QT configuration tool # # Copyright (C) 2007-2009 Michael Buesch # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. import sys from PyQt4.QtCore import * from PyQt4.QtGui import * from pyrazer import * class OneButtonConfig(QWidget): def __init__(self, id, name, supportedFunctions, buttonConfWidget): QWidget.__init__(self, buttonConfWidget) self.buttonConfWidget = buttonConfWidget self.id = id self.name = name self.setLayout(QHBoxLayout(self)) self.nameLabel = QLabel(name, self) self.layout().addWidget(self.nameLabel) self.layout().addStretch() l = QLabel(self.tr("button is assigned to function"), self) self.layout().addWidget(l) self.funcCombo = QComboBox(self) for func in supportedFunctions: self.funcCombo.addItem(func[1], QVariant(func[0])) curFunc = razer.getButtonFunction(buttonConfWidget.profileWidget.mouseWidget.mouse, buttonConfWidget.profileWidget.profileId, id) self.initialFunc = curFunc[0] index = self.funcCombo.findData(QVariant(curFunc[0])) if index >= 0: self.funcCombo.setCurrentIndex(index) self.layout().addWidget(self.funcCombo) def getId(self): return self.id def getSelectedFunction(self): index = self.funcCombo.currentIndex() return self.funcCombo.itemData(index).toUInt()[0] def getInitialFunction(self): return self.initialFunc class ButtonConfDialog(QDialog): def __init__(self, profileWidget): QDialog.__init__(self, profileWidget) self.profileWidget = profileWidget self.setWindowTitle(self.tr("Configure buttons")) self.setLayout(QVBoxLayout(self)) h = QHBoxLayout() l = QLabel(self.tr("Physical button"), self) h.addWidget(l) h.addStretch() l = QLabel(self.tr("Assigned function"), self) h.addWidget(l) self.layout().addLayout(h) funcs = razer.getSupportedButtonFunctions(profileWidget.mouseWidget.mouse) self.buttons = [] for b in razer.getSupportedButtons(profileWidget.mouseWidget.mouse): button = OneButtonConfig(b[0], b[1], funcs, self) self.layout().addWidget(button) self.buttons.append(button) h = QHBoxLayout() self.applyButton = QPushButton(self.tr("Apply"), self) self.connect(self.applyButton, SIGNAL("clicked()"), self.apply) h.addWidget(self.applyButton) self.cancelButton = QPushButton(self.tr("Cancel"), self) self.connect(self.cancelButton, SIGNAL("clicked()"), self.cancel) h.addWidget(self.cancelButton) self.layout().addLayout(h) def cancel(self): self.done(0) def apply(self): for button in self.buttons: func = button.getSelectedFunction() if func != button.getInitialFunction(): razer.setButtonFunction(self.profileWidget.mouseWidget.mouse, self.profileWidget.profileId, button.getId(), func) self.done(1) class LedCheckBox(QCheckBox): def __init__(self, ledsWidget, ledname, ledstate): text = ledname text += ledsWidget.tr(" LED enabled") QCheckBox.__init__(self, text, ledsWidget) self.ledsWidget = ledsWidget self.led = ledname if ledstate: self.setCheckState(Qt.Checked) else: self.setCheckState(Qt.Unchecked) self.connect(self, SIGNAL("stateChanged(int)"), self.toggled) def toggled(self, state): razer.setLed(self.ledsWidget.mouseWidget.mouse, self.led, bool(state)) class LedsWidget(QGroupBox): def __init__(self, mouseWidget): QGroupBox.__init__(self, "LEDs", mouseWidget) self.mouseWidget = mouseWidget self.setLayout(QVBoxLayout(self)) self.leds = [] def clear(self): for led in self.leds: led.deleteLater() self.leds = [] self.hide() def add(self, name, state): led = LedCheckBox(self, name, state) self.layout().addWidget(led) self.leds.append(led) class MouseProfileWidget(QWidget): def __init__(self, mouseWidget, profileId): QWidget.__init__(self, mouseWidget) self.mouseWidget = mouseWidget self.profileId = profileId self.recurseProtect = False self.setLayout(QGridLayout(self)) self.profileActive = QRadioButton(self.tr("Profile active"), self) self.connect(self.profileActive, SIGNAL("toggled(bool)"), self.activeChanged) self.layout().addWidget(self.profileActive, 0, 0) self.layout().addWidget(QLabel(self.tr("Mouse scan frequency:"), self), 1, 0) self.freqSel = QComboBox(self) self.connect(self.freqSel, SIGNAL("currentIndexChanged(int)"), self.freqChanged) self.layout().addWidget(self.freqSel, 1, 1) self.layout().addWidget(QLabel(self.tr("Mouse scan resolution:"), self), 2, 0) self.resSel = QComboBox(self) self.connect(self.resSel, SIGNAL("currentIndexChanged(int)"), self.resChanged) self.layout().addWidget(self.resSel, 2, 1) funcs = razer.getSupportedButtonFunctions(self.mouseWidget.mouse) if funcs: self.buttonConf = QPushButton(self.tr("Configure buttons"), self) self.connect(self.buttonConf, SIGNAL("clicked(bool)"), self.showButtonConf) self.layout().addWidget(self.buttonConf, 3, 0, 1, 2) def reload(self): # Refetch the data from the daemon self.recurseProtect = True self.freqSel.clear() supportedFreqs = razer.getSupportedFreqs(self.mouseWidget.mouse) curFreq = razer.getCurrentFreq(self.mouseWidget.mouse, self.profileId) self.freqSel.addItem(self.tr("Unknown Hz"), QVariant(0)) for freq in supportedFreqs: self.freqSel.addItem(self.tr("%u Hz" % freq), QVariant(freq)) index = self.freqSel.findData(QVariant(curFreq)) if index >= 0: self.freqSel.setCurrentIndex(index) self.resSel.clear() supportedMappings = razer.getSupportedDpiMappings(self.mouseWidget.mouse) curMapping = razer.getDpiMapping(self.mouseWidget.mouse, self.profileId) self.resSel.addItem(self.tr("Unknown mapping"), QVariant(0xFFFFFFFF)) for mapping in supportedMappings: id = mapping[0] res = mapping[1] if res: res = str(res) else: res = self.tr("Unknown") self.resSel.addItem(self.tr("Scan resolution %u (%s DPI)" % (id+1, res)), QVariant(id)) index = self.resSel.findData(QVariant(curMapping)) if index >= 0: self.resSel.setCurrentIndex(index) activeProf = razer.getActiveProfile(self.mouseWidget.mouse) self.profileActive.setChecked(activeProf == self.profileId) self.recurseProtect = False def activeChanged(self, checked): if self.recurseProtect: return if not checked: # Cannot disable self.recurseProtect = True self.profileActive.setChecked(1) self.recurseProtect = False return razer.setActiveProfile(self.mouseWidget.mouse, self.profileId) self.mouseWidget.reloadProfiles() def freqChanged(self, index): if self.recurseProtect or index <= 0: return freq = self.freqSel.itemData(index).toUInt()[0] razer.setFrequency(self.mouseWidget.mouse, self.profileId, freq) def resChanged(self, index): if self.recurseProtect or index <= 0: return res = self.resSel.itemData(index).toUInt()[0] razer.setDpiMapping(self.mouseWidget.mouse, self.profileId, res) def showButtonConf(self, checked): bconf = ButtonConfDialog(self) bconf.exec_() class OneDpiMapping(QWidget): def __init__(self, dpiMappingsWidget, id, resolution, isMutable): QWidget.__init__(self, dpiMappingsWidget) self.dpiMappingsWidget = dpiMappingsWidget self.mappingId = id self.setLayout(QHBoxLayout(self)) self.layout().addWidget(QLabel(self.tr("Scan resolution %u" % (id+1)), self)) supportedRes = razer.getSupportedRes(self.dpiMappingsWidget.mouseWidget.mouse) self.mappingSel = QComboBox(self) self.mappingSel.addItem(self.tr("Unknown DPI"), QVariant(0)) for res in supportedRes: self.mappingSel.addItem(self.tr("%u DPI" % res), QVariant(res)) index = self.mappingSel.findData(QVariant(resolution)) if index >= 0: self.mappingSel.setCurrentIndex(index) self.connect(self.mappingSel, SIGNAL("currentIndexChanged(int)"), self.changed) self.mappingSel.setEnabled(isMutable) self.layout().addWidget(self.mappingSel) def changed(self, index): if index <= 0: return resolution = self.mappingSel.itemData(index).toUInt()[0] razer.changeDpiMapping(self.dpiMappingsWidget.mouseWidget.mouse, self.mappingId, resolution) self.dpiMappingsWidget.mouseWidget.reloadProfiles() class MouseDpiMappingsWidget(QGroupBox): def __init__(self, mouseWidget): QGroupBox.__init__(self, mouseWidget.tr("Possible scan resolutions"), mouseWidget) self.mouseWidget = mouseWidget self.setLayout(QVBoxLayout(self)) self.mappings = [] def clear(self): for mapping in self.mappings: mapping.deleteLater() self.mappings = [] def add(self, id, resolution, isMutable): mapping = OneDpiMapping(self, id, resolution, isMutable) self.mappings.append(mapping) self.layout().addWidget(mapping) class MouseWidget(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.mainwnd = parent self.setLayout(QVBoxLayout(self)) self.mousesel = QComboBox(self) self.connect(self.mousesel, SIGNAL("currentIndexChanged(int)"), self.mouseChanged) self.layout().addWidget(self.mousesel) self.layout().addSpacing(15) self.profiletab = QTabWidget(self) self.layout().addWidget(self.profiletab) self.profileWidgets = [] self.dpimappings = MouseDpiMappingsWidget(self) self.layout().addWidget(self.dpimappings) self.leds = LedsWidget(self) self.layout().addWidget(self.leds) self.layout().addStretch() self.fwVer = QLabel(self) self.layout().addWidget(self.fwVer) def update(self, mice): self.mice = mice self.mousesel.clear() for mouse in mice: id = RazerDevId(mouse) self.mousesel.addItem("%s %s-%s %s" % \ (id.getDevName(), id.getBusType(), id.getBusPosition(), id.getDevId())) def mouseChanged(self, index): self.profiletab.clear() self.profileWidgets = [] self.dpimappings.clear() self.leds.clear() self.profiletab.setEnabled(index > -1) self.dpimappings.setEnabled(index > -1) self.leds.setEnabled(index > -1) if index == -1: self.fwVer.clear() return self.mouse = self.mice[index] profileIds = razer.getProfiles(self.mouse) activeProfileId = razer.getActiveProfile(self.mouse) activeWidget = None for profileId in profileIds: widget = MouseProfileWidget(self, profileId) if profileId == activeProfileId: activeWidget = widget self.profiletab.addTab(widget, str(profileId + 1)) self.profileWidgets.append(widget) self.reloadProfiles() if activeWidget: self.profiletab.setCurrentWidget(activeWidget) dpimappings = razer.getSupportedDpiMappings(self.mouse) for dpimapping in dpimappings: id = dpimapping[0] resolution = dpimapping[1] isMutable = dpimapping[2] self.dpimappings.add(id, resolution, isMutable) leds = razer.getLeds(self.mouse) for led in leds: name = led[0] state = led[1] self.leds.add(name, state) self.leds.show() ver = razer.getFwVer(self.mouse) if ver[0] == 0xFF and ver[1] == 0xFF: self.fwVer.hide() else: self.fwVer.setText(self.tr("Firmware version: %u.%u" % (ver[0], ver[1]))) self.fwVer.show() def reloadProfiles(self): for prof in self.profileWidgets: prof.reload() activeProf = razer.getActiveProfile(self.mouse) for i in range(0, self.profiletab.count()): id = self.profiletab.widget(i).profileId name = "Profile " + str(id + 1) if activeProf == id: name = ">" + name + "<" self.profiletab.setTabText(i, name) class StatusBar(QStatusBar): def showMessage(self, msg): QStatusBar.showMessage(self, msg, 10000) class MainWindow(QMainWindow): def __init__(self, parent=None): QMainWindow.__init__(self, parent) self.setWindowTitle(self.tr("Razer device configuration")) mb = QMenuBar(self) rzrmen = QMenu(self.tr("Razer"), mb) rzrmen.addAction(self.tr("Rescan devices"), self.scan) rzrmen.addSeparator() rzrmen.addAction(self.tr("Exit"), self.close) mb.addMenu(rzrmen) helpmen = QMenu(self.tr("Help"), mb) helpmen.addAction(self.tr("About"), self.about) mb.addMenu(helpmen) self.setMenuBar(mb) tab = QTabWidget(self) self.mousewidget = MouseWidget(self) tab.addTab(self.mousewidget, self.tr("Mice")) self.setCentralWidget(tab) self.setStatusBar(StatusBar()) self.mice = [] self.scan() self.pokeNotificationTimer() self.resize(450, 350) def pokeNotificationTimer(self): QTimer.singleShot(300, self.pollNotifications) def pollNotifications(self): n = razer.pollNotifications() if n: self.scan() self.pokeNotificationTimer() # Rescan for new devices def scan(self): razer.rescanMice() mice = razer.getMice() if len(mice) != len(self.mice): if (len(mice) == 1): self.statusBar().showMessage(self.tr("Found one Razer mouse")) elif (len(mice) > 1): self.statusBar().showMessage(self.tr("Found %d Razer mice" % len(mice))) self.mice = mice self.mousewidget.update(mice) def about(self): QMessageBox.information(self, self.tr("About"), self.tr("Razer device configuration tool\n" "Version %s\n" "Copyright (c) 2007-2009 Michael Buesch" % RAZER_VERSION)) def exit(exitcode): sys.exit(exitcode) def main(): try: global razer razer = Razer(enableNotifications=True) except RazerEx, e: print e print "Is razerd running?" sys.exit(1) app = QApplication(sys.argv) mainwnd = MainWindow() mainwnd.show() return app.exec_() if __name__ == "__main__": exit(main())