Esempio n. 1
0
class AutoClicker(QtGui.QMainWindow, Ui_AutoClicker_Window):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self, parent)

        self.setupUi(self)

        # redirect stdout
        sys.stdout = EmittingStream(textWritten=self.normalOutputWritten)        

        # member variables
        self.title = "Mouse Autoclicker v.1.1"
        self.selectedRow  = -1
        self.selectedCol  = -1
        self.recording    = False
        self.picking      = False
        self.hotkeychange = False
        self.savePending  = False
        self.timer        = QtCore.QTimer()

        #Hotkey options
        self.ctrlModifier  = True
        self.altModifier   = False
        self.shiftModifier = False
        self.hotkey        = 'S'

        # create the hook mananger, register callbacks and hook to mouse and keyboard events
        hm = pyHook.HookManager()
        hm.MouseAllButtonsDown = self.OnMouseEvent
        hm.MouseAllButtonsUp = self.OnMouseEvent
        hm.KeyDown = self.OnKeyboardPressEvent
        hm.KeyUp = self.OnKeyboardReleaseEvent
        hm.HookKeyboard()
        hm.HookMouse()
        self.ctrlPressed = False
        self.altPressed = False
        self.shiftPressed = False

        # connect signals / slots of UI controls
        self.btnAdd.clicked.connect(self.buttonAddPressed)
        self.btnLoad.clicked.connect(self.buttonLoadPressed)
        self.btnPick.clicked.connect(self.buttonPickPressed)
        self.btnSave.clicked.connect(self.buttonSavePressed)
        self.btnClear.clicked.connect(self.buttonClearPressed)
        self.btnDelete.clicked.connect(self.buttonDeletePressed)
        self.btnMoveUp.clicked.connect(self.buttonMoveUpPressed)
        self.btnRecord.clicked.connect(self.buttonRecordPressed)
        self.btnUpdate.clicked.connect(self.buttonUpdatePressed)
        self.btnMoveDown.clicked.connect(self.buttonMoveDownPressed)
        self.actionAbout.triggered.connect(self.aboutActionTriggered)
        self.btnStartStopSequence.clicked.connect(self.buttonStartStopPressed)
        self.table.itemClicked.connect(self.cellClicked)
        self.timer.timeout.connect(self.updateMouseCoordstoStatusBar)

        self.btnHotkey.clicked.connect(self.hotkeyChangeRequested)

        self.thread = WorkThread()
        self.thread.finished.connect(self.updateUI)
        self.thread.terminated.connect(self.updateUI)
        self.connect(self.thread, QtCore.SIGNAL("output(int)"), self.highlightRow)

        self.updateHotkeyButton()
        
        self.timer.start(100)

    def __del__(self):
        sys.stdout = sys.__stdout__

    #Triggered by pyhook library
    def OnMouseEvent(self, event):
        if self.picking == True:
            self.picking = False
            self.txtXcoord.setText(str(event.Position[0]))
            self.txtYcoord.setText(str(event.Position[1]))

            if event.Message == 513:
                self.cmbClickType.setCurrentIndex(1)
            elif event.Message == 519:
                self.cmbClickType.setCurrentIndex(2)
            elif event.Message == 516:
                self.cmbClickType.setCurrentIndex(3)

            self.setWindowState(QtCore.Qt.WindowActive)
            return False
        if self.recording == True:
            xcoord = event.Position[0]
            ycoord = event.Position[1]
            delay  = self.spinDelay.value()
            click  = 0

            if event.Message == 513:
                click = 1
            elif event.Message == 519:
                click = 2
            elif event.Message == 516:
                click = 3
            if click != 0:
                self.addTableEntry(click, xcoord, ycoord, delay, 1)

        return True   

    def OnKeyboardPressEvent(self, event):
        #Update modifier key status
        if event.Key == "Lcontrol" or event.Key == "Rcontrol":
            self.ctrlPressed = True
        if event.Key == "Lmenu" or event.Key == "Rmenu":
            self.altPressed = True
        if event.Key == "Lshift" or event.Key == "Rshift":
            self.shiftPressed = True

        #Check if mathching hotkey was pressed
        if self.ctrlModifier == True and self.ctrlPressed == False:
            return True
        if self.altModifier == True and self.altPressed == False:
            return True
        if self.shiftModifier == True and self.shiftPressed == False:
            return True
        if event.Key.upper() != self.hotkey.upper():
            return True

        #Hotkey matched. Do proper actions
        if self.recording == True:
            self.stopRecording()
        if self.thread.isRunning() == True:
            self.thread.stopclicking()
            win32api.SetCursorPos((self.x() + self.width() / 2, self.y() + self.height() / 2))   

        return True

    def OnKeyboardReleaseEvent(self, event):
        if event.Key == "Lcontrol" or event.Key == "Rcontrol":
            self.ctrlPressed = False
        if event.Key == "Lmenu" or event.Key == "Rmenu":
            self.altPressed = False
        if event.Key == "Lshift" or event.Key == "Rshift":
            self.shiftPressed = False
        return True

    def normalOutputWritten(self, text):       
        if len(text) == 1 and ord(str(text)) == 10:
            return
        self.statusBar.showMessage(text, 0)

    def updateHotkeyButton(self):
        hotkeytext = ""
        if self.ctrlModifier == True:
            hotkeytext += "CTRL+"
        if self.altModifier == True:
            hotkeytext += "ALT+"
        if self.shiftModifier == True:
            hotkeytext += "SHIFT+"
        hotkeytext += self.hotkey

        self.btnHotkey.setText(hotkeytext)

    def highlightRow(self, index):
        self.table.selectRow(index)

    def updateMouseCoordstoStatusBar(self):
        pos = QPoint(QCursor.pos())
        print "Mouse Position: (%d, %d)" % (pos.x(), pos.y())

    def hotkeyChangeRequested(self):
        dialog = HotKey.HotKeyDialog()
        dialog.setHotkey([self.ctrlModifier, self.altModifier, self.shiftModifier, self.hotkey])
        if dialog.exec_():
            result = dialog.getHotKey()
            self.ctrlModifier  = result[0]
            self.altModifier   = result[1]
            self.shiftModifier = result[2]
            self.hotkey        = result[3]
            self.updateHotkeyButton()

    def aboutActionTriggered(self):
        dialog = QDialog()
        dialog.ui = Ui_About()
        dialog.ui.setupUi(dialog)
        dialog.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        dialog.exec_()

    def buttonPickPressed(self):
        self.setWindowState(QtCore.Qt.WindowMinimized)
        self.picking = True

    def buttonAddPressed(self):
        try:
            xcoord = int(self.txtXcoord.text())
            ycoord = int(self.txtYcoord.text())
            repeat = self.spinRepeat.value()
            duration = self.spinDelay.value()
            click = self.cmbClickType.currentIndex()

            if click == 0:
                raise InvalidComboBoxValue

            self.addTableEntry(click, xcoord, ycoord, duration, repeat)

            #Reset fields
            self.txtXcoord.setText("0")
            self.txtYcoord.setText("0")
            self.spinDelay.setValue(500)
            self.spinRepeat.setValue(1)
            self.cmbClickType.setCurrentIndex(0)

            self.btnStartStopSequence.setEnabled(True)
            self.btnClear.setEnabled(True)
            self.btnMoveDown.setEnabled(False)
            self.btnMoveUp.setEnabled(False)
            self.btnDelete.setEnabled(False)

            self.savePending = True
        except ValueError:
            QtGui.QMessageBox.question(self, 'Error', "Invalid values given. Please check your parameters.", QtGui.QMessageBox.Ok, QtGui.QMessageBox.Ok)
            return
        except InvalidComboBoxValue:
            QtGui.QMessageBox.question(self, 'Error', "Please choose a click type.", QtGui.QMessageBox.Ok, QtGui.QMessageBox.Ok)
            return

    def buttonUpdatePressed(self):
        if self.selectedRow != -1 and self.selectedCol != -1:
            repeat = self.spinRepeat.value()
            duration = self.spinDelay.value()
            xcoord = int(self.txtXcoord.text())
            ycoord = int(self.txtYcoord.text())
            click = self.cmbClickType.currentIndex()

            self.updateTableEntry(self.selectedRow, click, xcoord, ycoord, duration, repeat)
            self.selectedRow = -1
            self.selectedCol = -1
            self.btnMoveDown.setEnabled(False)
            self.btnMoveUp.setEnabled(False)
            self.btnDelete.setEnabled(False)

    def buttonLoadPressed(self):
        filename = QtGui.QFileDialog.getOpenFileName(self, "Load Autoclick Sequence", "", "Sequence files (*.seq)", "Sequence files (*.seq)")
        if filename == "":
            return
        if self.savePending == True or self.table.rowCount() != 0:
            if self.confirm("About to clear the current sequence. Are you sure?") == True:
                self.clearTable()
            else:
                return

        self.load(filename)
        self.enableUI()

    def buttonSavePressed(self):
        filename = QtGui.QFileDialog.getSaveFileName(self, "Save sequence", "", "Sequence files (*.seq)", "Sequence files (*.seq)")

        if filename == "":
            return
        else:
            self.save(filename)

    def buttonRecordPressed(self):
        if "Record Sequence" in self.btnRecord.text():
            self.startRecording()
        else:
            self.table.removeRow(self.table.rowCount() - 1)
            self.stopRecording()

    def startRecording(self):
        if self.savePending == True or self.table.rowCount() != 0:
            if self.confirm("About to clear the current sequence. Are you sure?") == True:
                self.clearTable()
            else:
                return

        self.disableUI()
        self.btnRecord.setText("Stop Recording")
        self.btnRecord.setEnabled(True)

        self.recording = True
        self.savePending = True
        self.setWindowState(QtCore.Qt.WindowMinimized)
        self.setWindowTitle("Press F12 to stop")

    def stopRecording(self):
        self.enableUI()
        self.setWindowState(QtCore.Qt.WindowActive)
        self.setWindowTitle(self.title)
        self.btnRecord.setText("Record Sequence")

        self.btnMoveDown.setEnabled(False)
        self.btnMoveUp.setEnabled(False)
        self.btnDelete.setEnabled(False)

        if self.table.rowCount() == 0:
            self.savePending = False
            self.btnStartStopSequence.setEnabled(False)

        self.recording = False

    def buttonStartStopPressed(self):
        if "Start" in self.btnStartStopSequence.text():
            self.disableUI()
            self.table.selectRow(0)
            self.btnStartStopSequence.setText("Stop")
            self.btnStartStopSequence.setEnabled(True)
            self.setWindowState(QtCore.Qt.WindowMinimized)
            self.setWindowTitle("Press F12 to stop")
            self.thread.startclicking(self.tableToList(), self.spinRerun.value(), self.spinRerunDelay.value())
        else:
            self.thread.stopclicking()

    def buttonMoveUpPressed(self):
        row = self.table.currentRow()

        if row != 0:
            self.table.insertRow(row - 1)
            for i in range(self.table.columnCount()):
                self.table.setItem(row - 1, i, self.table.takeItem(row + 1, i))
            self.table.removeRow(row + 1)
            self.table.setCurrentCell(row - 1, 0)
            self.table.selectRow(self.table.currentRow())

    def buttonMoveDownPressed(self):
        row = self.table.currentRow()

        if row != self.table.rowCount() - 1:
            self.table.insertRow(row + 2)
            for i in range(self.table.columnCount()):
                self.table.setItem(row + 2, i, self.table.takeItem(row, i))
            self.table.removeRow(row)
            self.table.setCurrentCell(row + 1, 0)
            self.table.selectRow(self.table.currentRow())

    def buttonDeletePressed(self):
        self.table.removeRow(self.table.currentRow())

        if self.table.rowCount() == 0:
            self.btnStartStopSequence.setEnabled(False)
            self.btnMoveDown.setEnabled(False)
            self.btnMoveUp.setEnabled(False)
            self.btnDelete.setEnabled(False)
            self.btnClear.setEnabled(False)
            self.savePending = False

    def buttonClearPressed(self):
        if self.confirm("About to clear the current sequence. Are you sure?") == True:
            self.clearTable()
            self.savePending = False
        else:
            return

    def cellClicked(self, item):
        self.selectedRow = item.row()
        self.selectedCol = item.column()

        clicktype = self.table.item(self.selectedRow, 0).text()
        xcoord    = self.table.item(self.selectedRow, 1).text()
        ycoord    = self.table.item(self.selectedRow, 2).text()
        duration  = int(self.table.item(self.selectedRow, 3).text())
        repeat    = int(self.table.item(self.selectedRow, 4).text())

        self.txtXcoord.setText(xcoord)
        self.txtYcoord.setText(ycoord)
        self.spinDelay.setValue(duration)
        self.spinRepeat.setValue(repeat)

        self.btnMoveDown.setEnabled(True)
        self.btnMoveUp.setEnabled(True)
        self.btnDelete.setEnabled(True)

        if clicktype == "Left Click":
            self.cmbClickType.setCurrentIndex(1)
        elif clicktype == "Middle Click":
            self.cmbClickType.setCurrentIndex(2)
        else:
            self.cmbClickType.setCurrentIndex(3)

    def clearTable(self):
        while self.table.rowCount() > 0:
            self.table.removeRow(0)

        self.btnStartStopSequence.setEnabled(False)
        self.btnMoveUp.setEnabled(False)
        self.btnMoveDown.setEnabled(False)
        self.btnDelete.setEnabled(False)
        self.btnClear.setEnabled(False)

    def tableToList(self):
        list = []

        for i in range(self.table.rowCount()):
            templist = []
            for j in range(self.table.columnCount()):
                templist.append(str(self.table.item(i, j).text()))
            list.append(templist)

        return list

    def listToTable(self, list):
        for i in range(len(list[0])):
            self.table.insertRow(i)
            for j in range(len(list[0][i])):
                self.table.setItem(i , j, QtGui.QTableWidgetItem(str(list[0][i][j])))
                self.table.item(i, j).setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter | QtCore.Qt.AlignCenter)

    def updateTableEntry(self, row, click, xcoord, ycoord, duration, repeat):
        clicktype = self.clickTypetoAscii(click)
        self.insertRow(row, clicktype, xcoord, ycoord, duration, repeat)

    def addTableEntry(self, click, xcoord, ycoord, duration, repeat):
        clicktype = self.clickTypetoAscii(click)
        row = self.table.rowCount()
        self.table.insertRow(row)
        self.insertRow(row, clicktype, xcoord, ycoord, duration, repeat)

    def insertRow(self, row, clicktype, xcoord, ycoord, duration, repeat):
        self.table.setItem(row , 1, QtGui.QTableWidgetItem(str(xcoord)))
        self.table.setItem(row , 2, QtGui.QTableWidgetItem(str(ycoord)))
        self.table.setItem(row , 4, QtGui.QTableWidgetItem(str(repeat)))
        self.table.setItem(row , 3, QtGui.QTableWidgetItem(str(duration)))
        self.table.setItem(row , 0, QtGui.QTableWidgetItem(str(clicktype)))
        self.table.item(row, 0).setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter | QtCore.Qt.AlignCenter)
        self.table.item(row, 1).setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter | QtCore.Qt.AlignCenter)
        self.table.item(row, 2).setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter | QtCore.Qt.AlignCenter)
        self.table.item(row, 3).setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter | QtCore.Qt.AlignCenter)
        self.table.item(row, 4).setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter | QtCore.Qt.AlignCenter)

    def clickTypetoAscii(self, click):
        try:
            if click == 1:
                return "Left Click"
            elif click == 2:
                return "Middle Click"
            else:
                return "Right Click"
        except ValueError:
            return "Left Click"

    def disableUI(self):
        for w in self.findChildren(QtGui.QPushButton):
            w.setEnabled(False)
        for w in self.findChildren(QtGui.QLineEdit):
            w.setEnabled(False)

        self.cmbClickType.setEnabled(False)
        self.table.setEnabled(False)

    def enableUI(self):
        for w in self.findChildren(QtGui.QPushButton):
            w.setEnabled(True)
        for w in self.findChildren(QtGui.QLineEdit):
            w.setEnabled(True)

        self.cmbClickType.setEnabled(True)
        self.table.setEnabled(True)

    def updateUI(self):
        self.enableUI()
        self.setWindowState(QtCore.Qt.WindowActive)
        self.setWindowTitle(self.title)
        self.btnStartStopSequence.setText("Start")
        win32api.SetCursorPos((self.x() + self.width() / 2, self.y() + self.height() / 2))

    def load(self, fileName):
        list = []

        with open(fileName, "rb") as fileInput:
            reader = csv.reader(fileInput)
            templist = []
            for row in reader:
                items = [ str(field) for field in row ]
                templist.append(items)
            list.append(templist)

        self.listToTable(list)

    def save(self, fileName):
        list = self.tableToList()

        with open(fileName, "wb") as fileOutput:
            writer = csv.writer(fileOutput)
            writer.writerows(list)

        self.savePending = False

    def confirm(self, question):
        reply = QtGui.QMessageBox.question(self, 'Confirmation Required', question, QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)

        if reply == QtGui.QMessageBox.Yes:
            return True
        else:
            return False