Partial re-refactor of the accessibles registration code.
[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                 if self.type == constants.KEY_PRESSED_EVENT:
178                         kind = 'pressed'
179                 elif self.type == constants.KEY_RELEASED_EVENT:
180                         kind = 'released'
181                 return """\
182 %s
183 \thw_code: %d
184 \tevent_string: %s
185 \tmodifiers: %d
186 \tid: %d
187 \ttimestamp: %d
188 \tis_text: %s""" % (kind, self.hw_code, self.event_string, self.modifiers,
189                 self.id, self.timestamp, self.is_text)
190
191 #------------------------------------------------------------------------------
192
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):
199                 return self[0]
200         def _set_synchronous(self, val):
201                 self[0] = val
202         synchronous = property(fget=_get_synchronous, fset=_set_synchronous)
203         def _get_preemptive(self):
204                 return self[1]
205         def _set_preemptive(self, val):
206                 self[1] = val
207         preemptive = property(fget=_get_preemptive, fset=_set_preemptive)
208         def _get_global_(self):
209                 return self[2]
210         def _set_global_(self, val):
211                 self[2] = val
212         global_ = property(fget=_get_global_, fset=_set_global_)
213
214 #------------------------------------------------------------------------------
215
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):
222                 return self[0]
223         def _set_keycode(self, val):
224                 self[0] = val
225         keycode = property(fget=_get_keycode, fset=_set_keycode)
226         def _get_keysym(self):
227                 return self[1]
228         def _set_keysym(self, val):
229                 self[1] = val
230         keysym = property(fget=_get_keysym, fset=_set_keysym)
231         def _get_keystring(self):
232                 return self[2]
233         def _set_keystring(self, val):
234                 self[2] = val
235         keystring = property(fget=_get_keystring, fset=_set_keystring)
236         def _get_unused(self):
237                 return self[3]
238         def _set_unused(self, val):
239                 self[3] = val
240         unused = property(fget=_get_unused, fset=_set_unused)
241
242 #------------------------------------------------------------------------------
243
244 class DeviceEventController(object):
245         """
246         The interface via which clients request notification of device
247         events, and through which device events may be simulated.
248         """
249
250         def __init__ (self, connection):
251                 dec_object = connection.get_object(interfaces.ATSPI_REGISTRY_NAME,
252                                                    interfaces.ATSPI_DEVICE_EVENT_CONTROLLER_PATH,
253                                                    introspect=True)
254                 self._dec = _dbus.Interface(dec_object, interfaces.ATSPI_DEVICE_EVENT_CONTROLLER_INTERFACE)
255
256         def registerKeystrokeListener(self,
257                                       event_listener,
258                                       keys,
259                                       event_mask,
260                                       key_event_types,
261                                       event_listener_mode):
262                 """
263                 Register to intercept keyboard events, and either pass them on
264                 or consume them.
265                 @param : listener
266                 A DeviceEventListener which will intercept key events. 
267                 @param : keys
268                 A list of KeyDefinition indicating which keys to intercept, or KEYSET_ALL_KEYS.
269                 @param : mask
270                 A ControllerEventMask bitmask for filtering the intercepted key events.
271                 @param : type
272                 A list of KeyEventType
273                 @param : mode
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.
277
278                 @return True if the DeviceEventListener was successfully registered
279                 for the requested KeySet, ControllerEventMask, event types, and
280                 EventListenerMode; otherwise returns False.
281                 """
282                 func = self._dec.get_dbus_method("registerKeystrokeListener")
283                 return func(event_listener,
284                             keys,
285                             event_mask,
286                             key_event_types,
287                             event_listener_mode)
288
289         def deregisterKeystrokeListener(self,
290                                         event_listener,
291                                         keys,
292                                         event_mask,
293                                         key_event_types):
294                 """
295                 De-register a previously registered keyboard eventlistener.
296                 @param : listener
297                 A DeviceEventListener which will intercept key events.
298                 @param : keys
299                 A list of KeyDefinition indicating which keys to intercept, or KEYSET_ALL_KEYS.
300                 @param : mask
301                 A ControllerEventMask filtering the intercepted key events.
302                 @param : type
303                 A list of KeyEventType
304                 """
305                 func = self._dec.get_dbus_method("deregisterKeystrokeListener")
306                 return func(event_listener,
307                             keys,
308                             event_mask,
309                             key_event_types)
310
311         def registerDeviceEventListener(self,
312                                         event_listener,
313                                         event_types):
314                 """
315                 Register to intercept events, and either pass them on or consume
316                 them. To listen to keyboard events use registerKeystrokeListener
317                 instead. 
318                 @param : listener
319                 A DeviceEventListener which will intercept events.
320                 @param : typeseq
321                 A list of EventType indicating which event types to listen for.
322                 @return True if successful, False if not
323                 """
324                 func = self._dec.get_dbus_method("registerDeviceEventListener")
325                 return func(event_listener, event_types)
326
327         def deregisterDeviceEventListener(self,
328                                           event_listener,
329                                           event_types):
330                 """
331                 De-register a previously registered keyboard eventlistener.
332                 @param : listener
333                 A DeviceEventListener which will intercept events.
334                 @param : typeseq
335                 A List of EventType indicating which event types to stop listening
336                 for.
337                 """
338                 func = self._dec.get_dbus_method("deregisterDeviceEventListener")
339                 return func(event_listener, event_types)
340
341         def notifyListenersSync(self, event):
342                 """
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
348                 process space.
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
353                 keyboard events).
354                 """
355                 func = self._dec.get_dbus_method("notifyListenersSync")
356                 return func(event)
357
358         def notifyListenersAsync(self, event):
359                 """
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
365                 instead.
366                 """
367                 func = self._dec.get_dbus_method("notifyListenersAsync")
368                 return func(event)
369
370         def generateKeyboardEvent(self, keycode, keystring, type):
371                 """
372                 Synthesize a keyboard event.
373                 @param : keycode
374                 A long integer indicating the keycode of the keypress to be synthesized.
375                 @param : keystring
376                 an optional UTF-8 string indicating a complex keyboard input
377                 event.
378                 @param : type
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).
383                 """
384                 func = self._dec.get_dbus_method("generateKeyboardEvent")
385                 return func(keycode, keystring, type)
386
387         def generateMouseEvent(self, x, y, name):
388                 """
389                 Synthesize a mouse event.
390                 @param : x
391                 A long integer indicating the screen x coord for the mouse event.
392                 @param : y
393                 A long integer indicating the screen y coord for the mouse event.
394                 @param : name
395                 A string indicating the type of mouse event, e.g. "button1up"
396                 """
397                 func = self._dec.get_dbus_method("generateMouseEvent")
398                 return func(x, y, name)
399
400 #------------------------------------------------------------------------------
401
402 class _TestDeviceEventController(object):
403         """
404         Used for testing when no Registry daemon is present.
405         """
406
407         def registerKeystrokeListener(self, event_listener, keys, event_mask, key_event_types, event_listener_mode):
408                 return True
409
410         def deregisterKeystrokeListener(self, event_listener, keys, event_mask, key_event_types):
411                 pass
412
413         def registerDeviceEventListener(self, event_listener, event_types):
414                 return True
415
416         def deregisterDeviceEventListener(self, event_listener, event_types):
417                 pass
418
419         def notifyListenersSync(self, event):
420                 return False
421
422         def notifyListenersAsync(self, event):
423                 pass
424
425         def generateKeyboardEvent(self, keycode, keystring, type):
426                 pass
427
428         def generateMouseEvent(self, x, y, name):
429                 pass
430
431 #------------------------------------------------------------------------------
432
433 class KeyboardDeviceEventListener(_service.Object):
434         """
435         Observes keyboard press and release events.
436
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
442         @type mask: integer
443         @ivar kind: Kind of events to monitor
444         @type kind: integer
445         @ivar mode: Keyboard event mode
446         @type mode: Accessibility.EventListenerMode
447         """
448
449         _next_listener_id = 0
450
451         def _get_unique_path (self):
452                 KeyboardDeviceEventListener._next_listener_id += 1
453                 return "/org/freedesktop/atspi/keyeventlistener/%d" % (KeyboardDeviceEventListener._next_listener_id,)
454
455         def __init__(self, registry, synchronous, preemptive, global_):
456                 """
457                 Creates a mode object that defines when key events will be received from 
458                 the system. Stores all other information for later registration.
459
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
468                 """
469                 self._upath = self._get_unique_path()
470                 _service.Object.__init__(self, registry._bus, self._upath)
471                 self.mode = EventListenerMode(synchronous, preemptive, global_)
472
473         def register(self, dc, key_set, mask, kind):
474                 """
475                 Starts keyboard event monitoring.
476
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
482                         unapply all at once
483                 @type mask: integer, iterable, or None
484                 @param kind: Kind of events to monitor
485                 @type kind: integer
486                 """
487                 try:
488                         # check if the mask is iterable
489                         iter(mask)
490                 except TypeError:
491                         # register a single integer if not
492                         dc.registerKeystrokeListener(self._upath, key_set, mask, kind, self.mode)
493                 else:
494                         for m in mask:
495                                 dc.registerKeystrokeListener(self._upath, key_set, m, kind, self.mode)
496
497         def unregister(self, dc, key_set, mask, kind):
498                 """
499                 Stops keyboard event monitoring.
500
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
506                         unapply all at once
507                 @type mask: integer, iterable, or None
508                 @param kind: Kind of events to monitor
509                 @type kind: integer
510                 """
511                 try:
512                         # check if the mask is iterable
513                         iter(mask)
514                 except TypeError:
515                         # unregister a single integer if not
516                         dc.deregisterKeystrokeListener(self._upath, key_set, mask, kind)
517                 else:
518                         for m in mask:
519                                 dc.deregisterKeystrokeListener(self._upath, key_set, m, kind)
520
521         @_service.method(dbus_interface=interfaces.ATSPI_DEVICE_EVENT_LISTENER_INTERFACE,
522                          in_signature="(uinnisb)",
523                          out_signature="b")
524         def notifyEvent(self, ev):
525                 """
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.
530
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)?
535                 @rtype: boolean
536                 """
537                 # wrap the device event
538                 ev = event.DeviceEvent(ev)
539                 return self.registry.handleDeviceEvent(ev, self)
540
541 #END---------------------------------------------------------------------------