Пример #1
0
    def createButton(self, button, propertyDict = dict()):
        """
        Creates the buttons according to the user size definition
        button: Button name
        propertyDict: optional dict parameters that may contain other properties to button, such as color, tooltip and custom category
        """

        pushButton = QtGui.QPushButton(button)
        keys = propertyDict.keys()
        styleSheet = ''
        if 'buttonColor' in keys:
            r, g, b, a = propertyDict['buttonColor'].split(',')
            styleSheet += "background-color:rgba({0},{1},{2},{3});".format(r, g, b, a)
        if 'buttonToolTip' in keys:
            pushButton.setToolTip(propertyDict['buttonToolTip'])
        if 'buttonShortcut' in keys:
            keySequence = QKeySequence(propertyDict['buttonShortcut'])
            pushButton.setText('{0} [{1}]'.format(button, keySequence.toString(format = QKeySequence.NativeText)))
            pushButton.setShortcut(keySequence)

        pushButton.clicked.connect(self.reclassify)
        pushButton.toggled.connect(self.acquire)
        if self.size == 0:
            pushButton.setMinimumSize(100, 25)
            styleSheet += 'font-size:12px;'
        elif self.size == 1:            
            pushButton.setMinimumSize(100, 40)
            styleSheet += 'font-size:20px;'
        elif self.size == 2:            
            pushButton.setMinimumSize(100, 80)
            styleSheet += 'font-size:30px;'
        pushButton.setStyleSheet(styleSheet)
        self.buttons.append(pushButton)
        return pushButton        
Пример #2
0
 def change_keyseq(self, group, name, old_keyseq, keyseq):
     """
     Customize a shortcut's activating key sequence.
     """
     if old_keyseq:
         old_keyseq = QKeySequence(old_keyseq)
         old_keytext = str(old_keyseq.toString())
         self._keyseq_target_actions[old_keytext].remove( (group, name) )        
     try:
         keyseq = QKeySequence(keyseq)
         keytext = str(keyseq.toString())
         target_name_set = self._keyseq_target_actions[keytext]
     except KeyError:
         target_name_set = self._keyseq_target_actions[keytext] = set()
         self._add_global_shortcut_listener( keyseq )
     
     target_name_set.add( (group, name) )
     self._update_tooltip( group, name, keyseq )
Пример #3
0
    def change_keyseq(self, group, name, old_keyseq, keyseq):
        """
        Customize a shortcut's activating key sequence.
        """
        if old_keyseq:
            old_keyseq = QKeySequence(old_keyseq)
            old_keytext = str(old_keyseq.toString())
            self._keyseq_target_actions[old_keytext].remove((group, name))
        try:
            keyseq = QKeySequence(keyseq)
            keytext = str(keyseq.toString())
            target_name_set = self._keyseq_target_actions[keytext]
        except KeyError:
            target_name_set = self._keyseq_target_actions[keytext] = set()
            self._add_global_shortcut_listener(keyseq)

        target_name_set.add((group, name))
        self._update_tooltip(group, name, keyseq)
Пример #4
0
 def test_load_default_shortcuts(self):
     shorts_count = self.shortcuts_manager.result_widget.topLevelItemCount()
     item = self.shortcuts_manager.result_widget.topLevelItem(0)
     shortcut_keys = item.text(1)
     # Expected data
     expected_key = QKeySequence(Qt.CTRL + Qt.Key_N)
     expected_key_str = expected_key.toString(QKeySequence.NativeText)
     # Just one shortcut should be loaded
     self.assertEqual(shorts_count, 1)
     # The key should be the same as the expected
     self.assertEqual(shortcut_keys, expected_key_str)
Пример #5
0
 def test_load_default_shortcuts(self):
     shorts_count = self.shortcuts_manager.result_widget.topLevelItemCount()
     item = self.shortcuts_manager.result_widget.topLevelItem(0)
     shortcut_keys = item.text(1)
     # Expected data
     expected_key = QKeySequence(Qt.CTRL + Qt.Key_N)
     expected_key_str = expected_key.toString(QKeySequence.NativeText)
     # Just one shortcut should be loaded
     self.assertEqual(shorts_count, 1)
     # The key should be the same as the expected
     self.assertEqual(shortcut_keys, expected_key_str)
