Package pyLinAcc :: Module Event
[hide private]
[frames] | no frames]

Source Code for Module pyLinAcc.Event

  1  ''' 
  2  Defines classes for monitoring and wrapping AT-SPI events. Hides most of the 
  3  details of registering and unregistering for events behind a simple interface. 
  4   
  5  @author: Peter Parente 
  6  @organization: IBM Corporation 
  7  @copyright: Copyright (c) 2005, 2007 IBM Corporation 
  8  @license: The BSD License 
  9   
 10  All rights reserved. This program and the accompanying materials are made  
 11  available under the terms of the BSD license which accompanies 
 12  this distribution, and is available at  
 13  U{http://www.opensource.org/licenses/bsd-license.php} 
 14  ''' 
 15   
 16  # these modules are generated from IDL by the __init__ module 
 17  # see http://developer.gnome.org/doc/guides/corba/html/c561.html about POA 
 18  import Accessibility, Accessibility__POA 
 19  import pyLinAcc, Constants, Interfaces 
 20  import weakref, traceback 
 21   
22 -class Event(object):
23 ''' 24 Wraps an AT-SPI event with a more Pythonic interface. Both AT-SPI device 25 events (e.g. keyboard) and "normal" AT-SPI events (everything else) are 26 handled by this class. 27 28 @note: All unmarked attributes of this class should be considered public 29 readable and writable as the class is acting as a record object. 30 @ivar consume: Should this event be consumed and not allowed to pass on to 31 observers further down the dispatch chain? 32 @type consume: boolean 33 @ivar type: The type of the AT-SPI event 34 @type type: L{EventType} 35 @ivar detail1: First AT-SPI event parameter 36 @type detail1: integer 37 @ivar detail2: Second AT-SPI event parameter 38 @type detail2: integer 39 @ivar any_data: Extra AT-SPI data payload 40 @type any_data: object 41 @ivar source: Source of the event 42 @type source: Accessibility.Accessible 43 '''
44 - def __init__(self, event):
45 ''' 46 Extracts information from the provided event. If the event is a "normal" 47 event, pulls the detail1, detail2, any_data, and source values out of the 48 given object and stores it in this object. If the event is a device event, 49 key ID is stored in detail1, scan code is stored in detail2, key name, 50 key modifiers (e.g. ALT, CTRL, etc.), is text flag, and timestamp are 51 stored as a 4-tuple in any_data, and source is None (since key events are 52 global). 53 54 @param event: Event from an AT-SPI callback 55 @type event: Accessibility.Event or Accessibility.DeviceEvent 56 ''' 57 # always start out assuming no consume 58 self.consume = False 59 try: 60 # wrapping will fail if the event is actually a device event 61 self.type = EventType(event.type) 62 self.detail1 = event.detail1 63 self.detail2 = event.detail2 64 # store the event source and increase the reference count since event 65 # sources are borrowed references; the AccessibleMixin automatically 66 # decrements it later 67 self.source = event.source 68 self.source.ref() 69 # process any_data in a at-spi version independent manner 70 self.any_data = event.any_data.value() 71 try: 72 self.any_data = self.any_data.any_data.value() 73 except Exception: 74 pass 75 try: 76 # increase the any_data reference count since the objects are borrowed 77 # references; the AccessibleMixin automatically decrements it later 78 self.any_data.ref() 79 except AttributeError: 80 pass 81 except AttributeError: 82 # a device event, make up the type 83 self.type = EventType(Constants.device_type_to_name[event.type]) 84 self.detail1 = event.id 85 self.detail2 = event.hw_code 86 # pack all other data into a tuple in any_data 87 self.any_data = (event.event_string, event.modifiers, event.is_text, 88 event.timestamp) 89 # key events have no source 90 self.source = None
91
92 - def __str__(self):
93 ''' 94 Builds a human readable representation of the event including event type, 95 parameters, and, optionally, source info. This method is used by an 96 L{AEMonitor} to buffer string representations of events. 97 98 @return: Event description 99 @rtype: string 100 ''' 101 try: 102 s = '%s(%s, %s, %s)\n\tsource: %s\n\tapplication: %s' % \ 103 (self.type.asString(), self.detail1, self.detail2, self.any_data, 104 self.source, self.source.getApplication()) 105 except Exception: 106 if self.any_data is None: 107 s = '%s(%s, %s, None)' % \ 108 (self.type.asString(), self.detail1, self.detail2) 109 else: 110 s = '%s(%s, %s, %s, %s, %s, %s)' % \ 111 ((self.type.asString(), self.detail1, self.detail2)+self.any_data) 112 return s
113
114 -class EventType(object):
115 ''' 116 Wraps the AT-SPI event type string so its components can be accessed 117 individually as klass (can't use the keyword class), major, minor, and detail 118 (klass:major:minor:detail). 119 120 @note: All attributes of an instance of this class should be considered public 121 readable as it is acting a a struct. 122 @ivar klass: Most general event type identifier (object, window, mouse, etc.) 123 @type klass: string 124 @ivar major: Second level event type description 125 @type major: string 126 @ivar minor: Third level event type description 127 @type minor: string 128 @ivar detail: Lowest level event type description 129 @type detail: string 130 @ivar name: Full, unparsed event name as received from AT-SPI 131 @type name: string 132 @cvar format: Names of the event string components 133 @type format: 4-tuple of string 134 ''' 135 format = ('klass', 'major', 'minor', 'detail')
136 - def __init__(self, name):
137 ''' 138 Parses the full AT-SPI event name into its components 139 (klass:major:minor:detail). If the provided event name is an integer instead 140 of a string, then the event is really a device event. An exception is raised 141 in this case so L{Event} knows to convert the device event integer constant 142 to a keyboard event name string. 143 144 @param name: Full AT-SPI event name 145 @type name: string 146 @raise AttributeError: When the given event name is not a valid string 147 ''' 148 # get rid of any leading and trailing ':' separators 149 self.name = name.strip(':') 150 self.klass = None 151 self.major = None 152 self.minor = None 153 self.detail = None 154 155 # split type according to delimiters 156 split = self.name.split(':') 157 # loop over all the components 158 for i in xrange(len(split)): 159 # store values of attributes in this object 160 setattr(self, self.format[i], split[i])
161
162 - def __str__(self):
163 ''' 164 @return: Full event name as human readable representation of this event type 165 @rtype: string 166 ''' 167 return self.asString()
168
169 - def asString(self):
170 ''' 171 Builds a human readable representation of the event type. 172 173 @return: Event type description 174 @rtype: string 175 ''' 176 return self.name
177
178 -def _createObserver(manager, et):
179 ''' 180 Factory function that builds the right kind of observer based on whether 181 events to monitor are at the device level or not. 182 183 @param manager: Manager that will own this observer 184 @type manager: L{Manager} 185 @param et: Type of event the created observer will monitor 186 @type et: L{EventType} 187 @return: Created observer object 188 @rtype: L{Observer} 189 ''' 190 if et.klass == 'keyboard': 191 # keyboard event types need to be monitored by a device observer 192 ob = DeviceObserver(manager) 193 else: 194 # all others use the regular observer 195 ob = EventObserver(manager) 196 return ob
197
198 -class Observer(object):
199 ''' 200 Parent class for all event observers. Dispatches all received events to the 201 L{Manager} that created this L{Observer}. Provides basic reference counting 202 functionality needed by L{Manager} to determine when an L{Observer} can be 203 released for garbage collection. 204 205 The reference counting provided by this class is independent of the reference 206 counting used by CORBA. Keeping the counts separate makes it easier for the 207 L{Manager} to detect when an L{Observer} can be freed in the 208 L{Manager._unregisterObserver} method. 209 210 @ivar manager: Reference to the L{Manager} that created this L{Observer} 211 @type manager: L{Manager} 212 @ivar ref_count: Reference count on this L{Observer} 213 @type ref_count: integer 214 '''
215 - def __init__(self, manager):
216 ''' 217 Stores a reference to the creating L{Manager}. Intializes the reference 218 count on this object to zero. 219 220 @param manager: The L{Manager} that created this observer 221 @type manager: L{Manager} 222 ''' 223 self.manager = manager 224 self.ref_count = 0
225
226 - def clientRef(self):
227 ''' 228 Increments the L{pyLinAcc} reference count on this L{Observer} by one. This 229 method is called when a new client is registered in L{Manager} to receive 230 notification of an event type monitored by this L{Observer}. 231 ''' 232 self.ref_count += 1
233
234 - def clientUnref(self):
235 ''' 236 Decrements the L{pyLinAcc} reference count on this L{Observer} by one. This 237 method is called when a client is unregistered in L{Manager} to stop 238 receiving notifications of an event type monitored by this L{Observer}. 239 ''' 240 self.ref_count -= 1
241
242 - def getClientRefCount(self):
243 ''' 244 @return: Current L{pyLinAcc} reference count on this L{Observer} 245 @rtype: integer 246 ''' 247 return self.ref_count
248
249 - def ref(self):
250 '''Required by CORBA. Does nothing.''' 251 pass
252
253 - def unref(self):
254 '''Required by CORBA. Does nothing.''' 255 pass 256
257 -class DeviceObserver(Observer, Accessibility__POA.DeviceEventListener):
258 ''' 259 Observes keyboard press and release events. The settings for the listener 260 mode are hard coded so that key presses and releases can be consumed by any 261 client registered with the L{Manager} to observe these events. 262 263 @ivar mode: Keyboard event mode (currently hardwired as non-preemptive and 264 asynchronous) 265 @type mode: Accessibility.EventListenerMode 266 '''
267 - def __init__(self, manager):
268 ''' 269 Creates a mode object that defines when key events will be received from 270 the system. 271 272 @param manager: The L{Manager} that created this observer 273 @type manager: L{Manager} 274 ''' 275 Observer.__init__(self, manager) 276 self.mode = Accessibility.EventListenerMode() 277 self.mode.preemptive = True 278 self.mode.synchronous = True 279 self.mode._global = False
280
281 - def register(self, registry, name):
282 ''' 283 Starts keyboard event monitoring on all keys and key combinations. The 284 event type to be monitored (key press or key release) is given by the event 285 name. See L{Manager.addClient} for valid event names. 286 287 @param registry: Registry where the device event controller is defined 288 @type registry: Accessibility.Registry 289 @param name: L{pyLinAcc.Constants} keyboard event name 290 @type name: string 291 ''' 292 mask = 0 293 # map the pretty keyboard event name string to the real AT-SPI constant 294 type = [Constants.name_to_device_type[name]] 295 # create an AT-SPI device event controller 296 dc = registry.getDeviceEventController() 297 # register for all possible key combos (plain key, key+shift, key+alt, ...) 298 while mask <= (1 << Accessibility.MODIFIER_NUMLOCK): 299 dc.registerKeystrokeListener(self._this(), [], mask, type, self.mode) 300 mask += 1
301
302 - def unregister(self, registry, name):
303 ''' 304 Stops keyboard event monitoring on all keys and key combinations. The event 305 type to stop monitoring (key press or key release) is given by the event 306 name. See L{Manager.addClient} for possible event names. 307 308 @param registry: Registry where the device event controller is defined 309 @type registry: Accessibility.Registry 310 @param name: Pretty AT-SPI event name 311 @type name: string 312 ''' 313 mask = 0 314 type = [Constants.name_to_device_type[name]] 315 dc = registry.getDeviceEventController() 316 # unregister all possible key combos 317 while mask <= (1 << Accessibility.MODIFIER_NUMLOCK): 318 dc.deregisterKeystrokeListener(self._this(), [], mask, type) 319 mask += 1
320
321 - def queryInterface(self, repo_id):
322 ''' 323 Reports that this class only implements the AT-SPI DeviceEventListener 324 interface. Required by AT-SPI. 325 326 @param repo_id: Request for an interface 327 @type repo_id: string 328 @return: The underlying CORBA object for the device event listener 329 @rtype: Accessibility.EventListener 330 ''' 331 if repo_id == Constants.DEVICEEVENT_LISTENER_IDL: 332 return self._this() 333 else: 334 return None
335
336 - def notifyEvent(self, event):
337 ''' 338 Notifies the L{Manager} that an event has occurred. Wraps the raw event 339 object in our L{Event} class to support automatic ref and unref calls. An 340 observer can set the L{Event} consume flag to True to indicate this event 341 should not be allowed to pass to other AT-SPI observers or the underlying 342 application. 343 344 @param event: Low-level AT-SPI event (keyboard, mouse) 345 @type event: Accessibility.DeviceEvent 346 @return: Should the event be consumed (True) or allowed to pass on to other 347 AT-SPI observers (False)? 348 @rtype: boolean 349 ''' 350 wrap = Event(event) 351 try: 352 self.manager.handleEvent(wrap) 353 except Exception: 354 pass 355 return wrap.consume
356
357 -class EventObserver(Observer, Accessibility__POA.EventListener):
358 ''' 359 Observes all non-keyboard AT-SPI events. 360 '''
361 - def register(self, registry, name):
362 ''' 363 Starts monitoring for the given event. See L{Manager.addClient} for 364 possible event names. 365 366 @param registry: Registry on which the listener will be registered 367 @type registry: Accessibility.Registry 368 @param name: AT-SPI event name 369 @type name: string 370 ''' 371 registry.registerGlobalEventListener(self._this(), name)
372
373 - def unregister(self, registry, name):
374 ''' 375 Stops monitoring for the given event. See L{Manager.addClient} for possible 376 event names. 377 378 @param registry: Registry on which the listener will be registered 379 @type registry: Accessibility.Registry 380 @param name: AT-SPI event name 381 @type name: string 382 ''' 383 registry.deregisterGlobalEventListener(self._this(), name)
384
385 - def queryInterface(self, repo_id):
386 ''' 387 Reports that this class only implements the AT-SPI DeviceEventListener 388 interface. Required by AT-SPI. 389 390 @param repo_id: Request for an interface 391 @type repo_id: string 392 @return: The underlying CORBA object for the device event listener 393 @rtype: Accessibility.EventListener 394 ''' 395 if repo_id == EVENT_LISTENER_IDL: 396 return self._this() 397 else: 398 return None
399
400 - def notifyEvent(self, event):
401 ''' 402 Notifies the L{Manager} that an event has occurred. Wraps the raw event 403 object in our L{Event} class to support automatic ref and unref calls. 404 Aborts on any exception indicating the event could not be wrapped. 405 406 @param event: High-level AT-SPI event (anything but keyboard, mouse) 407 @type event: Accessibility.Event 408 ''' 409 try: 410 ev = Event(event) 411 except Exception: 412 return 413 try: 414 self.manager.handleEvent(ev) 415 except Exception: 416 pass
417
418 -class Manager(object):
419 ''' 420 Manages all event L{Observer}s. Allows clients to register and unregister 421 callbacks for observed events. Acts as a point of serialization for events so 422 events of the same klass (see L{EventType}) can be gauranteed to be delivered 423 to the registered clients in the order they were registered. No such guarantee 424 is made across event klasses. 425 426 @ivar registry: Reference to the Gnome Accessibility.Registry 427 @type registry: Accessibility.Registry 428 @ivar clients: Registered Clients to be notified about events 429 @type clients: dictionary {event name : client callable} 430 @ivar observers: L{Observer} objects registered to monitor events 431 @type observers: dictionary {event klass : L{Observer}} 432 '''
433 - def __init__(self):
434 ''' 435 Stores references to the Accessibility.Registery and creates the empty 436 client and observer dictionaries. 437 ''' 438 self.registry = pyLinAcc.Registry 439 self.dev = self.registry.getDeviceEventController() 440 self.clients = {} 441 self.observers = {}
442
443 - def _registerClients(self, client, name):
444 ''' 445 Internal method that recursively associates a client with AT-SPI event 446 names. Allows a clientto incompletely specify an event name in order to 447 register for subevents without specifying their full names manually. See 448 L{Manager.addClient} for valid event names. 449 450 @param client: Client callback to receive event notifications 451 @type client: callable 452 @param name: Partial or full event name 453 @type name: string 454 ''' 455 try: 456 # look for an event name in our event tree dictionary 457 events = Constants.event_tree[name] 458 except KeyError: 459 # if the event name doesn't exist, it's a leaf event meaning there are 460 # no subtypes for that event 461 # add this client to the list of clients already in the dictionary 462 # using the event name as the key; if there are no clients yet for this 463 # event, insert an empty list into the dictionary before appending 464 # the client 465 et = EventType(name) 466 clients = self.clients.setdefault(et.name, []) 467 try: 468 clients.index(client) 469 except ValueError: 470 # only allow a particular client to register once 471 clients.append(client) 472 self._registerObserver(name) 473 return 474 # if the event name does exist in the tree, there are subevents for this 475 # event; loop through them calling this method again to get to the leaf 476 # events 477 for e in events: 478 self._registerClients(client, e)
479
480 - def _unregisterClients(self, client, name):
481 ''' 482 Internal method that recursively unassociates a client with AT-SPI event 483 names. Allows a client to incompletely specify an event name in order to 484 unregister for subevents without specifying their full names manually. 485 486 @param client: Client callback to receive event notifications 487 @type client: callable 488 @param name: Partial or full event name 489 @type name: string 490 ''' 491 missed = False 492 try: 493 # look for an event name in our event tree dictionary 494 events = Constants.event_tree[name] 495 except KeyError: 496 try: 497 # if the event name doesn't exist, it's a leaf event meaning there are 498 # no subtypes for that event 499 # get the list of registered clients and try to remove the one provided 500 et = EventType(name) 501 clients = self.clients[et.name] 502 clients.remove(client) 503 self._unregisterObserver(name) 504 except (ValueError, KeyError): 505 # ignore any exceptions indicating the client is not registered 506 missed = True 507 return missed 508 # if the event name does exist in the tree, there are subevents for this 509 # event; loop through them calling this method again to get to the leaf 510 # events 511 for e in events: 512 missed |= self._unregisterClients(client, e) 513 return missed
514
515 - def _registerObserver(self, name):
516 ''' 517 Creates a new L{Observer} to watch for events of the given type or returns 518 the existing observer if one is already registered. One L{Observer} 519 is created for each event type which has no subevents. 520 521 @param name: Name of the event to observe 522 @type name: string 523 @return: L{Observer} object that is monitoring the event 524 @rtype: L{Observer} 525 ''' 526 et = EventType(name) 527 try: 528 # see if an observer already exists for this event 529 ob = self.observers[et.name] 530 except KeyError: 531 # build a new observer if one does not exist 532 ob = _createObserver(self, et) 533 # we have to register for the raw name because it may be different from 534 # the parsed name determined by EventType (e.g. trailing ':' might be 535 # missing) 536 ob.register(self.registry, name) 537 self.observers[et.name] = ob 538 ob.clientRef() 539 return ob
540
541 - def _unregisterObserver(self, name):
542 ''' 543 Destroys an existing L{Observer} for the given event type only if no clients 544 are registered for the events it is monitoring. 545 546 @param name: Name of the event to observe 547 @type name: string 548 @raise KeyError: When an observer for the given event is not regist 549 ''' 550 et = EventType(name) 551 # see if an observer already exists for this event 552 ob = self.observers[et.name] 553 ob.clientUnref() 554 if ob.getClientRefCount() == 0: 555 ob.unregister(self.registry, name) 556 del self.observers[et.name]
557
558 - def close(self):
559 ''' 560 Shuts down the L{Manager} by destroying all observers. 561 ''' 562 for name, ob in self.observers.items(): 563 ob.unregister(self.registry, name)
564
565 - def addClient(self, client, *names):
566 ''' 567 Registers a new client callback for the given event names. Supports 568 registration for all subevents if only partial event name is specified. 569 Do not include a trailing colon. The valid event names are the following: 570 571 terminal 572 terminal:line-changed 573 terminal:columncount-changed 574 terminal:linecount-changed 575 terminal:application-changed', 576 terminal:charwidth-changed 577 document:load-complete 578 document:reload 579 document:load-stopped 580 document:content-changed 581 document:attributes-changed 582 object 583 object:bounds-changed 584 object:link-selected 585 object:property-change 586 object:state-changed 587 object:children-changed 588 object:visible-data-changed 589 object:selection-changed 590 object:model-changed 591 object:active-descendant-changed 592 object:row-inserted 593 object:row-reordered 594 object:row-deleted 595 object:column-inserted 596 object:column-reordered 597 object:column-deleted 598 object:attributes-changed 599 object:text-attributes-changed 600 object:text-selection-changed 601 object:text-caret-moved 602 object:text-changed 603 object:text-changed:insert 604 object:text-changed:delete 605 object:property-change 606 object:property-change:accessible-parent 607 object:property-change:accessible-name 608 object:property-change:accessible-description 609 object:property-change:accessible-value 610 object:property-change:accessible-role 611 object:property-change:accessible-table-caption 612 object:property-change:accessible-table-column-description 613 object:property-change:accessible-table-column-header 614 object:property-change:accessible-table-row-description 615 object:property-change:accessible-table-row-header 616 object:property-change:accessible-table-summary 617 object:children-changed 618 object:children-changed:add 619 object:children-changed:remove 620 object:state-changed 621 object:state-changed:active 622 object:state-changed:armed 623 object:state-changed:busy 624 object:state-changed:checked 625 object:state-changed:collapsed 626 object:state-changed:defunct 627 object:state-changed:editable 628 object:state-changed:enabled 629 object:state-changed:expandable 630 object:state-changed:expanded 631 object:state-changed:focusable 632 object:state-changed:focused 633 object:state-changed:has-tooltip 634 object:state-changed:horizontal 635 object:state-changed:iconified 636 object:state-changed:indeterminate 637 object:state-changed:invalid 638 object:state-changed:last-defined 639 object:state-changed:manages-descendants 640 object:state-changed:modal 641 object:state-changed:multi-line 642 object:state-changed:multiselectable 643 object:state-changed:opaque 644 object:state-changed:pressed 645 object:state-changed:resizable 646 object:state-changed:selectable 647 object:state-changed:selected 648 object:state-changed:sensitive 649 object:state-changed:showing 650 object:state-changed:single-line 651 object:state-changed:stale 652 object:state-changed:transient 653 object:state-changed:vertical 654 object:state-changed:visible 655 ... 656 mouse 657 mouse:abs 658 mouse:rel 659 mouse:button 660 mouse:button 661 mouse:button:1p 662 mouse:button:1r 663 mouse:button:2p 664 mouse:button:2r 665 mouse:button:3p 666 mouse:button:3r 667 window 668 window:minimize 669 window:maximize 670 window:restore 671 window:close 672 window:create 673 window:reparent 674 window:desktop-create 675 window:desktop-destroy 676 window:activate 677 window:deactivate 678 window:raise 679 window:lower 680 window:move 681 window:resize 682 window:shade 683 window:unshade 684 window:restyle 685 focus 686 keyboard 687 keyboard:press 688 keyboard:release 689 690 For example, 'object' will register for all object events, 691 'object:property-change' will register for all property change events, 692 and 'object:property-change:accessible-parent' will register only for the 693 parent property change event. 694 695 Registered clients will not be automatically removed when the client dies. 696 To ensure the client is properly garbage collected, call 697 L{Manager.removeClient}. 698 699 @param client: Callable to be invoked when the event occurs 700 @type client: callable 701 @param names: List of full or partial event names 702 @type names: list of string 703 ''' 704 for name in names: 705 # store the callback for each specific event name 706 self._registerClients(client, name)
707
708 - def removeClient(self, client, *names):
709 ''' 710 Unregisters an existing client callback for the given event names. Supports 711 unregistration for all subevents if only partial event name is specified. 712 Do not include a trailing colon. 713 714 This method must be called to ensure a client registered by 715 L{Manager.addClient} is properly garbage collected. 716 717 @param client: Client callback to remove 718 @type client: callable 719 @param names: List of full or partial event names 720 @type names: list of string 721 @return: Were event names specified for which the given client was not 722 registered? 723 @rtype: boolean 724 ''' 725 missed = False 726 for name in names: 727 # remove the callback for each specific event name 728 missed |= self._unregisterClients(client, name) 729 return missed
730
731 - def generateKeyEvent(self, key_code, press=True):
732 ''' 733 Synthesizes a key press or key release to be sent to the foreground window 734 with the input focus. 735 736 @param key_code: Key code representing the physical key on the keyboard to 737 press 738 @type key_code: integer 739 @param press: True to send a key press, False to send a key release 740 @type press: boolean 741 ''' 742 if press: 743 kind = Constants.KEY_PRESS 744 else: 745 kind = Constants.KEY_RELEASE 746 self.dev.generateKeyboardEvent(key_code, '', kind)
747
748 - def handleEvent(self, event):
749 ''' 750 Handles an AT-SPI event. The default implementation immediately calls 751 L{_dispatchEvent} to send the event on to the registered clients. Override 752 this method to implement some other default behavior (e.g. queueing events 753 for later processing. 754 755 As of 9/12/05, the faster this method returns, the better, as AT-SPI event 756 handling appears to be done synchronously across the Gnome desktop. If this 757 method stalls, the entire desktop will freeze. 758 759 @param event: Wrapped AT-SPI event 760 @type event: L{Event} 761 ''' 762 self._dispatchEvent(event)
763
764 - def _dispatchEvent(self, event):
765 ''' 766 Dispatches L{Event}s to registered clients. Clients are called in the order 767 they were registered for the given AT-SPI event. If any client sets the 768 L{Event} consume flag to True, callbacks cease immediately for that event. 769 For keyboard events, this also implies that no other observer registered 770 with AT-SPI across the system will receive the event nor will the 771 application with the input focus. 772 773 @param event: Wrapped AT-SPI event 774 @type event: L{Event} 775 ''' 776 try: 777 # try to get the client registered for this event type 778 clients = self.clients[event.type.name] 779 except KeyError: 780 # if there's an exception, we might have a keyboard event constant 781 # which needs to be mapped to our keyboard event string names 782 try: 783 clients = self.clients[Constants.device_type_to_name[event.type.name]] 784 except KeyError: 785 return 786 # make the call to each client 787 for client in clients: 788 try: 789 client(event) 790 except Exception: 791 traceback.print_exc() 792 if event.consume: 793 # don't allow further processing if the consume flag is set 794 break
795