2009-27-09 Mark Doffman <mark.doffman@codethink.co.uk>
[platform/core/uifw/at-spi2-atk.git] / pyatspi / deviceevent.py
1 #Copyright (C) 2008 Codethink Ltd
2
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.
6
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.
14
15 import dbus as _dbus
16 import dbus.service as _service
17 import interfaces
18
19 from base import Enum as _Enum
20
21 #------------------------------------------------------------------------------
22
23 class PressedEventType(_Enum):
24         _enum_lookup = {
25                 0:'KEY_PRESSED_EVENT',
26                 1:'KEY_RELEASED_EVENT',
27                 2:'BUTTON_PRESSED_EVENT',
28                 3:'BUTTON_RELEASED_EVENT',
29         }
30
31 KEY_PRESSED_EVENT = PressedEventType(0)
32 KEY_RELEASED_EVENT = PressedEventType(1)
33 BUTTON_PRESSED_EVENT = PressedEventType(2)
34 BUTTON_RELEASED_EVENT = PressedEventType(3)
35
36 #------------------------------------------------------------------------------
37
38 class ControllerEventMask(_Enum):
39         _enum_lookup = {
40                 1:'KEY_PRESSED_EVENT_MASK',
41                 2:'KEY_RELEASED_EVENT_MASK',
42                 4:'BUTTON_PRESSED_EVENT_MASK',
43                 8:'BUTTON_RELEASED_EVENT_MASK',
44         }
45
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)
50
51 #------------------------------------------------------------------------------
52
53 class KeyEventType(_Enum):
54         _enum_lookup = {
55                 0:'KEY_PRESSED',
56                 1:'KEY_RELEASED',
57         }
58 KEY_PRESSED = KeyEventType(0)
59 KEY_RELEASED = KeyEventType(1)
60
61 #------------------------------------------------------------------------------
62
63 class KeySynthType(_Enum):
64         _enum_lookup = {
65                 0:'KEY_PRESS',
66                 1:'KEY_RELEASE',
67                 2:'KEY_PRESSRELEASE',
68                 3:'KEY_SYM',
69                 4:'KEY_STRING',
70         }
71
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)
77
78 #------------------------------------------------------------------------------
79
80 class ModifierType(_Enum):
81         _enum_lookup = {
82                 0:'MODIFIER_SHIFT',
83                 1:'MODIFIER_SHIFTLOCK',
84                 2:'MODIFIER_CONTROL',
85                 3:'MODIFIER_ALT',
86                 4:'MODIFIER_META',
87                 5:'MODIFIER_META2',
88                 6:'MODIFIER_META3',
89                 7:'MODIFIER_NUMLOCK',
90         }
91
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)
100
101 #------------------------------------------------------------------------------
102
103 class DeviceEvent(list):
104         """
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.
107
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
110                 system wide?
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
115         @type id: integer
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
128         """
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))
133                 self.consume = False
134         def _get_type(self):
135                 return self[0]
136         def _set_type(self, val):
137                 self[0] = val
138         type = property(fget=_get_type, fset=_set_type)
139         def _get_id(self):
140                 return self[1]
141         def _set_id(self, val):
142                 self[1] = val
143         id = property(fget=_get_id, fset=_set_id)
144         def _get_hw_code(self):
145                 return self[2]
146         def _set_hw_code(self, val):
147                 self[2] = val
148         hw_code = property(fget=_get_hw_code, fset=_set_hw_code)
149         def _get_modifiers(self):
150                 return self[3]
151         def _set_modifiers(self, val):
152                 self[3] = val
153         modifiers = property(fget=_get_modifiers, fset=_set_modifiers)
154         def _get_timestamp(self):
155                 return self[4]
156         def _set_timestamp(self, val):
157                 self[4] = val
158         timestamp = property(fget=_get_timestamp, fset=_set_timestamp)
159         def _get_event_string(self):
160                 return self[5]
161         def _set_event_string(self, val):
162                 self[5] = val
163         event_string = property(fget=_get_event_string, fset=_set_event_string)
164         def _get_is_text(self):
165                 return self[6]
166         def _set_is_text(self, val):
167                 self[6] = val
168         is_text = property(fget=_get_is_text, fset=_set_is_text)
169
170         def __str__(self):
171                 """
172                 Builds a human readable representation of the event.
173
174                 @return: Event description
175                 @rtype: string
176                 """
177                 import constants
178                 if self.type == constants.KEY_PRESSED_EVENT:
179                         kind = 'pressed'
180                 elif self.type == constants.KEY_RELEASED_EVENT:
181                         kind = 'released'
182                 return """\
183 %s
184 \thw_code: %d
185 \tevent_string: %s
186 \tmodifiers: %d
187 \tid: %d
188 \ttimestamp: %d
189 \tis_text: %s""" % (kind, self.hw_code, self.event_string, self.modifiers,
190                 self.id, self.timestamp, self.is_text)
191
192 #------------------------------------------------------------------------------
193
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):
200                 return self[0]
201         def _set_synchronous(self, val):
202                 self[0] = val
203         synchronous = property(fget=_get_synchronous, fset=_set_synchronous)
204         def _get_preemptive(self):
205                 return self[1]
206         def _set_preemptive(self, val):
207                 self[1] = val
208         preemptive = property(fget=_get_preemptive, fset=_set_preemptive)
209         def _get_global_(self):
210                 return self[2]
211         def _set_global_(self, val):
212                 self[2] = val
213         global_ = property(fget=_get_global_, fset=_set_global_)
214
215 #------------------------------------------------------------------------------
216
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):
223                 return self[0]
224         def _set_keycode(self, val):
225                 self[0] = val
226         keycode = property(fget=_get_keycode, fset=_set_keycode)
227         def _get_keysym(self):
228                 return self[1]
229         def _set_keysym(self, val):
230                 self[1] = val
231         keysym = property(fget=_get_keysym, fset=_set_keysym)
232         def _get_keystring(self):
233                 return self[2]
234         def _set_keystring(self, val):
235                 self[2] = val
236         keystring = property(fget=_get_keystring, fset=_set_keystring)
237         def _get_unused(self):
238                 return self[3]
239         def _set_unused(self, val):
240                 self[3] = val
241         unused = property(fget=_get_unused, fset=_set_unused)
242
243 #------------------------------------------------------------------------------
244
245 class DeviceEventController(object):
246         """
247         The interface via which clients request notification of device
248         events, and through which device events may be simulated.
249         """
250
251         def __init__ (self, connection):
252                 dec_object = connection.get_object(interfaces.ATSPI_REGISTRY_NAME,
253                                                    interfaces.ATSPI_DEVICE_EVENT_CONTROLLER_PATH,
254                                                    introspect=True)
255                 self._dec = _dbus.Interface(dec_object, interfaces.ATSPI_DEVICE_EVENT_CONTROLLER_INTERFACE)
256
257         def registerKeystrokeListener(self,
258                                       event_listener,
259                                       keys,
260                                       event_mask,
261                                       key_event_types,
262                                       event_listener_mode):
263                 """
264                 Register to intercept keyboard events, and either pass them on
265                 or consume them.
266                 @param : listener
267                 A DeviceEventListener which will intercept key events. 
268                 @param : keys
269                 A list of KeyDefinition indicating which keys to intercept, or KEYSET_ALL_KEYS.
270                 @param : mask
271                 A ControllerEventMask bitmask for filtering the intercepted key events.
272                 @param : type
273                 A list of KeyEventType
274                 @param : mode
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.
278
279                 @return True if the DeviceEventListener was successfully registered
280                 for the requested KeySet, ControllerEventMask, event types, and
281                 EventListenerMode; otherwise returns False.
282                 """
283                 func = self._dec.get_dbus_method("registerKeystrokeListener")
284                 return func(event_listener,
285                             _dbus.Array(keys, signature="(iisi)"),
286                             event_mask,
287                             key_event_types,
288                             event_listener_mode)
289
290         def deregisterKeystrokeListener(self,
291                                         event_listener,
292                                         keys,
293                                         event_mask,
294                                         key_event_types):
295                 """
296                 De-register a previously registered keyboard eventlistener.
297                 @param : listener
298                 A DeviceEventListener which will intercept key events.
299                 @param : keys
300                 A list of KeyDefinition indicating which keys to intercept, or KEYSET_ALL_KEYS.
301                 @param : mask
302                 A ControllerEventMask filtering the intercepted key events.
303                 @param : type
304                 A list of KeyEventType
305                 """
306                 func = self._dec.get_dbus_method("deregisterKeystrokeListener")
307                 return func(event_listener,
308                             keys,
309                             event_mask,
310                             key_event_types)
311
312         def registerDeviceEventListener(self,
313                                         event_listener,
314                                         event_types):
315                 """
316                 Register to intercept events, and either pass them on or consume
317                 them. To listen to keyboard events use registerKeystrokeListener
318                 instead. 
319                 @param : listener
320                 A DeviceEventListener which will intercept events.
321                 @param : typeseq
322                 A list of EventType indicating which event types to listen for.
323                 @return True if successful, False if not
324                 """
325                 func = self._dec.get_dbus_method("registerDeviceEventListener")
326                 return func(event_listener, event_types)
327
328         def deregisterDeviceEventListener(self,
329                                           event_listener,
330                                           event_types):
331                 """
332                 De-register a previously registered keyboard eventlistener.
333                 @param : listener
334                 A DeviceEventListener which will intercept events.
335                 @param : typeseq
336                 A List of EventType indicating which event types to stop listening
337                 for.
338                 """
339                 func = self._dec.get_dbus_method("deregisterDeviceEventListener")
340                 return func(event_listener, event_types)
341
342         def notifyListenersSync(self, event):
343                 """
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
349                 process space.
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
354                 keyboard events).
355                 """
356                 func = self._dec.get_dbus_method("notifyListenersSync")
357                 return func(event)
358
359         def notifyListenersAsync(self, event):
360                 """
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
366                 instead.
367                 """
368                 func = self._dec.get_dbus_method("notifyListenersAsync")
369                 return func(event)
370
371         def generateKeyboardEvent(self, keycode, keystring, type):
372                 """
373                 Synthesize a keyboard event.
374                 @param : keycode
375                 A long integer indicating the keycode of the keypress to be synthesized.
376                 @param : keystring
377                 an optional UTF-8 string indicating a complex keyboard input
378                 event.
379                 @param : type
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).
384                 """
385                 func = self._dec.get_dbus_method("generateKeyboardEvent")
386                 return func(keycode, keystring, type)
387
388         def generateMouseEvent(self, x, y, name):
389                 """
390                 Synthesize a mouse event.
391                 @param : x
392                 A long integer indicating the screen x coord for the mouse event.
393                 @param : y
394                 A long integer indicating the screen y coord for the mouse event.
395                 @param : name
396                 A string indicating the type of mouse event, e.g. "button1up"
397                 """
398                 func = self._dec.get_dbus_method("generateMouseEvent")
399                 return func(x, y, name)
400
401 #------------------------------------------------------------------------------
402
403 class _TestDeviceEventController(object):
404         """
405         Used for testing when no Registry daemon is present.
406         """
407
408         def registerKeystrokeListener(self, event_listener, keys, event_mask, key_event_types, event_listener_mode):
409                 return True
410
411         def deregisterKeystrokeListener(self, event_listener, keys, event_mask, key_event_types):
412                 pass
413
414         def registerDeviceEventListener(self, event_listener, event_types):
415                 return True
416
417         def deregisterDeviceEventListener(self, event_listener, event_types):
418                 pass
419
420         def notifyListenersSync(self, event):
421                 return False
422
423         def notifyListenersAsync(self, event):
424                 pass
425
426         def generateKeyboardEvent(self, keycode, keystring, type):
427                 pass
428
429         def generateMouseEvent(self, x, y, name):
430                 pass
431
432 #------------------------------------------------------------------------------
433
434 class KeyboardDeviceEventListener(_service.Object):
435         """
436         Observes keyboard press and release events.
437
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
443         @type mask: integer
444         @ivar kind: Kind of events to monitor
445         @type kind: integer
446         @ivar mode: Keyboard event mode
447         @type mode: Accessibility.EventListenerMode
448         """
449
450         _next_listener_id = 0
451
452         def _get_unique_path (self):
453                 KeyboardDeviceEventListener._next_listener_id += 1
454                 return "/org/freedesktop/atspi/keyeventlistener/%d" % (KeyboardDeviceEventListener._next_listener_id,)
455
456         def __init__(self, registry, synchronous, preemptive, global_):
457                 """
458                 Creates a mode object that defines when key events will be received from 
459                 the system. Stores all other information for later registration.
460
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
469                 """
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
474
475         def register(self, dc, key_set, mask, kind):
476                 """
477                 Starts keyboard event monitoring.
478
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
484                         unapply all at once
485                 @type mask: integer, iterable, or None
486                 @param kind: Kind of events to monitor
487                 @type kind: integer
488                 """
489                 try:
490                         # check if the mask is iterable
491                         iter(mask)
492                 except TypeError:
493                         # register a single integer if not
494                         dc.registerKeystrokeListener(self._upath, key_set, mask, kind, self.mode)
495                 else:
496                         for m in mask:
497                                 dc.registerKeystrokeListener(self._upath, key_set, m, kind, self.mode)
498
499         def unregister(self, dc, key_set, mask, kind):
500                 """
501                 Stops keyboard event monitoring.
502
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
508                         unapply all at once
509                 @type mask: integer, iterable, or None
510                 @param kind: Kind of events to monitor
511                 @type kind: integer
512                 """
513                 try:
514                         # check if the mask is iterable
515                         iter(mask)
516                 except TypeError:
517                         # unregister a single integer if not
518                         dc.deregisterKeystrokeListener(self._upath, key_set, mask, kind)
519                 else:
520                         for m in mask:
521                                 dc.deregisterKeystrokeListener(self._upath, key_set, m, kind)
522
523         @_service.method(dbus_interface=interfaces.ATSPI_DEVICE_EVENT_LISTENER_INTERFACE,
524                          in_signature="(uinnisb)",
525                          out_signature="b")
526         def notifyEvent(self, ev):
527                 """
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.
532
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)?
537                 @rtype: boolean
538                 """
539                 # TODO Find out where the exceptions are falling in to.
540                 try:
541                         # wrap the device event
542                         event = DeviceEvent(*ev)
543                         return self._registry.handleDeviceEvent(event, self)
544                 except Exception, e:
545                         import traceback
546                         traceback.print_exc()
547                         return False
548
549 #END---------------------------------------------------------------------------