Пример #6
0
 def _add_global_shortcut_listener(self, keyseq):
     # Create a shortcut for this new key sequence
     # Note: We associate the shortcut with the ENTIRE WINDOW.
     #       We intercept the shortcut and decide which widget to direct it to.
     #       (We don't rely on Qt to do this for us.)
     # Note: This class assumes that all widgets using shortcuts belong to the SAME main window.
     assert keyseq not in self._global_shortcuts
     keyseq = QKeySequence(keyseq)
     keytext = str(keyseq.toString())
     self._global_shortcuts[keytext] = QShortcut( QKeySequence(keyseq), 
                                                  getMainWindow(), 
                                                  member=partial(self._handle_shortcut_pressed, keytext), 
                                                  context=Qt.ApplicationShortcut )
Пример #7
0
 def _add_global_shortcut_listener(self, keyseq):
     # Create a shortcut for this new key sequence
     # Note: We associate the shortcut with the ENTIRE WINDOW.
     #       We intercept the shortcut and decide which widget to direct it to.
     #       (We don't rely on Qt to do this for us.)
     # Note: This class assumes that all widgets using shortcuts belong to the SAME main window.
     assert keyseq not in self._global_shortcuts
     keyseq = QKeySequence(keyseq)
     keytext = str(keyseq.toString())
     self._global_shortcuts[keytext] = QShortcut(
         QKeySequence(keyseq),
         getMainWindow(),
         member=partial(self._handle_shortcut_pressed, keytext),
         context=Qt.ApplicationShortcut)
Пример #8
0
def shortcut(item):
    """Returns a suitable text for the keyboard shortcut of the given item.
    
    Item may be a QAction, a QShortcut, a QKeySequence or a
    QKeySequence.StandardKey.
    
    The text is meant to be used in the help docs.
    
    """
    if isinstance(item, QAction):
        seq = item.shortcut()
    elif isinstance(item, QShortcut):
        seq = item.key()
    elif isinstance(item, QKeySequence.StandardKey):
        seq = QKeySequence(item)
    else:
        seq = item
    return seq.toString(QKeySequence.NativeText) or _("(no key defined)")
Пример #9
0
    def eventFilter(self, object, event):
        """
        Filters out key press events for the shortcut section for this edit.
        
        :param      object | <QObject>
                    event  | <QEvent>
        """
        if (object != self.uiShortcutTXT):
            return False

        if (event.type() == event.KeyPress):
            seq = QKeySequence(event.key() + int(event.modifiers()))
            self.uiShortcutTXT.setText(seq.toString())
            return True

        elif (event.type() == event.KeyRelease):
            return True

        return False
Пример #10
0
 def eventFilter( self, object, event ):
     """
     Filters out key press events for the shortcut section for this edit.
     
     :param      object | <QObject>
                 event  | <QEvent>
     """
     if ( object != self.uiShortcutTXT ):
         return False
         
     if ( event.type() == event.KeyPress ):
         seq = QKeySequence(event.key() + int(event.modifiers()))
         self.uiShortcutTXT.setText( seq.toString() )
         return True
         
     elif ( event.type() == event.KeyRelease):
         return True
     
     return False
Пример #11
0
    def test_save_shortcuts(self):
        data = []

        def called():
            data.append(True)

        actions = gui.FakeActions()
        setattr(actions, 'update_shortcuts', called)
        self.patch(shortcut_manager.actions, 'Actions', lambda: actions)
        self.shortcuts_manager.result_widget.clear()
        key = QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_N)
        key_str = key.toString(QKeySequence.NativeText)
        tree_data = ["New File", key_str, "New-File"]
        item = QTreeWidgetItem(self.shortcuts_manager.result_widget, tree_data)
        item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
        # Before save there is nothing in QSettings
        self.assertEqual(self.settings.value("New-File", None), None)
        # Save
        self.shortcuts_manager.save()
        # After save there is a value for New-File QSettings
        self.assertEqual(self.settings.values["New-File"], key_str)
        # After save check if NINJA call the update_shortcuts in actios.Actions
        self.assertEqual(data, [True])
