* event.py: Make EventType a string descendent, it is now IDL
[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     try:
164       # if we received an accessible, be sure to increment the ref count
165       self.any_data.ref()
166     except AttributeError:
167       pass
168
169   def __str__(self):
170     '''
171     Builds a human readable representation of the event including event type,
172     parameters, and source info.
173
174     @return: Event description
175     @rtype: string
176     '''
177     return '%s(%s, %s, %s)\n\tsource: %s\n\thost_application: %s' % \
178            (self.type, self.detail1, self.detail2, self.any_data,
179             self.source, self.host_application)
180   
181 class EventType(str):
182   '''
183   Wraps the AT-SPI event type string so its components can be accessed 
184   individually as klass (can't use the keyword class), major, minor, and detail 
185   (klass:major:minor:detail).
186   
187   @note: All attributes of an instance of this class should be considered 
188     public readable as it is acting a a struct.
189   @ivar klass: Most general event type identifier (object, window, mouse, etc.)
190   @type klass: string
191   @ivar major: Second level event type description
192   @type major: string
193   @ivar minor: Third level event type description
194   @type minor: string
195   @ivar detail: Lowest level event type description
196   @type detail: string
197   @ivar name: Full, unparsed event name as received from AT-SPI
198   @type name: string
199   @cvar format: Names of the event string components
200   @type format: 4-tuple of string
201   '''
202   format = ('klass', 'major', 'minor', 'detail')
203
204   def __init__(self, name):
205     '''    
206     Parses the full AT-SPI event name into its components
207     (klass:major:minor:detail). If the provided event name is an integer
208     instead of a string, then the event is really a device event.
209     
210     @param name: Full AT-SPI event name
211     @type name: string
212     @raise AttributeError: When the given event name is not a valid string 
213     '''
214     # get rid of any leading and trailing ':' separators
215     self.value = name.strip(':')
216     self.name = self.value # Backward compatability
217     self.klass = None
218     self.major = None
219     self.minor = None
220     self.detail = None
221     
222     # split type according to delimiters
223     split = self.value.split(':')
224     # loop over all the components
225     for i in xrange(len(split)):
226       # store values of attributes in this object
227       setattr(self, self.format[i], split[i])
228