twblue/src/keyboard_handler/wx_handler.py

131 lines
3.8 KiB
Python
Raw Normal View History

2019-06-06 18:52:23 +02:00
from __future__ import absolute_import
import functools
2019-06-06 18:52:23 +02:00
import logging
logger = logging.getLogger("keyboard_handler")
import wx
2019-06-06 18:52:23 +02:00
from .main import KeyboardHandler, KeyboardHandlerError
from . import key_constants
2019-06-06 18:52:23 +02:00
__all__ = ['WXKeyboardHandler', 'WXControlKeyboardHandler']
def call_after(func):
def wrapper(*args, **kwargs):
wx.CallAfter(func, *args, **kwargs)
functools.update_wrapper(wrapper, func)
return wrapper
class BaseWXKeyboardHandler(KeyboardHandler):
def __init__(self, *args, **kwargs):
super(BaseWXKeyboardHandler, self).__init__(*args, **kwargs)
#Setup the replacement dictionaries.
for i in dir(wx):
if i.startswith('WXK_'):
key = i[4:].lower()
self.replacement_keys[key] = getattr(wx, i)
elif i.startswith('MOD_'):
key = i[4:].lower()
self.replacement_mods[key] = getattr(wx, i)
def parse_key (self, keystroke, separator="+"):
keystroke = [self.keycode_from_key(i) for i in keystroke.split(separator)]
mods = 0
for i in keystroke[:-1]:
mods = mods | i #or everything together
return (mods, keystroke[-1])
def keycode_from_key(self, key):
2019-06-06 18:52:23 +02:00
result = None
if key in self.replacement_mods:
result = self.replacement_mods[key]
elif key in self.replacement_keys:
result = self.replacement_keys[key]
if result >= 277:
result -= 277
elif len(key) == 1:
result = ord(key.upper())
2019-06-06 18:52:23 +02:00
if result is None:
raise KeyboardHandlerError("Could not translate key %r into a valid keycode." % key)
return result
2019-06-06 18:52:23 +02:00
class WXKeyboardHandler(BaseWXKeyboardHandler):
def __init__ (self, parent, *args, **kwargs):
super(WXKeyboardHandler, self).__init__(*args, **kwargs)
self.parent = parent
self.key_ids = {}
2019-06-06 18:52:23 +02:00
self.replacement_keys = key_constants.keys
self.replacement_mods = key_constants.modifiers
@call_after
def register_key(self, key, function):
super(WXKeyboardHandler, self).register_key(key, function)
key_id = wx.NewId()
parsed = self.parse_key(key)
2019-06-06 18:52:23 +02:00
res = self.parent.RegisterHotKey(key_id, *parsed)
if not res:
logger.warn("Failed to register hotkey: %s for function %r", key, function)
self.parent.Bind(wx.EVT_HOTKEY, lambda evt: self.process_key(evt, key_id), id=key_id)
self.key_ids[key] = key_id
2019-06-06 18:52:23 +02:00
return res
def parse_key (self, keystroke, separator="+"):
keystroke = str(keystroke) #We don't want unicode
keystroke = [self.keycode_from_key(i) for i in keystroke.split(separator)]
mods = 0
for i in keystroke[:-1]:
mods = mods | i #or everything together
return (mods, keystroke[-1])
@call_after
def unregister_key (self, key, function):
super(WXKeyboardHandler, self).unregister_key(key, function)
if key not in self.key_ids:
return #there's nothing we can do.
key_id = self.key_ids[key]
self.parent.UnregisterHotKey(key_id)
self.parent.Unbind( wx.EVT_HOTKEY, id=key_id)
self.key_ids.pop(key)
def process_key (self, evt, id):
evt.Skip()
key_ids = self.key_ids.keys()
for i in key_ids:
if self.key_ids.get(i) == id:
self.handle_key(i)
class WXControlKeyboardHandler(wx.StaticText, KeyboardHandler):
def __init__(self, parent=None, *a, **k):
wx.StaticText.__init__(self, parent=parent)
KeyboardHandler.__init__(self, *a, **k)
self.wx_replacements = {}
for i in [d for d in dir(wx) if d.startswith('WXK_')]:
self.wx_replacements[getattr(wx, i)] = i[4:].lower()
self.Bind(wx.EVT_KEY_DOWN, self.process_key, self)
self.SetFocus()
def process_key(self, evt):
keycode = evt.GetKeyCode()
keyname = self.wx_replacements.get(keycode, None)
modifiers = ""
replacements = ( (evt.ControlDown(), 'control+'),
(evt.AltDown(), 'alt+'),
(evt.ShiftDown(), 'shift+'),
(evt.MetaDown(), 'win+')
)
for mod, ch in (replacements):
if mod:
modifiers += ch
if keyname is None:
if 27 < keycode < 256:
keyname = chr(keycode).lower()
else:
keyname = "(%s)unknown" % keycode
key = modifiers + keyname
self.handle_key(key)