Пример #12
0
    def test_save_shortcuts(self):
        data = []

        def called():
            data.append(True)

        actions = gui.FakeActions()
        setattr(actions, 'update_shortcuts', called)
        self.patch(shortcut_manager.actions, 'Actions', lambda: actions)
        self.shortcuts_manager.result_widget.clear()
        key = QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_N)
        key_str = key.toString(QKeySequence.NativeText)
        tree_data = ["New File", key_str, "New-File"]
        item = QTreeWidgetItem(self.shortcuts_manager.result_widget, tree_data)
        item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
        # Before save there is nothing in QSettings
        self.assertEqual(self.settings.value("New-File", None), None)
        # Save
        self.shortcuts_manager.save()
        # After save there is a value for New-File QSettings
        self.assertEqual(self.settings.values["New-File"], key_str)
        # After save check if NINJA call the update_shortcuts in actios.Actions
        self.assertEqual(data, [True])
Пример #13
0
    def createButton(self, button, propertyDict=dict()):
        """
        Creates the buttons according to the user size definition
        button: Button name
        propertyDict: optional dict parameters that may contain other properties to button, such as color, tooltip and custom category
        """

        pushButton = QtGui.QPushButton(button)
        keys = propertyDict.keys()
        styleSheet = ''
        if 'buttonColor' in keys:
            r, g, b, a = propertyDict['buttonColor'].split(',')
            styleSheet += "background-color:rgba({0},{1},{2},{3});".format(
                r, g, b, a)
        if 'buttonToolTip' in keys:
            pushButton.setToolTip(propertyDict['buttonToolTip'])
        if 'buttonShortcut' in keys:
            keySequence = QKeySequence(propertyDict['buttonShortcut'])
            pushButton.setText('{0} [{1}]'.format(
                button, keySequence.toString(format=QKeySequence.NativeText)))
            pushButton.setShortcut(keySequence)

        pushButton.clicked.connect(self.reclassify)
        pushButton.toggled.connect(self.acquire)
        if self.size == 0:
            pushButton.setMinimumSize(100, 25)
            styleSheet += 'font-size:12px;'
        elif self.size == 1:
            pushButton.setMinimumSize(100, 40)
            styleSheet += 'font-size:20px;'
        elif self.size == 2:
            pushButton.setMinimumSize(100, 80)
            styleSheet += 'font-size:30px;'
        pushButton.setStyleSheet(styleSheet)
        self.buttons.append(pushButton)
        return pushButton
Пример #14
0
 def stringWithAppendedShortcut(string: str, shortcut: QKeySequence) -> str:
     """
     :returns: An HTML string that contains the given string with a suffixed shortcut key in grey.
     """
     s = shortcut.toString(QKeySequence.NativeText)
     return "{0} <span style=\"color: gray; font-size: small\">{1}</span>".format(string, s)
