1 #Copyright (C) 2008 Codethink Ltd
3 #This library is free software; you can redistribute it and/or
4 #modify it under the terms of the GNU Lesser General Public
5 #License version 2 as published by the Free Software Foundation.
7 #This program is distributed in the hope that it will be useful,
8 #but WITHOUT ANY WARRANTY; without even the implied warranty of
9 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 #GNU General Public License for more details.
11 #You should have received a copy of the GNU Lesser General Public License
12 #along with this program; if not, write to the Free Software
13 #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 import dbus.service as _service
19 from base import Enum as _Enum
21 #------------------------------------------------------------------------------
23 class PressedEventType(_Enum):
25 0:'KEY_PRESSED_EVENT',
26 1:'KEY_RELEASED_EVENT',
27 2:'BUTTON_PRESSED_EVENT',
28 3:'BUTTON_RELEASED_EVENT',
31 KEY_PRESSED_EVENT = PressedEventType(0)
32 KEY_RELEASED_EVENT = PressedEventType(1)
33 BUTTON_PRESSED_EVENT = PressedEventType(2)
34 BUTTON_RELEASED_EVENT = PressedEventType(3)
36 #------------------------------------------------------------------------------
38 class ControllerEventMask(_Enum):
40 1:'KEY_PRESSED_EVENT_MASK',
41 2:'KEY_RELEASED_EVENT_MASK',
42 4:'BUTTON_PRESSED_EVENT_MASK',
43 8:'BUTTON_RELEASED_EVENT_MASK',
46 KEY_PRESSED_EVENT_MASK = ControllerEventMask(1)
47 KEY_RELEASED_EVENT_MASK = ControllerEventMask(2)
48 BUTTON_PRESSED_EVENT_MASK = ControllerEventMask(4)
49 BUTTON_RELEASED_EVENT_MASK = ControllerEventMask(8)
51 #------------------------------------------------------------------------------
53 class KeyEventType(_Enum):
58 KEY_PRESSED = KeyEventType(0)
59 KEY_RELEASED = KeyEventType(1)
61 #------------------------------------------------------------------------------
63 class KeySynthType(_Enum):
72 KEY_PRESS = KeySynthType(0)
73 KEY_PRESSRELEASE = KeySynthType(2)
74 KEY_RELEASE = KeySynthType(1)
75 KEY_STRING = KeySynthType(4)
76 KEY_SYM = KeySynthType(3)
78 #------------------------------------------------------------------------------
80 class ModifierType(_Enum):
83 1:'MODIFIER_SHIFTLOCK',
92 MODIFIER_ALT = ModifierType(3)
93 MODIFIER_CONTROL = ModifierType(2)
94 MODIFIER_META = ModifierType(4)
95 MODIFIER_META2 = ModifierType(5)
96 MODIFIER_META3 = ModifierType(6)
97 MODIFIER_NUMLOCK = ModifierType(7)
98 MODIFIER_SHIFT = ModifierType(0)
99 MODIFIER_SHIFTLOCK = ModifierType(1)
101 #------------------------------------------------------------------------------
103 class DeviceEvent(list):
105 Wraps an AT-SPI device event with a more Pythonic interface. Primarily adds
106 a consume attribute which can be used to cease propagation of a device event.
108 @ivar consume: Should this event be consumed and not allowed to pass on to
109 observers further down the dispatch chain in this process or possibly
111 @type consume: boolean
112 @ivar type: Kind of event, KEY_PRESSED_EVENT or KEY_RELEASED_EVENT
113 @type type: Accessibility.EventType
114 @ivar id: Serial identifier for this key event
116 @ivar hw_code: Hardware scan code for the key
117 @type hw_code: integer
118 @ivar modifiers: Modifiers held at the time of the key event
119 @type modifiers: integer
120 @ivar timestamp: Time at which the event occurred relative to some platform
121 dependent starting point (e.g. XWindows start time)
122 @type timestamp: integer
123 @ivar event_string: String describing the key pressed (e.g. keysym)
124 @type event_string: string
125 @ivar is_text: Is the event representative of text to be inserted (True), or
126 of a control key (False)?
127 @type is_text: boolean
129 def __new__(cls, type, id, hw_code, modifiers, timestamp, event_string, is_text):
130 return list.__new__(cls, (type, id, hw_code, modifiers, timestamp, event_string, is_text))
131 def __init__(self, type, id, hw_code, modifiers, timestamp, event_string, is_text):
132 list.__init__(self, (type, id, hw_code, modifiers, timestamp, event_string, is_text))
136 def _set_type(self, val):
138 type = property(fget=_get_type, fset=_set_type)
141 def _set_id(self, val):
143 id = property(fget=_get_id, fset=_set_id)
144 def _get_hw_code(self):
146 def _set_hw_code(self, val):
148 hw_code = property(fget=_get_hw_code, fset=_set_hw_code)
149 def _get_modifiers(self):
151 def _set_modifiers(self, val):
153 modifiers = property(fget=_get_modifiers, fset=_set_modifiers)
154 def _get_timestamp(self):
156 def _set_timestamp(self, val):
158 timestamp = property(fget=_get_timestamp, fset=_set_timestamp)
159 def _get_event_string(self):
161 def _set_event_string(self, val):
163 event_string = property(fget=_get_event_string, fset=_set_event_string)
164 def _get_is_text(self):
166 def _set_is_text(self, val):
168 is_text = property(fget=_get_is_text, fset=_set_is_text)
172 Builds a human readable representation of the event.
174 @return: Event description
178 if self.type == constants.KEY_PRESSED_EVENT:
180 elif self.type == constants.KEY_RELEASED_EVENT:
189 \tis_text: %s""" % (kind, self.hw_code, self.event_string, self.modifiers,
190 self.id, self.timestamp, self.is_text)
192 #------------------------------------------------------------------------------
194 class EventListenerMode(list):
195 def __new__(cls, synchronous, preemptive, global_):
196 return list.__new__(cls, (synchronous, preemptive, global_))
197 def __init__(self, synchronous, preemptive, global_):
198 list.__init__(self, (synchronous, preemptive, global_))
199 def _get_synchronous(self):
201 def _set_synchronous(self, val):
203 synchronous = property(fget=_get_synchronous, fset=_set_synchronous)
204 def _get_preemptive(self):
206 def _set_preemptive(self, val):
208 preemptive = property(fget=_get_preemptive, fset=_set_preemptive)
209 def _get_global_(self):
211 def _set_global_(self, val):
213 global_ = property(fget=_get_global_, fset=_set_global_)
215 #------------------------------------------------------------------------------
217 class KeyDefinition(list):
218 def __new__(cls, keycode, keysym, keystring, unused):
219 return list.__new__(cls, (keycode, keysym, keystring, unused))
220 def __init__(self, keycode, keysym, keystring, unused):
221 list.__init__(self, (keycode, keysym, keystring, unused))
222 def _get_keycode(self):
224 def _set_keycode(self, val):
226 keycode = property(fget=_get_keycode, fset=_set_keycode)
227 def _get_keysym(self):
229 def _set_keysym(self, val):
231 keysym = property(fget=_get_keysym, fset=_set_keysym)
232 def _get_keystring(self):
234 def _set_keystring(self, val):
236 keystring = property(fget=_get_keystring, fset=_set_keystring)
237 def _get_unused(self):
239 def _set_unused(self, val):
241 unused = property(fget=_get_unused, fset=_set_unused)
243 #------------------------------------------------------------------------------
245 class DeviceEventController(object):
247 The interface via which clients request notification of device
248 events, and through which device events may be simulated.
251 def __init__ (self, connection):
252 dec_object = connection.get_object(interfaces.ATSPI_REGISTRY_NAME,
253 interfaces.ATSPI_DEVICE_EVENT_CONTROLLER_PATH,
255 self._dec = _dbus.Interface(dec_object, interfaces.ATSPI_DEVICE_EVENT_CONTROLLER_INTERFACE)
257 def registerKeystrokeListener(self,
262 event_listener_mode):
264 Register to intercept keyboard events, and either pass them on
267 A DeviceEventListener which will intercept key events.
269 A list of KeyDefinition indicating which keys to intercept, or KEYSET_ALL_KEYS.
271 A ControllerEventMask bitmask for filtering the intercepted key events.
273 A list of KeyEventType
275 An EventListenerMode indicating whether the listener should receive
276 the events synchronously, potentially consuming them, or just
277 be notified asynchronously of those events that have been generated.
279 @return True if the DeviceEventListener was successfully registered
280 for the requested KeySet, ControllerEventMask, event types, and
281 EventListenerMode; otherwise returns False.
283 func = self._dec.get_dbus_method("registerKeystrokeListener")
284 return func(event_listener,
285 _dbus.Array(keys, signature="(iisi)"),
290 def deregisterKeystrokeListener(self,
296 De-register a previously registered keyboard eventlistener.
298 A DeviceEventListener which will intercept key events.
300 A list of KeyDefinition indicating which keys to intercept, or KEYSET_ALL_KEYS.
302 A ControllerEventMask filtering the intercepted key events.
304 A list of KeyEventType
306 func = self._dec.get_dbus_method("deregisterKeystrokeListener")
307 return func(event_listener,
312 def registerDeviceEventListener(self,
316 Register to intercept events, and either pass them on or consume
317 them. To listen to keyboard events use registerKeystrokeListener
320 A DeviceEventListener which will intercept events.
322 A list of EventType indicating which event types to listen for.
323 @return True if successful, False if not
325 func = self._dec.get_dbus_method("registerDeviceEventListener")
326 return func(event_listener, event_types)
328 def deregisterDeviceEventListener(self,
332 De-register a previously registered keyboard eventlistener.
334 A DeviceEventListener which will intercept events.
336 A List of EventType indicating which event types to stop listening
339 func = self._dec.get_dbus_method("deregisterDeviceEventListener")
340 return func(event_listener, event_types)
342 def notifyListenersSync(self, event):
344 Notify the Registry instance that a device event has taken place,
345 and allow pre-emptive listeners the opportunity to 'consume'
346 the event and thus prevent its further issuance/forwarding. This
347 is the method used by accessibility bridges to forward "toolkit
348 dependent" device events to the Registry from the application's
350 @return True if the event was consumed by a (pre-emptive) listener,
351 False if not (in which case the device event will be forwarded
352 as normal to any application which would normally receive it,
353 e.g. the currently active application in the case of mouse or
356 func = self._dec.get_dbus_method("notifyListenersSync")
359 def notifyListenersAsync(self, event):
361 Notify the Registry instance that a device event has taken place
362 in an asynchronous manner. This is the method used by accessibility
363 bridges to forward "toolkit dependent" device events to the Registry
364 from the application's process space. If the event in question
365 is potentially pre-emptible. notifyListenersSync should be used
368 func = self._dec.get_dbus_method("notifyListenersAsync")
371 def generateKeyboardEvent(self, keycode, keystring, type):
373 Synthesize a keyboard event.
375 A long integer indicating the keycode of the keypress to be synthesized.
377 an optional UTF-8 string indicating a complex keyboard input
380 A KeySynthType indicating the type of event(s) to be synthesized:
381 a key press, release, press-release pair, or a complex input
382 string (for instance from an internationalized or complex text
383 input method, or a composed character).
385 func = self._dec.get_dbus_method("generateKeyboardEvent")
386 return func(keycode, keystring, type)
388 def generateMouseEvent(self, x, y, name):
390 Synthesize a mouse event.
392 A long integer indicating the screen x coord for the mouse event.
394 A long integer indicating the screen y coord for the mouse event.
396 A string indicating the type of mouse event, e.g. "button1up"
398 func = self._dec.get_dbus_method("generateMouseEvent")
399 return func(x, y, name)
401 #------------------------------------------------------------------------------
403 class _TestDeviceEventController(object):
405 Used for testing when no Registry daemon is present.
408 def registerKeystrokeListener(self, event_listener, keys, event_mask, key_event_types, event_listener_mode):
411 def deregisterKeystrokeListener(self, event_listener, keys, event_mask, key_event_types):
414 def registerDeviceEventListener(self, event_listener, event_types):
417 def deregisterDeviceEventListener(self, event_listener, event_types):
420 def notifyListenersSync(self, event):
423 def notifyListenersAsync(self, event):
426 def generateKeyboardEvent(self, keycode, keystring, type):
429 def generateMouseEvent(self, x, y, name):
432 #------------------------------------------------------------------------------
434 class KeyboardDeviceEventListener(_service.Object):
436 Observes keyboard press and release events.
438 @ivar registry: The L{Registry} that created this observer
439 @type registry: L{Registry}
440 @ivar key_set: Set of keys to monitor
441 @type key_set: list of integer
442 @ivar mask: Watch for key events while these modifiers are held
444 @ivar kind: Kind of events to monitor
446 @ivar mode: Keyboard event mode
447 @type mode: Accessibility.EventListenerMode
450 _next_listener_id = 0
452 def _get_unique_path (self):
453 KeyboardDeviceEventListener._next_listener_id += 1
454 return "/org/freedesktop/atspi/keyeventlistener/%d" % (KeyboardDeviceEventListener._next_listener_id,)
456 def __init__(self, registry, synchronous, preemptive, global_):
458 Creates a mode object that defines when key events will be received from
459 the system. Stores all other information for later registration.
461 @param registry: The L{Registry} that created this observer
462 @type registry: L{Registry}
463 @param synchronous: Handle the key event synchronously?
464 @type synchronous: boolean
465 @param preemptive: Allow event to be consumed?
466 @type preemptive: boolean
467 @param global_: Watch for events on inaccessible applications too?
468 @type global_: boolean
470 self._upath = self._get_unique_path()
471 _service.Object.__init__(self, registry._bus, self._upath)
472 self.mode = EventListenerMode(synchronous, preemptive, global_)
473 self._registry = registry
475 def register(self, dc, key_set, mask, kind):
477 Starts keyboard event monitoring.
479 @param dc: Reference to a device controller
480 @type dc: Accessibility.DeviceEventController
481 @param key_set: Set of keys to monitor
482 @type key_set: list of integer
483 @param mask: Integer modifier mask or an iterable over multiple masks to
485 @type mask: integer, iterable, or None
486 @param kind: Kind of events to monitor
490 # check if the mask is iterable
493 # register a single integer if not
494 dc.registerKeystrokeListener(self._upath, key_set, mask, kind, self.mode)
497 dc.registerKeystrokeListener(self._upath, key_set, m, kind, self.mode)
499 def unregister(self, dc, key_set, mask, kind):
501 Stops keyboard event monitoring.
503 @param dc: Reference to a device controller
504 @type dc: Accessibility.DeviceEventController
505 @param key_set: Set of keys to monitor
506 @type key_set: list of integer
507 @param mask: Integer modifier mask or an iterable over multiple masks to
509 @type mask: integer, iterable, or None
510 @param kind: Kind of events to monitor
514 # check if the mask is iterable
517 # unregister a single integer if not
518 dc.deregisterKeystrokeListener(self._upath, key_set, mask, kind)
521 dc.deregisterKeystrokeListener(self._upath, key_set, m, kind)
523 @_service.method(dbus_interface=interfaces.ATSPI_DEVICE_EVENT_LISTENER_INTERFACE,
524 in_signature="(uinnisb)",
526 def notifyEvent(self, ev):
528 Notifies the L{Registry} that an event has occurred. Wraps the raw event
529 object in our L{Event} class to support automatic ref and unref calls. An
530 observer can return True to indicate this event should not be allowed to pass
531 to other AT-SPI observers or the underlying application.
533 @param ev: Keyboard event
534 @type ev: Accessibility.DeviceEvent
535 @return: Should the event be consumed (True) or allowed to pass on to other
536 AT-SPI observers (False)?
539 # TODO Find out where the exceptions are falling in to.
541 # wrap the device event
542 event = DeviceEvent(*ev)
543 return self._registry.handleDeviceEvent(event, self)
546 traceback.print_exc()
549 #END---------------------------------------------------------------------------