[core] Add input handling

Add a (half-finished) input library, that for now simply allows
registration and triggering of events.

As next steps, the trigger will happen as part of a separate thread that
reads input events.

Additionally, invoking commands via a execute() will be supported.

Thirdly, there is need of a way to selectively update the affected
modules (widgets), which should be possible given that the event
contains both the instance (widget ID) and name (module name).
This commit is contained in:
Tobias Witek 2020-02-07 21:28:29 +01:00
parent a70c82dc4c
commit e0df8b84e5
4 changed files with 79 additions and 4 deletions

35
core/input.py Normal file
View file

@ -0,0 +1,35 @@
import uuid
LEFT_MOUSE = 1
MIDDLE_MOUSE = 2
RIGHT_MOUSE = 3
WHEEL_UP = 4
WHEEL_DOWN = 5
callbacks = {}
class Object(object):
def __init__(self):
self._id = uuid.uuid4()
def id(self):
return self._id
def register(obj, button=None, cmd=None):
callbacks.setdefault(obj.id(), {}).setdefault(button, []).append(cmd)
def trigger(event):
for field in ['instance', 'name']:
if field in event:
cb = callbacks.get(event[field])
_invoke(event, cb)
def _invoke(event, callback):
if not callback: return
if not 'button' in event: return
for cb in callback.get(event['button']):
if callable(cb):
cb(event)
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -1,6 +1,8 @@
import importlib
import logging
import core.input
log = logging.getLogger(__name__)
def load(module_name, config=None):
@ -11,8 +13,9 @@ def load(module_name, config=None):
return Error(module_name)
return getattr(mod, 'Module')(config)
class Module(object):
class Module(core.input.Object):
def __init__(self, config=None, widgets=[]):
super().__init__()
self._config = config
self._widgets = widgets if isinstance(widgets, list) else [ widgets ]
self._name = None

View file

@ -13,13 +13,13 @@ import locale
import core.module
import core.widget
import core.input
class Module(core.module.Module):
def __init__(self, config):
super().__init__(config, core.widget.Widget(self.full_text))
# TODO: register callback
#engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE,
# cmd='calendar')
core.input.register(self, button=core.input.LEFT_MOUSE, cmd='calendar')
self._fmt = self.parameter('format', self.default_format())
l = locale.getdefaultlocale()
if not l or l == (None, None):

37
tests/core/test_input.py Normal file
View file

@ -0,0 +1,37 @@
import unittest
import core.input
class config(unittest.TestCase):
def setUp(self):
self.inputObject = core.input.Object()
self.anotherObject = core.input.Object()
self.someEvent = { 'button': core.input.LEFT_MOUSE, 'instance': self.inputObject.id() }
self.anotherEvent = { 'button': core.input.RIGHT_MOUSE, 'instance': self.inputObject.id() }
self.callback = unittest.mock.MagicMock()
self.callback2 = unittest.mock.MagicMock()
def test_callable_gets_called(self):
core.input.register(self.inputObject, self.someEvent['button'], self.callback)
core.input.trigger(self.someEvent)
self.callback.assert_called_once_with(self.someEvent)
def test_different_events(self):
core.input.register(self.inputObject, self.someEvent['button'], self.callback)
core.input.register(self.inputObject, self.anotherEvent['button'], self.callback)
core.input.register(self.anotherObject, self.someEvent['button'], self.callback2)
core.input.register(self.anotherObject, self.anotherEvent['button'], self.callback2)
core.input.trigger(self.someEvent)
core.input.trigger(self.anotherEvent)
self.callback.assert_any_call(self.someEvent)
self.callback.assert_any_call(self.anotherEvent)
self.callback2.assert_not_called()
def test_multiple_registrations(self):
core.input.register(self.inputObject, self.someEvent['button'], self.callback)
core.input.register(self.inputObject, self.someEvent['button'], self.callback2)
core.input.trigger(self.someEvent)
self.callback.assert_called_once_with(self.someEvent)
self.callback2.assert_called_once_with(self.someEvent)
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4