Пример #15
0
class ShortcutChooserWidget(QtGui.QWidget, FORM_CLASS):
    keyPressed = pyqtSignal()

    def __init__(self, parent=None):
        """
        Initializates ShortcutChooserWidget
        """
        super(ShortcutChooserWidget, self).__init__(parent)
        self.resetVariables()
        self.setupUi(self)

    @pyqtSlot(bool)
    def on_assignShortcutPushButton_clicked(self):
        """
        After button is clicked, focus is needed to use keyPressEvent and keyReleaseEvent
        """
        self.setFocus()

    @pyqtSlot(bool)
    def on_assignShortcutPushButton_toggled(self, toggled):
        """
        Button toggled reset self.modifiers and self.keys and also prepairs button text
        """
        if toggled:
            self.resetVariables()
            self.assignShortcutPushButton.setText(self.tr('Enter Value'))

    @pyqtSlot(bool, name='on_clearPushButton_clicked')
    def clearAll(self):
        """
        Clears push button and also resets self.modifiers and self.keys
        """
        self.assignShortcutPushButton.setChecked(False)
        self.assignShortcutPushButton.setText(self.tr('Assign Shortcut'))
        self.resetVariables()

    def resetVariables(self):
        """
        Resets self.modifiers, self.key and self.keySequence to 0
        """
        self.modifiers = 0
        self.key = 0
        self.keySequence = 0

    def keyPressEvent(self, event):
        """
        """
        if not self.assignShortcutPushButton.isChecked():
            super(ShortcutChooserWidget, self).keyPressEvent(event)
            return
        key = int(event.key())
        if key == Qt.Key_Meta:
            self.modifiers |= Qt.META
            self.updateShortcutText()
        elif key == Qt.Key_Alt:
            self.modifiers |= Qt.ALT
            self.updateShortcutText()
        elif key == Qt.Key_Control:
            self.modifiers |= Qt.CTRL
            self.updateShortcutText()
        elif key == Qt.Key_Shift:
            self.modifiers |= Qt.SHIFT
            self.updateShortcutText()
        elif key == Qt.Key_Escape:
            self.assignShortcutPushButton.setChecked(False)
            return
        else:
            self.key = key
            self.updateShortcutText()

    def keyReleaseEvent(self, event):
        if not self.assignShortcutPushButton.isChecked():
            super(ShortcutChooserWidget, self).keyReleaseEvent(event)
            return
        key = event.key()
        if key == Qt.Key_Meta:
            self.modifiers &= Qt.META
            self.updateShortcutText()
        elif key == Qt.Key_Alt:
            self.modifiers &= Qt.ALT
            self.updateShortcutText()
        elif key == Qt.Key_Control:
            self.modifiers &= Qt.CTRL
            self.updateShortcutText()
        elif key == Qt.Key_Shift:
            self.modifiers &= Qt.SHIFT
            self.updateShortcutText()
        elif key == Qt.Key_Escape:
            return
        else:
            self.assignShortcutPushButton.setChecked(False)
            self.updateShortcutText()
            self.setShortcut(self.keySequence)

    def setEnabled(self, enabled):
        if not enabled:
            self.clearAll()
        super(ShortcutChooserWidget, self).setEnabled(enabled)

    def setShortcut(self, shortcut):
        self.keySequence = QKeySequence(shortcut)
        self.assignShortcutPushButton.setChecked(False)
        self.assignShortcutPushButton.setText(
            self.keySequence.toString(format=QKeySequence.NativeText))

    def getShortcut(self, asQKeySequence=False):
        if asQKeySequence:
            return self.keySequence
        else:
            return int(self.keySequence)

    def updateShortcutText(self):
        self.keySequence = QKeySequence(self.modifiers + self.key)
        #this uses QKeySequence.NativeText to show in the interface. To store data, no filter should be provided
        self.assignShortcutPushButton.setText(
            self.tr('Input: {0}').format(
                self.keySequence.toString(format=QKeySequence.NativeText)))
