Package elisa :: Package core :: Module input_manager
[hide private]
[frames] | no frames]

Source Code for Module elisa.core.input_manager

  1  # -*- coding: utf-8 -*- 
  2  # Elisa - Home multimedia server 
  3  # Copyright (C) 2006-2008 Fluendo Embedded S.L. (www.fluendo.com). 
  4  # All rights reserved. 
  5  # 
  6  # This file is available under one of two license agreements. 
  7  # 
  8  # This file is licensed under the GPL version 3. 
  9  # See "LICENSE.GPL" in the root of this distribution including a special 
 10  # exception to use Elisa with Fluendo's plugins. 
 11  # 
 12  # The GPL part of Elisa is also available under a commercial licensing 
 13  # agreement from Fluendo. 
 14  # See "LICENSE.Elisa" in the root directory of this distribution package 
 15  # for details on that license. 
 16   
 17   
 18  __maintainer__ = 'Florian Boucault <florian@fluendo.com>' 
 19   
 20   
 21  from elisa.core import common 
 22  from elisa.core import manager 
 23  from elisa.core import input_event 
 24  from elisa.core.utils import signal, classinit 
 25  from elisa.base_components.input_provider import PushInputProvider, PollInputProvider 
 26  from twisted.internet import reactor 
 27   
28 -class InputManager(manager.Manager):
29 """ 30 InputManager provides a common place to retrieve input events 31 coming from a GUI toolkit, additional input sources or even a 32 network. InputEvents can be pushed by 33 L{elisa.base_components.input_provider.InputProvider}s 34 or be polled by the InputManager, depending on the implementation 35 chosen: L{elisa.base_components.input_provider.PollInputProvider} 36 or L{elisa.base_components.input_provider.PushInputProvider}. 37 38 Other objects can connect to the manager's signals 39 that are emitted when L{elisa.core.input_event.InputEvent}s coming from 40 L{elisa.base_components.input_provider.InputProvider}s are received. 41 """ 42
43 - def __init__(self):
44 manager.Manager.__init__(self) 45 46 # 35Hz polling rate for the PollInputProvider 47 self._polling_rate = 1 / 35. 48 self._polling = False 49 self._poll_call = None
50
51 - def start(self):
52 """ Start a polling loop that will regularly check the registered 53 L{elisa.base_components.input_provider.PollInputProvider}s for new 54 L{elisa.core.input_event.InputEvent}s. 55 """ 56 self.info("Starting") 57 self._polling = True 58 # start a looping callLater 59 self._poll_call = reactor.callLater(self._polling_rate, 60 self._poll_events)
61
62 - def stop(self):
63 """ Clean all the registered 64 L{elisa.base_components.input_provider.InputProvider}s and stop 65 polling for new L{elisa.core.input_event.InputEvent}s. 66 """ 67 self.info("Stopping") 68 if self._poll_call: 69 try: 70 self._poll_call.cancel() 71 except: 72 pass 73 self._polling = False 74 manager.Manager.stop(self)
75
76 - def process_event(self, event, provider_path):
77 """ Fire the signal corresponding to the event. 78 79 Each event type is mapped to a signal instance to which other 80 elisa components can connect (e.g to monitor user key presses). 81 82 This method can be called by 83 L{elisa.base_components.input_provider.PushInputProvider} 84 components when they receive input data from the input device. 85 86 @param event: the event to process 87 @type event: L{elisa.core.input_event.InputEvent} 88 @param provider_path: the path of the InputProvider where the event is from 89 @type provider_path: str 90 """ 91 self.debug("Event received: %r", event) 92 93 if event == None: 94 return 95 96 self._emit_event(event, provider_path)
97
98 - def register_component(self, component):
99 """ Register a new InputProvider in the InputManager so that the 100 events collected by the former are propagated by the latter. 101 102 @param component: the InputProvider instance to register 103 @type component: L{elisa.base_components.input_provider.InputProvider} 104 """ 105 manager.Manager.register_component(self, component) 106 # register myself to push_input_providers 107 if isinstance(component, PushInputProvider): 108 component.input_manager = self 109 component.bind() 110 sig_name = 'sig_%s' % component.path 111 setattr(self, sig_name, signal.Signal(sig_name, 112 input_event.InputEvent))
113
114 - def unregister_component(self, component):
115 """ Clean the InputProvider and unregister it from the InputManager; 116 no events from the InputProvider will be propagated anymore. 117 118 @param component: the InputProvider instance to unregister 119 @type component: L{elisa.base_components.input_provider.InputProvider} 120 """ 121 manager.Manager.unregister_component(self, component) 122 component.clean()
123
124 - def subscribe(self, provider_path, callback):
125 """ Register a callback which will be called whenever an 126 L{elisa.core.input_event.InputEvent} coming from the given 127 L{elisa.base_components.input_provider.InputProvider} is raised. 128 129 The first argument passed to the callback will be a 130 L{elisa.core.input_event.InputEvent} instance. 131 132 @param provider_path: the path of the InputProvider from which the 133 events will come from 134 @type provider_path: str 135 @param callback: the object to be called when an event is raised 136 @type callback: callable 137 """ 138 sig_name = 'sig_%s' % provider_path 139 try: 140 sig = getattr(self, sig_name) 141 except AttributeError: 142 msg = "Couldn't connect to input provider %r. Signal %r not found" 143 self.debug(msg, provider_path, sig_name) 144 else: 145 sig.connect(callback)
146
147 - def unsubscribe(self, provider_path, callback):
148 """ Unregister a previously registered callback against a given 149 L{elisa.base_components.input_provider.InputProvider}. Events will no 150 longer be forwarded to the callback. 151 152 @param provider_path: the path of the InputProvider from which the 153 events used to come from 154 @type provider_path: str 155 @param callback: the already registered callback 156 @type callback: callable 157 """ 158 sig_name = 'sig_%s' % provider_path 159 try: 160 sig = getattr(self, sig_name) 161 except AttributeError: 162 self.debug("Couldn't disconnect from input provider %r. Signal %r not found", provider_path, sig_name) 163 else: 164 if sig: 165 try: 166 sig.disconnect(callback) 167 except Exception, exc: 168 self.debug(exc)
169
170 - def _poll_events(self):
171 """ Poll each registered PollInputProvider for InputEvents to 172 process. 173 """ 174 input_providers = filter(lambda p: isinstance(p, PollInputProvider), 175 self._components) 176 177 for input_provider in input_providers: 178 events = input_provider.get_input_events() 179 for event in events: 180 self.process_event(event, input_provider.path) 181 182 if self._polling: 183 self._poll_call = reactor.callLater(self._polling_rate, 184 self._poll_events)
185
186 - def _emit_event(self, event, provider_path):
187 """ Emit an event coming from a given InputProvider """ 188 sig_name = 'sig_%s' % provider_path 189 try: 190 sig = getattr(self, sig_name) 191 except AttributeError: 192 self.debug("Input provider signal %r not found", sig_name) 193 else: 194 sig.emit(event)
195