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
177 if self.type == constants.KEY_PRESSED_EVENT:
179 elif self.type == constants.KEY_RELEASED_EVENT:
188 \tis_text: %s""" % (kind, self.hw_code, self.event_string, self.modifiers,
189 self.id, self.timestamp, self.is_text)
191 #------------------------------------------------------------------------------
193 class EventListenerMode(list):
194 def __new__(cls, synchronous, preemptive, global_):
195 return list.__new__(cls, (synchronous, preemptive, global_))
196 def __init__(self, synchronous, preemptive, global_):
197 list.__init__(self, (synchronous, preemptive, global_))
198 def _get_synchronous(self):
200 def _set_synchronous(self, val):
202 synchronous = property(fget=_get_synchronous, fset=_set_synchronous)
203 def _get_preemptive(self):
205 def _set_preemptive(self, val):
207 preemptive = property(fget=_get_preemptive, fset=_set_preemptive)
208 def _get_global_(self):
210 def _set_global_(self, val):
212 global_ = property(fget=_get_global_, fset=_set_global_)
214 #------------------------------------------------------------------------------
216 class KeyDefinition(list):
217 def __new__(cls, keycode, keysym, keystring, unused):
218 return list.__new__(cls, (keycode, keysym, keystring, unused))
219 def __init__(self, keycode, keysym, keystring, unused):
220 list.__init__(self, (keycode, keysym, keystring, unused))
221 def _get_keycode(self):
223 def _set_keycode(self, val):
225 keycode = property(fget=_get_keycode, fset=_set_keycode)
226 def _get_keysym(self):
228 def _set_keysym(self, val):
230 keysym = property(fget=_get_keysym, fset=_set_keysym)
231 def _get_keystring(self):
233 def _set_keystring(self, val):
235 keystring = property(fget=_get_keystring, fset=_set_keystring)
236 def _get_unused(self):
238 def _set_unused(self, val):
240 unused = property(fget=_get_unused, fset=_set_unused)
242 #------------------------------------------------------------------------------
244 class DeviceEventController(object):
246 The interface via which clients request notification of device
247 events, and through which device events may be simulated.
250 def __init__ (self, connection):
251 dec_object = connection.get_object(interfaces.ATSPI_REGISTRY_NAME,
252 interfaces.ATSPI_DEVICE_EVENT_CONTROLLER_PATH,
254 self._dec = _dbus.Interface(dec_object, interfaces.ATSPI_DEVICE_EVENT_CONTROLLER_INTERFACE)
256 def registerKeystrokeListener(self,
261 event_listener_mode):
263 Register to intercept keyboard events, and either pass them on
266 A DeviceEventListener which will intercept key events.
268 A list of KeyDefinition indicating which keys to intercept, or KEYSET_ALL_KEYS.
270 A ControllerEventMask bitmask for filtering the intercepted key events.
272 A list of KeyEventType
274 An EventListenerMode indicating whether the listener should receive
275 the events synchronously, potentially consuming them, or just
276 be notified asynchronously of those events that have been generated.
278 @return True if the DeviceEventListener was successfully registered
279 for the requested KeySet, ControllerEventMask, event types, and
280 EventListenerMode; otherwise returns False.
282 func = self._dec.get_dbus_method("registerKeystrokeListener")
283 return func(event_listener,
289 def deregisterKeystrokeListener(self,
295 De-register a previously registered keyboard eventlistener.
297 A DeviceEventListener which will intercept key events.
299 A list of KeyDefinition indicating which keys to intercept, or KEYSET_ALL_KEYS.
301 A ControllerEventMask filtering the intercepted key events.
303 A list of KeyEventType
305 func = self._dec.get_dbus_method("deregisterKeystrokeListener")
306 return func(event_listener,
311 def registerDeviceEventListener(self,
315 Register to intercept events, and either pass them on or consume
316 them. To listen to keyboard events use registerKeystrokeListener
319 A DeviceEventListener which will intercept events.
321 A list of EventType indicating which event types to listen for.
322 @return True if successful, False if not
324 func = self._dec.get_dbus_method("registerDeviceEventListener")
325 return func(event_listener, event_types)
327 def deregisterDeviceEventListener(self,
331 De-register a previously registered keyboard eventlistener.
333 A DeviceEventListener which will intercept events.
335 A List of EventType indicating which event types to stop listening
338 func = self._dec.get_dbus_method("deregisterDeviceEventListener")
339 return func(event_listener, event_types)
341 def notifyListenersSync(self, event):
343 Notify the Registry instance that a device event has taken place,
344 and allow pre-emptive listeners the opportunity to 'consume'
345 the event and thus prevent its further issuance/forwarding. This
346 is the method used by accessibility bridges to forward "toolkit
347 dependent" device events to the Registry from the application's
349 @return True if the event was consumed by a (pre-emptive) listener,
350 False if not (in which case the device event will be forwarded
351 as normal to any application which would normally receive it,
352 e.g. the currently active application in the case of mouse or
355 func = self._dec.get_dbus_method("notifyListenersSync")
358 def notifyListenersAsync(self, event):
360 Notify the Registry instance that a device event has taken place
361 in an asynchronous manner. This is the method used by accessibility
362 bridges to forward "toolkit dependent" device events to the Registry
363 from the application's process space. If the event in question
364 is potentially pre-emptible. notifyListenersSync should be used
367 func = self._dec.get_dbus_method("notifyListenersAsync")
370 def generateKeyboardEvent(self, keycode, keystring, type):
372 Synthesize a keyboard event.
374 A long integer indicating the keycode of the keypress to be synthesized.
376 an optional UTF-8 string indicating a complex keyboard input
379 A KeySynthType indicating the type of event(s) to be synthesized:
380 a key press, release, press-release pair, or a complex input
381 string (for instance from an internationalized or complex text
382 input method, or a composed character).
384 func = self._dec.get_dbus_method("generateKeyboardEvent")
385 return func(keycode, keystring, type)
387 def generateMouseEvent(self, x, y, name):
389 Synthesize a mouse event.
391 A long integer indicating the screen x coord for the mouse event.
393 A long integer indicating the screen y coord for the mouse event.
395 A string indicating the type of mouse event, e.g. "button1up"
397 func = self._dec.get_dbus_method("generateMouseEvent")
398 return func(x, y, name)
400 #------------------------------------------------------------------------------
402 class _TestDeviceEventController(object):
404 Used for testing when no Registry daemon is present.
407 def registerKeystrokeListener(self, event_listener, keys, event_mask, key_event_types, event_listener_mode):
410 def deregisterKeystrokeListener(self, event_listener, keys, event_mask, key_event_types):
413 def registerDeviceEventListener(self, event_listener, event_types):
416 def deregisterDeviceEventListener(self, event_listener, event_types):
419 def notifyListenersSync(self, event):
422 def notifyListenersAsync(self, event):
425 def generateKeyboardEvent(self, keycode, keystring, type):
428 def generateMouseEvent(self, x, y, name):
431 #------------------------------------------------------------------------------
433 class KeyboardDeviceEventListener(_service.Object):
435 Observes keyboard press and release events.
437 @ivar registry: The L{Registry} that created this observer
438 @type registry: L{Registry}
439 @ivar key_set: Set of keys to monitor
440 @type key_set: list of integer
441 @ivar mask: Watch for key events while these modifiers are held
443 @ivar kind: Kind of events to monitor
445 @ivar mode: Keyboard event mode
446 @type mode: Accessibility.EventListenerMode
449 _next_listener_id = 0
451 def _get_unique_path (self):
452 KeyboardDeviceEventListener._next_listener_id += 1
453 return "/org/freedesktop/atspi/keyeventlistener/%d" % (KeyboardDeviceEventListener._next_listener_id,)
455 def __init__(self, registry, synchronous, preemptive, global_):
457 Creates a mode object that defines when key events will be received from
458 the system. Stores all other information for later registration.
460 @param registry: The L{Registry} that created this observer
461 @type registry: L{Registry}
462 @param synchronous: Handle the key event synchronously?
463 @type synchronous: boolean
464 @param preemptive: Allow event to be consumed?
465 @type preemptive: boolean
466 @param global_: Watch for events on inaccessible applications too?
467 @type global_: boolean
469 self._upath = self._get_unique_path()
470 _service.Object.__init__(self, registry._bus, self._upath)
471 self.mode = EventListenerMode(synchronous, preemptive, global_)
473 def register(self, dc, key_set, mask, kind):
475 Starts keyboard event monitoring.
477 @param dc: Reference to a device controller
478 @type dc: Accessibility.DeviceEventController
479 @param key_set: Set of keys to monitor
480 @type key_set: list of integer
481 @param mask: Integer modifier mask or an iterable over multiple masks to
483 @type mask: integer, iterable, or None
484 @param kind: Kind of events to monitor
488 # check if the mask is iterable
491 # register a single integer if not
492 dc.registerKeystrokeListener(self._upath, key_set, mask, kind, self.mode)
495 dc.registerKeystrokeListener(self._upath, key_set, m, kind, self.mode)
497 def unregister(self, dc, key_set, mask, kind):
499 Stops keyboard event monitoring.
501 @param dc: Reference to a device controller
502 @type dc: Accessibility.DeviceEventController
503 @param key_set: Set of keys to monitor
504 @type key_set: list of integer
505 @param mask: Integer modifier mask or an iterable over multiple masks to
507 @type mask: integer, iterable, or None
508 @param kind: Kind of events to monitor
512 # check if the mask is iterable
515 # unregister a single integer if not
516 dc.deregisterKeystrokeListener(self._upath, key_set, mask, kind)
519 dc.deregisterKeystrokeListener(self._upath, key_set, m, kind)
521 @_service.method(dbus_interface=interfaces.ATSPI_DEVICE_EVENT_LISTENER_INTERFACE,
522 in_signature="(uinnisb)",
524 def notifyEvent(self, ev):
526 Notifies the L{Registry} that an event has occurred. Wraps the raw event
527 object in our L{Event} class to support automatic ref and unref calls. An
528 observer can return True to indicate this event should not be allowed to pass
529 to other AT-SPI observers or the underlying application.
531 @param ev: Keyboard event
532 @type ev: Accessibility.DeviceEvent
533 @return: Should the event be consumed (True) or allowed to pass on to other
534 AT-SPI observers (False)?
537 # wrap the device event
538 ev = event.DeviceEvent(ev)
539 return self.registry.handleDeviceEvent(ev, self)
541 #END---------------------------------------------------------------------------