Пример #16
0
class KeySequenceButton(QPushButton):
    def __init__(self, parent=None):
        super(KeySequenceButton, self).__init__(parent)
        self.setIcon(icons.get("configure"))
        self._modifierlessAllowed = False
        self._seq = QKeySequence()
        self._timer = QTimer()
        self._timer.setSingleShot(True)
        self._isrecording = False
        self.clicked.connect(self.startRecording)
        self._timer.timeout.connect(self.doneRecording)

    def setKeySequence(self, seq):
        self._seq = seq
        self.updateDisplay()

    def keySequence(self):
        if self._isrecording:
            self.doneRecording()
        return self._seq

    def updateDisplay(self):
        if self._isrecording:
            s = self._recseq.toString(QKeySequence.NativeText).replace("&", "&&")
            if self._modifiers:
                if s:
                    s += ","
                s += QKeySequence(self._modifiers).toString(QKeySequence.NativeText)
            elif self._recseq.isEmpty():
                s = _("Input")
            s += " ..."
        else:
            s = self._seq.toString(QKeySequence.NativeText).replace("&", "&&")
        self.setText(s)

    def isRecording(self):
        return self._isrecording

    def event(self, ev):
        if self._isrecording:
            # prevent Qt from special casing Tab and Backtab
            if ev.type() == QEvent.KeyPress:
                self.keyPressEvent(ev)
                return True
        return super(KeySequenceButton, self).event(ev)

    def keyPressEvent(self, ev):
        if not self._isrecording:
            return super(KeySequenceButton, self).keyPressEvent(ev)
        if ev.isAutoRepeat():
            return
        modifiers = int(ev.modifiers() & (Qt.SHIFT | Qt.CTRL | Qt.ALT | Qt.META))
        ev.accept()

        key = ev.key()
        # check if key is a modifier or a character key without modifier (and if that is allowed)
        if (
            # don't append the key if the key is -1 (garbage) or a modifier ...
            key not in (-1, Qt.Key_AltGr, Qt.Key_Shift, Qt.Key_Control, Qt.Key_Alt, Qt.Key_Meta, Qt.Key_Menu)
            # or if this is the first key and without modifier and modifierless keys are not allowed
            and (
                self._modifierlessAllowed
                or self._recseq.count() > 0
                or modifiers & ~Qt.SHIFT
                or not ev.text()
                or (
                    modifiers & Qt.SHIFT
                    and key
                    in (
                        Qt.Key_Return,
                        Qt.Key_Space,
                        Qt.Key_Tab,
                        Qt.Key_Backtab,
                        Qt.Key_Backspace,
                        Qt.Key_Delete,
                        Qt.Key_Escape,
                    )
                )
            )
        ):
            # change Shift+Backtab into Shift+Tab
            if key == Qt.Key_Backtab and modifiers & Qt.SHIFT:
                key = Qt.Key_Tab | modifiers
            # remove the Shift modifier if it doesn't make sense
            #            elif (Qt.Key_Exclam <= key <= Qt.Key_At
            #                  or Qt.Key_Z < key <= 0x0ff):
            #                key = key | (modifiers & ~Qt.SHIFT)
            else:
                key = key | modifiers

            # append max. 4 keystrokes
            if self._recseq.count() < 4:
                l = list(self._recseq)
                l.append(key)
                self._recseq = QKeySequence(*l)

        self._modifiers = modifiers
        self.controlTimer()
        self.updateDisplay()

    def keyReleaseEvent(self, ev):
        if not self._isrecording:
            return super(KeySequenceButton, self).keyReleaseEvent(ev)
        modifiers = int(ev.modifiers() & (Qt.SHIFT | Qt.CTRL | Qt.ALT | Qt.META))
        ev.accept()

        self._modifiers = modifiers
        self.controlTimer()
        self.updateDisplay()

    def hideEvent(self, ev):
        if self._isrecording:
            self.cancelRecording()
        super(KeySequenceButton, self).hideEvent(ev)

    def controlTimer(self):
        if self._modifiers or self._recseq.isEmpty():
            self._timer.stop()
        else:
            self._timer.start(600)

    def startRecording(self):
        self.setFocus(True)  # because of QTBUG 17810
        self.setDown(True)
        self.setStyleSheet("text-align: left;")
        self._isrecording = True
        self._recseq = QKeySequence()
        self._modifiers = int(QApplication.keyboardModifiers() & (Qt.SHIFT | Qt.CTRL | Qt.ALT | Qt.META))
        self.grabKeyboard()
        self.updateDisplay()

    def doneRecording(self):
        self._seq = self._recseq
        self.cancelRecording()
        self.clearFocus()
        self.parentWidget().keySequenceChanged.emit(self.parentWidget().num())

    def cancelRecording(self):
        if not self._isrecording:
            return
        self.setDown(False)
        self.setStyleSheet(None)
        self._isrecording = False
        self.releaseKeyboard()
        self.updateDisplay()
