Make all key names work

This commit is contained in:
Florian Bruhin 2018-02-28 10:21:02 +01:00
parent 601e56d2fa
commit 0b6d2c2b0a
3 changed files with 110 additions and 142 deletions

View File

@ -39,69 +39,63 @@ def _key_to_string(key):
Return:
A name of the key as a string.
"""
return QKeySequence(key).toString() # FIXME
special_names_str = {
# Some keys handled in a weird way by QKeySequence::toString.
# See https://bugreports.qt.io/browse/QTBUG-40030
# Most are unlikely to be ever needed, but you never know ;)
# For dead/combining keys, we return the corresponding non-combining
# key, as that's easier to add to the config.
'Key_Blue': 'Blue',
'Key_Calendar': 'Calendar',
'Key_ChannelDown': 'Channel Down',
'Key_ChannelUp': 'Channel Up',
'Key_ContrastAdjust': 'Contrast Adjust',
'Key_Dead_Abovedot': '˙',
'Key_Dead_Abovering': '˚',
'Key_Dead_Acute': '´',
'Key_Dead_Belowdot': 'Belowdot',
'Key_Dead_Breve': '˘',
'Key_Dead_Caron': 'ˇ',
'Key_Dead_Cedilla': '¸',
'Key_Dead_Circumflex': '^',
'Key_Dead_Diaeresis': '¨',
'Key_Dead_Doubleacute': '˝',
'Key_Dead_Grave': '`',
'Key_Dead_Hook': 'Hook',
'Key_Dead_Horn': 'Horn',
'Key_Dead_Iota': 'Iota',
'Key_Dead_Macron': '¯',
'Key_Dead_Ogonek': '˛',
'Key_Dead_Semivoiced_Sound': 'Semivoiced Sound',
'Key_Dead_Tilde': '~',
'Key_Dead_Voiced_Sound': 'Voiced Sound',
'Key_Exit': 'Exit',
'Key_Green': 'Green',
'Key_Guide': 'Guide',
'Key_Info': 'Info',
'Key_LaunchG': 'LaunchG',
'Key_LaunchH': 'LaunchH',
'Key_MediaLast': 'MediaLast',
'Key_Memo': 'Memo',
'Key_MicMute': 'Mic Mute',
'Key_Mode_switch': 'Mode switch',
'Key_Multi_key': 'Multi key',
'Key_PowerDown': 'Power Down',
'Key_Red': 'Red',
'Key_Settings': 'Settings',
'Key_SingleCandidate': 'Single Candidate',
'Key_ToDoList': 'Todo List',
'Key_TouchpadOff': 'Touchpad Off',
'Key_TouchpadOn': 'Touchpad On',
'Key_TouchpadToggle': 'Touchpad toggle',
'Key_Yellow': 'Yellow',
'Key_Alt': 'Alt',
'Key_AltGr': 'AltGr',
'Key_Control': 'Control',
'Key_Direction_L': 'Direction L',
'Key_Direction_R': 'Direction R',
'Key_Hyper_L': 'Hyper L',
'Key_Hyper_R': 'Hyper R',
'Key_Meta': 'Meta',
'Key_Shift': 'Shift',
'Key_Super_L': 'Super L',
'Key_Super_R': 'Super R',
'Key_unknown': 'Unknown',
'Super_L': 'Super L',
'Super_R': 'Super R',
'Hyper_L': 'Hyper L',
'Hyper_R': 'Hyper R',
'Direction_L': 'Direction L',
'Direction_R': 'Direction R',
'Shift': 'Shift',
'Control': 'Control',
'Meta': 'Meta',
'Alt': 'Alt',
'AltGr': 'AltGr',
'Multi_key': 'Multi key',
'SingleCandidate': 'Single Candidate',
'Mode_switch': 'Mode switch',
'Dead_Grave': '`',
'Dead_Acute': '´',
'Dead_Circumflex': '^',
'Dead_Tilde': '~',
'Dead_Macron': '¯',
'Dead_Breve': '˘',
'Dead_Abovedot': '˙',
'Dead_Diaeresis': '¨',
'Dead_Abovering': '˚',
'Dead_Doubleacute': '˝',
'Dead_Caron': 'ˇ',
'Dead_Cedilla': '¸',
'Dead_Ogonek': '˛',
'Dead_Iota': 'Iota',
'Dead_Voiced_Sound': 'Voiced Sound',
'Dead_Semivoiced_Sound': 'Semivoiced Sound',
'Dead_Belowdot': 'Belowdot',
'Dead_Hook': 'Hook',
'Dead_Horn': 'Horn',
'Memo': 'Memo',
'ToDoList': 'To Do List',
'Calendar': 'Calendar',
'ContrastAdjust': 'Contrast Adjust',
'LaunchG': 'Launch (G)',
'LaunchH': 'Launch (H)',
'MediaLast': 'Media Last',
'unknown': 'Unknown',
# For some keys, we just want a different name
'Backtab': 'Tab',
'Escape': 'Escape',
}
# We now build our real special_names dict from the string mapping above.
# The reason we don't do this directly is that certain Qt versions don't
@ -109,23 +103,14 @@ def _key_to_string(key):
special_names = {}
for k, v in special_names_str.items():
try:
special_names[getattr(Qt, k)] = v
special_names[getattr(Qt, 'Key_' + k)] = v
except AttributeError:
pass
# Now we check if the key is any special one - if not, we use
# QKeySequence::toString.
try:
if key in special_names:
return special_names[key]
except KeyError:
name = QKeySequence(key).toString()
morphings = {
'Backtab': 'Tab',
'Esc': 'Escape',
}
if name in morphings:
return morphings[name]
else:
return name
return QKeySequence(key).toString()
class KeyParseError(Exception):

View File

@ -34,9 +34,9 @@ class Key:
# From enum Key in qt5/qtbase/src/corelib/global/qnamespace.h
KEYS = [
### misc keys
Key('Escape', 'Esc'),
Key('Escape'), # qutebrowser has a different name from Qt
Key('Tab'),
Key('Backtab'),
Key('Backtab', 'Tab'), # qutebrowser has a different name from Qt
Key('Backspace'),
Key('Return'),
Key('Enter'),
@ -56,10 +56,10 @@ KEYS = [
Key('PageUp', 'PgUp'),
Key('PageDown', 'PgDown'),
### modifiers
Key('Shift', '\u17c0\udc20'), # FIXME
Key('Control', '\u17c0\udc21'), # FIXME
Key('Meta', '\u17c0\udc22'), # FIXME
Key('Alt', '\u17c0\udc23'), # FIXME
Key('Shift'),
Key('Control'),
Key('Meta'),
Key('Alt'),
Key('CapsLock'),
Key('NumLock'),
Key('ScrollLock'),
@ -101,17 +101,17 @@ KEYS = [
Key('F34'),
Key('F35'),
### extra keys
Key('Super_L', '\u17c0\udc53'), # FIXME
Key('Super_R', '\u17c0\udc54'), # FIXME
Key('Super_L', 'Super L'),
Key('Super_R', 'Super R'),
Key('Menu'),
Key('Hyper_L', '\u17c0\udc56'), # FIXME
Key('Hyper_R', '\u17c0\udc57'), # FIXME
Key('Hyper_L', 'Hyper L'),
Key('Hyper_R', 'Hyper R'),
Key('Help'),
Key('Direction_L', '\u17c0\udc59'), # FIXME
Key('Direction_R', '\u17c0\udc60'), # FIXME
Key('Direction_L', 'Direction L'),
Key('Direction_R', 'Direction R'),
### 7 bit printable ASCII
Key('Space'),
Key('Any', 'Space'), # FIXME
Key('Any', 'Space'), # Same value
Key('Exclam', '!'),
Key('QuoteDbl', '"'),
Key('NumberSign', '#'),
@ -253,15 +253,15 @@ KEYS = [
### you are writing your own input method
### International & multi-key character composition
Key('AltGr', '\u17c4\udd03'), # FIXME
Key('Multi_key', '\u17c4\udd20'), # FIXME Multi-key character compose
Key('AltGr'),
Key('Multi_key', 'Multi key'), # Multi-key character compose
Key('Codeinput', 'Code input'),
Key('SingleCandidate', '\u17c4\udd3c'), # FIXME
Key('SingleCandidate', 'Single Candidate'),
Key('MultipleCandidate', 'Multiple Candidate'),
Key('PreviousCandidate', 'Previous Candidate'),
### Misc Functions
Key('Mode_switch', '\u17c4\udd7e'), # FIXME Character set switch
Key('Mode_switch', 'Mode switch'), # Character set switch
# Key('script_switch'), # Alias for mode_switch
### Japanese keyboard support
@ -309,25 +309,25 @@ KEYS = [
# Key('Hangul_switch', 'Hangul switch'), # Alias for mode_switch
# dead keys (X keycode - 0xED00 to avoid the conflict),
Key('Dead_Grave', '\u17c4\ude50'), # FIXME
Key('Dead_Acute', '\u17c4\ude51'), # FIXME
Key('Dead_Circumflex', '\u17c4\ude52'), # FIXME
Key('Dead_Tilde', '\u17c4\ude53'), # FIXME
Key('Dead_Macron', '\u17c4\ude54'), # FIXME
Key('Dead_Breve', '\u17c4\ude55'), # FIXME
Key('Dead_Abovedot', '\u17c4\ude56'), # FIXME
Key('Dead_Diaeresis', '\u17c4\ude57'), # FIXME
Key('Dead_Abovering', '\u17c4\ude58'), # FIXME
Key('Dead_Doubleacute', '\u17c4\ude59'), # FIXME
Key('Dead_Caron', '\u17c4\ude5a'), # FIXME
Key('Dead_Cedilla', '\u17c4\ude5b'), # FIXME
Key('Dead_Ogonek', '\u17c4\ude5c'), # FIXME
Key('Dead_Iota', '\u17c4\ude5d'), # FIXME
Key('Dead_Voiced_Sound', '\u17c4\ude5e'), # FIXME
Key('Dead_Semivoiced_Sound', '\u17c4\ude5f'), # FIXME
Key('Dead_Belowdot', '\u17c4\ude60'), # FIXME
Key('Dead_Hook', '\u17c4\ude61'), # FIXME
Key('Dead_Horn', '\u17c4\ude62'), # FIXME
Key('Dead_Grave', '`'),
Key('Dead_Acute', '´'),
Key('Dead_Circumflex', '^'),
Key('Dead_Tilde', '~'),
Key('Dead_Macron', '¯'),
Key('Dead_Breve', '˘'),
Key('Dead_Abovedot', '˙'),
Key('Dead_Diaeresis', '¨'),
Key('Dead_Abovering', '˚'),
Key('Dead_Doubleacute', '˝'),
Key('Dead_Caron', 'ˇ'),
Key('Dead_Cedilla', '¸'),
Key('Dead_Ogonek', '˛'),
Key('Dead_Iota', 'Iota'),
Key('Dead_Voiced_Sound', 'Voiced Sound'),
Key('Dead_Semivoiced_Sound', 'Semivoiced Sound'),
Key('Dead_Belowdot', 'Belowdot'),
Key('Dead_Hook', 'Hook'),
Key('Dead_Horn', 'Horn'),
# Not in Qt 5.10, so data may be wrong!
Key('Dead_Stroke'),
@ -415,7 +415,7 @@ KEYS = [
Key('Eject'),
Key('ScreenSaver', 'Screensaver'),
Key('WWW'),
Key('Memo', '\u17c0\udcbc'), # FIXME
Key('Memo', 'Memo'),
Key('LightBulb'),
Key('Shop'),
Key('History'),
@ -431,7 +431,7 @@ KEYS = [
Key('Book'),
Key('CD'),
Key('Calculator'),
Key('ToDoList', '\u17c0\udccc'), # FIXME
Key('ToDoList', 'To Do List'),
Key('ClearGrab', 'Clear Grab'),
Key('Close'),
Key('Copy'),
@ -455,7 +455,7 @@ KEYS = [
Key('Option'),
Key('Paste'),
Key('Phone'),
Key('Calendar', '\u17c0\udce4'), # FIXME
Key('Calendar'),
Key('Reply'),
Key('Reload'),
Key('RotateWindows', 'Rotate Windows'),
@ -496,10 +496,10 @@ KEYS = [
Key('TopMenu', 'Top Menu'),
Key('PowerDown', 'Power Down'),
Key('Suspend'),
Key('ContrastAdjust', '\u17c0\udd0d'), # FIXME
Key('ContrastAdjust', 'Contrast Adjust'),
Key('LaunchG', '\u17c0\udd0e'), # FIXME
Key('LaunchH', '\u17c0\udd0f'), # FIXME
Key('LaunchG', 'Launch (G)'),
Key('LaunchH', 'Launch (H)'),
Key('TouchpadToggle', 'Touchpad Toggle'),
Key('TouchpadOn', 'Touchpad On'),
@ -528,7 +528,7 @@ KEYS = [
Key('Undo'),
Key('Redo'),
Key('MediaLast', '\u17ff\udfff'), # FIXME
Key('MediaLast', 'Media Last'),
### Keypad navigation keys
Key('Select'),
@ -562,5 +562,5 @@ KEYS = [
Key('Camera', 'Camera Shutter'),
Key('CameraFocus', 'Camera Focus'),
Key('unknown', ''), # FIXME
Key('unknown', 'Unknown'),
]

View File

@ -35,43 +35,26 @@ def qt_key(request):
return key
def test_new_to_string(qt_key):
name = qt_key.attribute if qt_key.name is None else qt_key.name
assert keyutils._key_to_string(qt_key.member) == name
class TestKeyToString:
@pytest.mark.parametrize('key, expected', [
(Qt.Key_Blue, 'Blue'),
(Qt.Key_Backtab, 'Tab'),
(Qt.Key_Escape, 'Escape'),
(Qt.Key_A, 'A'),
(Qt.Key_degree, '°'),
(Qt.Key_Meta, 'Meta'),
])
@pytest.mark.skipif(True, reason='FIXME')
def test_normal(self, key, expected):
"""Test a special key where QKeyEvent::toString works incorrectly."""
assert keyutils._key_to_string(key) == expected
def test_to_string(self, qt_key):
name = qt_key.attribute if qt_key.name is None else qt_key.name
assert keyutils._key_to_string(qt_key.member) == name
def test_missing(self, monkeypatch):
"""Test with a missing key."""
monkeypatch.delattr(keyutils.Qt, 'Key_Blue')
# We don't want to test the key which is actually missing - we only
# want to know if the mapping still behaves properly.
assert keyutils._key_to_string(Qt.Key_A) == 'A'
@pytest.mark.skipif(True, reason='FIXME')
def test_all(self):
"""Make sure there's some sensible output for all keys."""
for name, value in sorted(vars(Qt).items()):
if not isinstance(value, Qt.Key):
continue
print(name)
string = keyutils._key_to_string(value)
assert string
string.encode('utf-8') # make sure it's encodable
"""Make sure all possible keys are in key_data.KEYS."""
key_names = {name[len("Key_"):]
for name, value in sorted(vars(Qt).items())
if isinstance(value, Qt.Key)}
key_data_names = {key.attribute for key in sorted(key_data.KEYS)}
diff = key_names - key_data_names
assert not diff
class TestKeyEventToString: