2007-04-18 Li Yuan <li.yuan@sun.com>
[platform/core/uifw/at-spi2-atk.git] / pyatspi / event.py
1 '''
2 Wrapper classes for AT-SPI events and device events.
3
4 @author: Peter Parente
5 @organization: IBM Corporation
6 @copyright: Copyright (c) 2005, 2007 IBM Corporation
7 @license: LGPL
8
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Library General Public
11 License as published by the Free Software Foundation; either
12 version 2 of the License, or (at your option) any later version.
13
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 Library General Public License for more details.
18
19 You should have received a copy of the GNU Library General Public
20 License along with this library; if not, write to the
21 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.
23
24 Portions of this code originally licensed and copyright (c) 2005, 2007
25 IBM Corporation under the BSD license, available at
26 U{http://www.opensource.org/licenses/bsd-license.php}
27 '''
28 import constants
29
30 class DeviceEvent(object):
31   '''
32   Wraps an AT-SPI device event with a more Pythonic interface. Primarily adds
33   a consume attribute which can be used to cease propagation of a device event.
34   
35   @ivar consume: Should this event be consumed and not allowed to pass on to
36     observers further down the dispatch chain in this process or possibly
37     system wide?
38   @type consume: boolean
39   @ivar type: Kind of event, KEY_PRESSED_EVENT or KEY_RELEASED_EVENT
40   @type type: Accessibility.EventType
41   @ivar id: Serial identifier for this key event
42   @type id: integer
43   @ivar hw_code: Hardware scan code for the key
44   @type hw_code: integer
45   @ivar modifiers: Modifiers held at the time of the key event
46   @type modifiers: integer
47   @ivar timestamp: Time at which the event occurred relative to some platform
48     dependent starting point (e.g. XWindows start time)
49   @type timestamp: integer
50   @ivar event_string: String describing the key pressed (e.g. keysym)
51   @type event_string: string
52   @ivar is_text: Is the event representative of text to be inserted (True), or 
53     of a control key (False)?
54   @type is_text: boolean
55   '''
56   def __init__(self, event):
57     '''
58     Attaches event data to this object.
59     
60     @param event: Event object
61     @type event: Accessibility.DeviceEvent
62     '''
63     self.consume = False
64     self.type = event.type
65     self.id = event.id
66     self.hw_code = event.hw_code
67     self.modifiers = event.modifiers
68     self.timestamp = event.timestamp
69     self.event_string = event.event_string
70     self.is_text = event.is_text
71     
72   def __str__(self):
73     '''
74     Builds a human readable representation of the event.
75
76     @return: Event description
77     @rtype: string
78     '''
79     if self.type == constants.KEY_PRESSED_EVENT:
80       kind = 'pressed'
81     elif self.type == constants.KEY_RELEASED_EVENT:
82       kind = 'released'
83     return '''\
84 %s
85 \thw_code: %d
86 \tevent_string: %s
87 \tmodifiers: %d
88 \tid: %d
89 \ttimestamp: %d
90 \tis_text: %s''' % (kind, self.hw_code, self.event_string, self.modifiers,
91                     self.id, self.timestamp, self.is_text)
92
93 class Event(object):
94   '''
95   Wraps an AT-SPI event with a more Pythonic interface managing exceptions,
96   the differences in any_data across versions, and the reference counting of
97   accessibles provided with the event.
98   
99   @note: All unmarked attributes of this class should be considered public
100     readable and writable as the class is acting as a record object.
101     
102   @ivar consume: Should this event be consumed and not allowed to pass on to
103     observers further down the dispatch chain in this process?
104   @type consume: boolean
105   @ivar type: The type of the AT-SPI event
106   @type type: L{EventType}
107   @ivar detail1: First AT-SPI event parameter
108   @type detail1: integer
109   @ivar detail2: Second AT-SPI event parameter
110   @type detail2: integer
111   @ivar any_data: Extra AT-SPI data payload
112   @type any_data: object
113   @ivar host_application: Application owning the event source
114   @type host_application: Accessibility.Application
115   @ivar source_name: Name of the event source at the time of event dispatch
116   @type source_name: string
117   @ivar source_role: Role of the event source at the time of event dispatch
118   @type source_role: Accessibility.Role
119   @ivar source: Source of the event
120   @type source: Accessibility.Accessible
121   '''
122   def __init__(self, event):
123     '''
124     Extracts information from the provided event. If the event is a "normal" 
125     event, pulls the detail1, detail2, any_data, and source values out of the
126     given object and stores it in this object. If the event is a device event,
127     key ID is stored in detail1, scan code is stored in detail2, key name, 
128     key modifiers (e.g. ALT, CTRL, etc.), is text flag, and timestamp are 
129     stored as a 4-tuple in any_data, and source is None (since key events are
130     global).
131
132     @param event: Event from an AT-SPI callback
133     @type event: Accessibility.Event or Accessibility.DeviceEvent
134     '''
135     # always start out assuming no consume
136     self.consume = False
137     self.type = EventType(event.type)
138     self.detail1 = event.detail1
139     self.detail2 = event.detail2
140     # store the event source and increase the reference count since event 
141     # sources are borrowed references; the AccessibleMixin automatically
142     # decrements it later
143     self.source = event.source
144     self.source.ref()
145
146     # process any_data in a at-spi version independent manner
147     details = event.any_data.value()
148     try:
149       # see if we have a "new" any_data object which is an EventDetails struct
150       self.any_data = details.any_data.value()
151     except Exception:
152       # any kind of error means we have an "old" any_data object and None of
153       # the extra data so set them to None
154       self.any_data = details
155       self.host_application = None
156       self.source_name = None
157       self.source_role = None
158     else:
159       # the rest of the data should be here, so retrieve it
160       self.host_application = details.host_application
161       self.source_name = details.source_name
162       self.source_role = details.source_role
163
164   def __str__(self):
165     '''
166     Builds a human readable representation of the event including event type,
167     parameters, and source info.
168
169     @return: Event description
170     @rtype: string
171     '''
172     return '%s(%s, %s, %s)\n\tsource: %s\n\thost_application: %s' % \
173            (self.type, self.detail1, self.detail2, self.any_data,
174             self.source, self.host_application)
175   
176 class EventType(object):
177   '''
178   Wraps the AT-SPI event type string so its components can be accessed 
179   individually as klass (can't use the keyword class), major, minor, and detail 
180   (klass:major:minor:detail).
181   
182   @note: All attributes of an instance of this class should be considered 
183     public readable as it is acting a a struct.
184   @ivar klass: Most general event type identifier (object, window, mouse, etc.)
185   @type klass: string
186   @ivar major: Second level event type description
187   @type major: string
188   @ivar minor: Third level event type description
189   @type minor: string
190   @ivar detail: Lowest level event type description
191   @type detail: string
192   @ivar name: Full, unparsed event name as received from AT-SPI
193   @type name: string
194   @cvar format: Names of the event string components
195   @type format: 4-tuple of string
196   '''
197   format = ('klass', 'major', 'minor', 'detail')
198
199   def __init__(self, name):
200     '''    
201     Parses the full AT-SPI event name into its components
202     (klass:major:minor:detail). If the provided event name is an integer
203     instead of a string, then the event is really a device event.
204     
205     @param name: Full AT-SPI event name
206     @type name: string
207     @raise AttributeError: When the given event name is not a valid string 
208     '''
209     # get rid of any leading and trailing ':' separators
210     self.name = name.strip(':')
211     self.klass = None
212     self.major = None
213     self.minor = None
214     self.detail = None
215     
216     # split type according to delimiters
217     split = self.name.split(':')
218     # loop over all the components
219     for i in xrange(len(split)):
220       # store values of attributes in this object
221       setattr(self, self.format[i], split[i])
222       
223   def __str__(self):
224     '''
225     @return: Full event name as human readable representation of this event 
226       type
227     @rtype: string
228     '''
229     return self.name