Пример #17
0
class ShortcutChooserWidget(QtGui.QWidget, FORM_CLASS):
    keyPressed = pyqtSignal()
    def __init__(self, parent=None):
        """
        Initializates ShortcutChooserWidget
        """
        super(ShortcutChooserWidget, self).__init__(parent)
        self.resetVariables()
        self.setupUi(self)
    
    @pyqtSlot(bool)
    def on_assignShortcutPushButton_clicked(self):
        """
        After button is clicked, focus is needed to use keyPressEvent and keyReleaseEvent
        """
        self.setFocus()
    
    @pyqtSlot(bool)
    def on_assignShortcutPushButton_toggled(self, toggled):
        """
        Button toggled reset self.modifiers and self.keys and also prepairs button text
        """
        if toggled:
            self.resetVariables()
            self.assignShortcutPushButton.setText(self.tr('Enter Value'))
    
    @pyqtSlot(bool, name = 'on_clearPushButton_clicked')
    def clearAll(self):
        """
        Clears push button and also resets self.modifiers and self.keys
        """
        self.assignShortcutPushButton.setChecked(False)
        self.assignShortcutPushButton.setText(self.tr('Assign Shortcut'))
        self.resetVariables()
    
    def resetVariables(self):
        """
        Resets self.modifiers, self.key and self.keySequence to 0
        """
        self.modifiers = 0
        self.key = 0
        self.keySequence = 0

    def keyPressEvent(self, event):
        """
        """
        if not self.assignShortcutPushButton.isChecked():
            super(ShortcutChooserWidget, self).keyPressEvent(event)
            return
        key = int(event.key())
        if key == Qt.Key_Meta:
            self.modifiers |= Qt.META
            self.updateShortcutText()
        elif key == Qt.Key_Alt:
            self.modifiers |= Qt.ALT
            self.updateShortcutText()
        elif key == Qt.Key_Control:
            self.modifiers |= Qt.CTRL
            self.updateShortcutText()
        elif key == Qt.Key_Shift:
            self.modifiers |= Qt.SHIFT
            self.updateShortcutText()
        elif key == Qt.Key_Escape:
            self.assignShortcutPushButton.setChecked(False)
            return
        else:
            self.key = key
            self.updateShortcutText()

    def keyReleaseEvent(self, event):
        if not self.assignShortcutPushButton.isChecked():
            super(ShortcutChooserWidget, self).keyReleaseEvent(event)
            return
        key = event.key()
        if key == Qt.Key_Meta:
            self.modifiers &= Qt.META
            self.updateShortcutText()
        elif key == Qt.Key_Alt:
            self.modifiers &= Qt.ALT
            self.updateShortcutText()
        elif key == Qt.Key_Control:
            self.modifiers &= Qt.CTRL
            self.updateShortcutText()
        elif key == Qt.Key_Shift:
            self.modifiers &= Qt.SHIFT
            self.updateShortcutText()
        elif key == Qt.Key_Escape:
            return
        else:
            self.assignShortcutPushButton.setChecked(False)
            self.updateShortcutText()
            self.setShortcut(self.keySequence)
    
    def setEnabled(self, enabled):
        if not enabled:
            self.clearAll()
        super(ShortcutChooserWidget, self).setEnabled(enabled)

    def setShortcut(self, shortcut):
        self.keySequence = QKeySequence(shortcut)
        self.assignShortcutPushButton.setChecked(False)
        self.assignShortcutPushButton.setText(self.keySequence.toString(format = QKeySequence.NativeText))
    
    def getShortcut(self, asQKeySequence = False):
        if asQKeySequence:
            return self.keySequence
        else:
            return int(self.keySequence)

    def updateShortcutText(self):
        self.keySequence = QKeySequence(self.modifiers+self.key)
        #this uses QKeySequence.NativeText to show in the interface. To store data, no filter should be provided
        self.assignShortcutPushButton.setText(self.tr('Input: {0}').format(self.keySequence.toString(format = QKeySequence.NativeText)))
