Implement handling keys with modifiers

This commit is contained in:
Florian Bruhin 2014-02-05 10:54:56 +01:00
parent 630ff1cbf6
commit 9c19fd21d6
2 changed files with 85 additions and 8 deletions

View File

@ -4,7 +4,8 @@
import logging import logging
import re import re
from PyQt5.QtCore import QObject, pyqtSignal from PyQt5.QtCore import QObject, pyqtSignal, Qt
from PyQt5.QtGui import QKeySequence
from qutebrowser.commands.utils import (CommandParser, ArgumentCountError, from qutebrowser.commands.utils import (CommandParser, ArgumentCountError,
NoSuchCommandError) NoSuchCommandError)
@ -22,6 +23,7 @@ class KeyParser(QObject):
keystring_updated = pyqtSignal(str) keystring_updated = pyqtSignal(str)
# Keybindings # Keybindings
bindings = {} bindings = {}
modifier_bindings = {}
commandparser = None commandparser = None
MATCH_PARTIAL = 0 MATCH_PARTIAL = 0
@ -39,16 +41,69 @@ class KeyParser(QObject):
gg = scrollstart gg = scrollstart
""" """
for (key, cmd) in sect.items(): for (key, cmd) in sect.items():
logging.debug('registered key: {} -> {}'.format(key, cmd)) if key.startswith('@') and key.endswith('@'):
self.bindings[key] = cmd # normalize keystring
keystr = self._normalize_keystr(key.strip('@'))
logging.debug('registered mod key: {} -> {}'.format(keystr,
cmd))
self.modifier_bindings[keystr] = cmd
else:
logging.debug('registered key: {} -> {}'.format(key, cmd))
self.bindings[key] = cmd
def handle(self, e): def handle(self, e):
"""Wrap _handle to emit keystring_updated after _handle.""" """Handle a new keypress and call the respective handlers.
self._handle(e)
self.keystring_updated.emit(self.keystring)
def _handle(self, e): e -- the KeyPressEvent from Qt
"""Handle a new keypress. """
handled = self._handle_modifier_key(e)
if not handled:
self._handle_single_key(e)
self.keystring_updated.emit(self.keystring)
def _handle_modifier_key(self, e):
"""Handle a new keypress with modifiers.
Returns True if the keypress has been handled, and False if not.
e -- the KeyPressEvent from Qt
"""
MODMASK2STR = {
Qt.ControlModifier: 'Ctrl',
Qt.AltModifier: 'Alt',
Qt.MetaModifier: 'Meta',
Qt.ShiftModifier: 'Shift'
}
if e.key() in [Qt.Key_Control, Qt.Key_Alt, Qt.Key_Shift, Qt.Key_Meta]:
# Only modifier pressed
return False
mod = e.modifiers()
modstr = ''
if not mod & (Qt.ControlModifier | Qt.AltModifier | Qt.MetaModifier):
# won't be a shortcut with modifiers
return False
for (mask, s) in MODMASK2STR.items():
if mod & mask:
modstr += s + '+'
keystr = QKeySequence(e.key()).toString()
try:
cmdstr = self.modifier_bindings[modstr + keystr]
except KeyError:
logging.debug('No binding found for {}.'.format(modstr + keystr))
return True
# FIXME use a common function for this
try:
self.commandparser.run(cmdstr, ignore_exc=False)
except NoSuchCommandError:
pass
except ArgumentCountError:
logging.debug('Filling statusbar with partial command {}'.format(
cmdstr))
self.set_cmd_text.emit(':{} '.format(cmdstr))
return True
def _handle_single_key(self, e):
"""Handle a new keypress with a single key (no modifiers).
Separates the keypress into count/command, then checks if it matches Separates the keypress into count/command, then checks if it matches
any possible command, and either runs the command, ignores it, or any possible command, and either runs the command, ignores it, or
@ -128,3 +183,21 @@ class KeyParser(QObject):
continue continue
# no definitive and no partial matches if we arrived here # no definitive and no partial matches if we arrived here
return (self.MATCH_NONE, None) return (self.MATCH_NONE, None)
def _normalize_keystr(self, keystr):
"""Normalizes a keystring like Ctrl-Q to a keystring like Ctrl+Q.
keystr -- The key combination as a string.
"""
replacements = [
('Control', 'Ctrl'),
('Windows', 'Meta'),
('Mod1', 'Alt'),
('Mod4', 'Meta'),
]
for (orig, repl) in replacements:
keystr = keystr.replace(orig, repl)
for mod in ['Ctrl', 'Meta', 'Alt', 'Shift']:
keystr = keystr.replace(mod + '-', mod + '+')
keystr = QKeySequence(keystr).toString()
return keystr

View File

@ -48,6 +48,10 @@ default_config = """
pP = paste sel pP = paste sel
Pp = tabpaste Pp = tabpaste
PP = tabpaste sel PP = tabpaste sel
@Ctrl-Q@ = quit
@Ctrl-Shift-T@ = undo
@Ctrl-W@ = tabclose
@Ctrl-T@ = tabopen about:blank
[colors] [colors]
completion.fg = #333333 completion.fg = #333333