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