Пример #18
0
class KeySequenceButton(QPushButton):
    def __init__(self, parent=None):
        super(KeySequenceButton, self).__init__(parent)
        self.setIcon(icons.get("configure"))
        self._modifierlessAllowed = False
        self._seq = QKeySequence()
        self._timer = QTimer()
        self._timer.setSingleShot(True)
        self._isrecording = False
        self.clicked.connect(self.startRecording)
        self._timer.timeout.connect(self.doneRecording)

    def setKeySequence(self, seq):
        self._seq = seq
        self.updateDisplay()

    def keySequence(self):
        if self._isrecording:
            self.doneRecording()
        return self._seq

    def updateDisplay(self):
        if self._isrecording:
            s = self._recseq.toString(QKeySequence.NativeText).replace(
                '&', '&&')
            if self._modifiers:
                if s: s += ","
                s += QKeySequence(self._modifiers).toString(
                    QKeySequence.NativeText)
            elif self._recseq.isEmpty():
                s = _("Input")
            s += " ..."
        else:
            s = self._seq.toString(QKeySequence.NativeText).replace('&', '&&')
        self.setText(s)

    def isRecording(self):
        return self._isrecording

    def event(self, ev):
        if self._isrecording:
            # prevent Qt from special casing Tab and Backtab
            if ev.type() == QEvent.KeyPress:
                self.keyPressEvent(ev)
                return True
        return super(KeySequenceButton, self).event(ev)

    def keyPressEvent(self, ev):
        if not self._isrecording:
            return super(KeySequenceButton, self).keyPressEvent(ev)
        if ev.isAutoRepeat():
            return
        modifiers = int(ev.modifiers()
                        & (Qt.SHIFT | Qt.CTRL | Qt.ALT | Qt.META))
        ev.accept()

        key = ev.key()
        # check if key is a modifier or a character key without modifier (and if that is allowed)
        if (
                # don't append the key if the key is -1 (garbage) or a modifier ...
                key not in (-1, Qt.Key_AltGr, Qt.Key_Shift, Qt.Key_Control,
                            Qt.Key_Alt, Qt.Key_Meta, Qt.Key_Menu)
                # or if this is the first key and without modifier and modifierless keys are not allowed
                and (self._modifierlessAllowed or self._recseq.count() > 0
                     or modifiers & ~Qt.SHIFT or not ev.text() or
                     (modifiers & Qt.SHIFT and key in
                      (Qt.Key_Return, Qt.Key_Space, Qt.Key_Tab, Qt.Key_Backtab,
                       Qt.Key_Backspace, Qt.Key_Delete, Qt.Key_Escape)))):
            # change Shift+Backtab into Shift+Tab
            if key == Qt.Key_Backtab and modifiers & Qt.SHIFT:
                key = Qt.Key_Tab | modifiers
            # remove the Shift modifier if it doesn't make sense
#            elif (Qt.Key_Exclam <= key <= Qt.Key_At
#                  or Qt.Key_Z < key <= 0x0ff):
#                key = key | (modifiers & ~Qt.SHIFT)
            else:
                key = key | modifiers

            # append max. 4 keystrokes
            if self._recseq.count() < 4:
                l = list(self._recseq)
                l.append(key)
                self._recseq = QKeySequence(*l)

        self._modifiers = modifiers
        self.controlTimer()
        self.updateDisplay()

    def keyReleaseEvent(self, ev):
        if not self._isrecording:
            return super(KeySequenceButton, self).keyReleaseEvent(ev)
        modifiers = int(ev.modifiers()
                        & (Qt.SHIFT | Qt.CTRL | Qt.ALT | Qt.META))
        ev.accept()

        self._modifiers = modifiers
        self.controlTimer()
        self.updateDisplay()

    def hideEvent(self, ev):
        if self._isrecording:
            self.cancelRecording()
        super(KeySequenceButton, self).hideEvent(ev)

    def controlTimer(self):
        if self._modifiers or self._recseq.isEmpty():
            self._timer.stop()
        else:
            self._timer.start(600)

    def startRecording(self):
        self.setFocus(True)  # because of QTBUG 17810
        self.setDown(True)
        self.setStyleSheet("text-align: left;")
        self._isrecording = True
        self._recseq = QKeySequence()
        self._modifiers = int(QApplication.keyboardModifiers()
                              & (Qt.SHIFT | Qt.CTRL | Qt.ALT | Qt.META))
        self.grabKeyboard()
        self.updateDisplay()

    def doneRecording(self):
        self._seq = self._recseq
        self.cancelRecording()
        self.clearFocus()
        self.parentWidget().keySequenceChanged.emit(self.parentWidget().num())

    def cancelRecording(self):
        if not self._isrecording:
            return
        self.setDown(False)
        self.setStyleSheet(None)
        self._isrecording = False
        self.releaseKeyboard()
        self.updateDisplay()