diff options
Diffstat (limited to 'src/python/app/keyboardmanager.py')
-rw-r--r-- | src/python/app/keyboardmanager.py | 204 |
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_)) + |