summaryrefslogtreecommitdiff
path: root/src/python/app/keyboardmanager.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/python/app/keyboardmanager.py')
-rw-r--r--src/python/app/keyboardmanager.py204
1 files changed, 204 insertions, 0 deletions
diff --git a/src/python/app/keyboardmanager.py b/src/python/app/keyboardmanager.py
new file mode 100644
index 0000000..accdf52
--- /dev/null
+++ b/src/python/app/keyboardmanager.py
@@ -0,0 +1,204 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# libavg - Media Playback Engine.
+# Copyright (C) 2003-2014 Ulrich von Zadow
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# Current versions can be found at www.libavg.de
+#
+# Original author of this file is OXullo Interecans <x at brainrapers dot org>
+
+
+from collections import namedtuple
+
+from libavg import avg, player
+
+IGNORED_KEYMODS = avg.KEYMOD_NUM
+KEYMOD_ANY = -1
+
+LOGCAT = avg.logger.configureCategory('KEYBOARDMANAGER',
+ avg.logger.Severity.WARN)
+
+class KeyboardManagerPublisher(avg.Publisher):
+ BINDINGS_UPDATED = avg.Publisher.genMessageID()
+ def __init__(self):
+ super(KeyboardManagerPublisher, self).__init__()
+ self.publish(self.BINDINGS_UPDATED)
+
+ def notifyUpdate(self):
+ self.notifySubscribers(self.BINDINGS_UPDATED, [])
+
+publisher = KeyboardManagerPublisher()
+
+_KeyBinding = namedtuple('_KeyBinding',
+ ['keystring', 'handler', 'help', 'modifiers', 'type'])
+
+
+_modifiedKeyBindings = []
+_plainKeyBindings = []
+_plainKeyBindingsStack = []
+_isEnabled = True
+
+
+def init():
+ player.subscribe(player.KEY_DOWN, _onKeyDown)
+ player.subscribe(player.KEY_UP, _onKeyUp)
+ avg.logger.debug('Keyboardmanager initialized', LOGCAT)
+
+def bindKeyDown(keystring, handler, help, modifiers=avg.KEYMOD_NONE):
+ _bindKey(keystring, handler, help, modifiers, avg.KEYDOWN)
+
+def bindKeyUp(keystring, handler, help, modifiers=avg.KEYMOD_NONE):
+ _bindKey(keystring, handler, help, modifiers, avg.KEYUP)
+
+def unbindKeyUp(keystring, modifiers=avg.KEYMOD_NONE):
+ _unbindKey(keystring, modifiers, avg.KEYUP)
+
+def unbindKeyDown(keystring, modifiers=avg.KEYMOD_NONE):
+ _unbindKey(keystring, modifiers, avg.KEYDOWN)
+
+def unbindAll():
+ global _modifiedKeyBindings, _plainKeyBindings, _plainKeyBindingsStack
+ _modifiedKeyBindings = []
+ _plainKeyBindings = []
+ _plainKeyBindingsStack = []
+ publisher.notifyUpdate()
+
+def push():
+ '''
+ Push the current non-modified defined key bindings to the stack
+ '''
+ global _plainKeyBindings
+ _plainKeyBindingsStack.append(_plainKeyBindings)
+ _plainKeyBindings = []
+ publisher.notifyUpdate()
+
+def pop():
+ '''
+ Pop from the stack the current non-modified defined key bindings
+ '''
+ global _plainKeyBindings
+ _plainKeyBindings = _plainKeyBindingsStack.pop()
+ publisher.notifyUpdate()
+
+def getCurrentBindings():
+ return _modifiedKeyBindings + _plainKeyBindings
+
+def enable():
+ global _isEnabled
+ _isEnabled = True
+
+def disable():
+ global _isEnabled
+ _isEnabled = False
+
+def _bindKey(keystring, handler, help, modifiers, type_):
+ if type(keystring) == unicode:
+ keystring = keystring.encode('utf8')
+
+ avg.logger.info('Binding key <%s> (mod:%s) to handler %s (%s)' % (keystring,
+ modifiers, handler, type), LOGCAT)
+ _checkDuplicates(keystring, modifiers, type_)
+ keyBinding = _KeyBinding(keystring, handler, help, modifiers, type_)
+
+ if modifiers != avg.KEYMOD_NONE:
+ _modifiedKeyBindings.append(keyBinding)
+ else:
+ _plainKeyBindings.append(keyBinding)
+
+ publisher.notifyUpdate()
+
+def _findAndRemoveKeybinding(keystring, modifiers, type, list):
+ for keybinding in list:
+ if keybinding.keystring == keystring and \
+ keybinding.modifiers == modifiers and \
+ keybinding.type == type:
+ list.remove(keybinding)
+ break;
+
+def _unbindKey(keystring, modifiers, type_):
+ if type(keystring) == unicode:
+ keystring = keystring.encode('utf8')
+
+ avg.logger.info('Unbinding key <%s> (mod:%s) (%s)' % (keystring,
+ modifiers, type), LOGCAT)
+ if modifiers != avg.KEYMOD_NONE:
+ _findAndRemoveKeybinding(keystring, modifiers, type_, _modifiedKeyBindings)
+ else:
+ _findAndRemoveKeybinding(keystring, modifiers, type_, _plainKeyBindings)
+
+ publisher.notifyUpdate()
+
+def _onKeyDown(event):
+ if _isEnabled:
+ _processEvent(event, avg.KEYDOWN)
+
+def _onKeyUp(event):
+ if _isEnabled:
+ _processEvent(event, avg.KEYUP)
+
+def _testModifiers(mod1, mod2):
+ if mod1 == KEYMOD_ANY or mod2 == KEYMOD_ANY:
+ return True
+
+ mod1 &= ~IGNORED_KEYMODS
+ mod2 &= ~IGNORED_KEYMODS
+ return mod1 == mod2 or mod1 & mod2
+
+def _testPatternMatch(pattern, text):
+ if pattern in ('shift', 'alt', 'ctrl', 'meta', 'super'):
+ return pattern in text
+ else:
+ return False
+
+def _testMatchString(keyBinding, keyString, type_):
+ sameType = keyBinding.type == type_
+ patternMatch = _testPatternMatch(keyBinding.keystring, keyString)
+ directMatch = keyBinding.keystring == keyString
+
+ return sameType and (directMatch or patternMatch)
+
+def _testMatchEvent(keyBinding, event, type_):
+ if not _testModifiers(event.modifiers, keyBinding.modifiers):
+ return False
+
+ if _testMatchString(keyBinding, event.keystring, type_):
+ return True
+
+ if type_ == avg.KEYDOWN:
+ return _testMatchString(keyBinding,
+ unichr(event.unicode).encode('utf8'), type_)
+ else:
+ return False
+
+def _processEvent(event, type_):
+ avg.logger.debug('Processing event keystring=%s '
+ 'modifiers=%s type=%s' % (event.keystring, event.modifiers, event.type),
+ LOGCAT)
+ for keyBinding in _plainKeyBindings + _modifiedKeyBindings:
+ if _testMatchEvent(keyBinding, event, type_):
+ avg.logger.debug(' Found keyBinding=%s' % (keyBinding,), LOGCAT)
+ keyBinding.handler()
+ return
+
+def _checkDuplicates(keystring, modifiers, type_):
+ for keyBinding in _plainKeyBindings + _modifiedKeyBindings:
+ if (_testModifiers(keyBinding.modifiers, modifiers) and
+ _testMatchString(keyBinding, keystring, type_)):
+ raise RuntimeError('Key binding keystring=%s modifiers=%s type=%s '
+ 'already defined' % (keystring, modifiers, type_))
+