/usr/share/sugar/activities/Physics.activity/olpcgames/gtkEvent.py is in sugar-physics-activity 7+dfsg-1.1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | """gtkEvent.py: translate GTK events into Pygame events."""
import pygtk
pygtk.require('2.0')
import gtk
import gobject
import pygame
from olpcgames import eventwrap
import logging
log = logging.getLogger( 'olpcgames.gtkevent' )
##log.setLevel( logging.DEBUG )
class _MockEvent(object):
"""Used to inject key-repeat events on the gtk side."""
def __init__(self, keyval):
self.keyval = keyval
class Translator(object):
"""Utility class to translate GTK events into Pygame events
The Translator object interprets incoming GTK events and generates
Pygame events in the eventwrap module's queue as a result.
It also handles generating Pygame style key-repeat events
by synthesizing them via a GTK timer.
"""
key_trans = {
'Alt_L': pygame.K_LALT,
'Alt_R': pygame.K_RALT,
'Control_L': pygame.K_LCTRL,
'Control_R': pygame.K_RCTRL,
'Shift_L': pygame.K_LSHIFT,
'Shift_R': pygame.K_RSHIFT,
'Super_L': pygame.K_LSUPER,
'Super_R': pygame.K_RSUPER,
'KP_Page_Up' : pygame.K_KP9,
'KP_Page_Down' : pygame.K_KP3,
'KP_End' : pygame.K_KP1,
'KP_Home' : pygame.K_KP7,
'KP_Up' : pygame.K_KP8,
'KP_Down' : pygame.K_KP2,
'KP_Left' : pygame.K_KP4,
'KP_Right' : pygame.K_KP6,
}
mod_map = {
pygame.K_LALT: pygame.KMOD_LALT,
pygame.K_RALT: pygame.KMOD_RALT,
pygame.K_LCTRL: pygame.KMOD_LCTRL,
pygame.K_RCTRL: pygame.KMOD_RCTRL,
pygame.K_LSHIFT: pygame.KMOD_LSHIFT,
pygame.K_RSHIFT: pygame.KMOD_RSHIFT,
}
def __init__(self, mainwindow, mouselistener=None):
"""Initialise the Translator with the windows to which to listen"""
# _inner_evb is Mouselistener
self._mainwindow = mainwindow
if mouselistener is None:
mouselistener = mainwindow
self._inner_evb = mouselistener
# Need to set our X event masks so we see mouse motion and stuff --
mainwindow.set_events(
gtk.gdk.KEY_PRESS_MASK | \
gtk.gdk.KEY_RELEASE_MASK \
)
self._inner_evb.set_events(
gtk.gdk.POINTER_MOTION_MASK | \
gtk.gdk.POINTER_MOTION_HINT_MASK | \
gtk.gdk.BUTTON_MOTION_MASK | \
gtk.gdk.BUTTON_PRESS_MASK | \
gtk.gdk.BUTTON_RELEASE_MASK
)
# Callback functions to link the event systems
mainwindow.connect('unrealize', self._quit)
mainwindow.connect('key_press_event', self._keydown)
mainwindow.connect('key_release_event', self._keyup)
self._inner_evb.connect('button_press_event', self._mousedown)
self._inner_evb.connect('button_release_event', self._mouseup)
self._inner_evb.connect('motion-notify-event', self._mousemove)
# You might need to do this
mainwindow.set_flags(gtk.CAN_FOCUS)
self._inner_evb.set_flags(gtk.CAN_FOCUS)
# Internal data
self.__stopped = False
self.__keystate = [0] * 323
self.__button_state = [0,0,0]
self.__mouse_pos = (0,0)
self.__repeat = (None, None)
self.__held = set()
self.__held_time_left = {}
self.__held_last_time = {}
self.__tick_id = None
#print "translator initialized"
self._inner_evb.connect( 'expose-event', self.do_expose_event )
# screen = gtk.gdk.screen_get_default()
# screen.connect( 'size-changed', self.do_resize_event )
self._inner_evb.connect( 'configure-event', self.do_resize_event )
def do_expose_event(self, event, widget):
"""Handle exposure event (trigger redraw by gst)"""
log.info( 'Expose event: %s', event )
from olpcgames import eventwrap
eventwrap.post( eventwrap.Event( eventwrap.pygame.VIDEOEXPOSE ))
return True
def do_resize_event( self, activity, event ):
"""Our screen (actually, the default screen) has resized"""
log.info( 'Resize event: %s %s', activity, event )
log.info( 'Event values: %s', (event.width,event.height) )
# from olpcgames import eventwrap
# # shouldn't the activity's window have this information too?
# eventwrap.post(
# eventwrap.Event(
# eventwrap.pygame.VIDEORESIZE,
# dict(size=(event.width,event.height), width=event.width, height=event.height)
# )
# )
return False # continue processing
def hook_pygame(self):
"""Hook the various Pygame features so that we implement the event APIs"""
# Pygame should be initialized. Hijack their key and mouse methods
pygame.key.get_pressed = self._get_pressed
pygame.key.set_repeat = self._set_repeat
pygame.mouse.get_pressed = self._get_mouse_pressed
pygame.mouse.get_pos = self._get_mouse_pos
import eventwrap
eventwrap.install()
def _quit(self, data=None):
self.__stopped = True
eventwrap.post(eventwrap.Event(pygame.QUIT))
def _keydown(self, widget, event):
key = event.keyval
log.debug( 'key down: %s', key )
if key in self.__held:
return True
else:
if self.__repeat[0] is not None:
self.__held_last_time[key] = pygame.time.get_ticks()
self.__held_time_left[key] = self.__repeat[0]
self.__held.add(key)
return self._keyevent(widget, event, pygame.KEYDOWN)
def _keyup(self, widget, event):
key = event.keyval
if self.__repeat[0] is not None:
if key in self.__held:
# This is possibly false if set_repeat() is called with a key held
del self.__held_time_left[key]
del self.__held_last_time[key]
self.__held.discard(key)
return self._keyevent(widget, event, pygame.KEYUP)
def _keymods(self):
"""Extract the keymods as they stand currently."""
mod = 0
for key_val, mod_val in self.mod_map.iteritems():
mod |= self.__keystate[key_val] and mod_val
return mod
def _keyevent(self, widget, event, type):
key = gtk.gdk.keyval_name(event.keyval)
if key is None:
# No idea what this key is.
return False
keycode = None
if key in self.key_trans:
keycode = self.key_trans[key]
elif hasattr(pygame, 'K_'+key.upper()):
keycode = getattr(pygame, 'K_'+key.upper())
elif hasattr(pygame, 'K_'+key.lower()):
keycode = getattr(pygame, 'K_'+key.lower())
elif key == 'XF86Start':
# view source request, specially handled...
self._mainwindow.view_source()
else:
print 'Key %s unrecognized'%key
if keycode is not None:
if type == pygame.KEYDOWN:
mod = self._keymods()
self.__keystate[keycode] = type == pygame.KEYDOWN
if type == pygame.KEYUP:
mod = self._keymods()
ukey = unichr(gtk.gdk.keyval_to_unicode(event.keyval))
if ukey == '\000':
ukey = ''
evt = eventwrap.Event(type, key=keycode, unicode=ukey, mod=mod)
assert evt.key, evt
self._post(evt)
return True
def _get_pressed(self):
"""Retrieve map/array of which keys are currently depressed (held down)"""
return self.__keystate
def _get_mouse_pressed(self):
"""Return three-element array of which mouse-buttons are currently depressed (held down)"""
return self.__button_state
def _mousedown(self, widget, event):
self.__button_state[event.button-1] = 1
return self._mouseevent(widget, event, pygame.MOUSEBUTTONDOWN)
def _mouseup(self, widget, event):
self.__button_state[event.button-1] = 0
return self._mouseevent(widget, event, pygame.MOUSEBUTTONUP)
def _mouseevent(self, widget, event, type):
evt = eventwrap.Event(type,
button=event.button,
pos=(event.x, event.y))
self._post(evt)
return True
def _mousemove(self, widget, event):
# From http://www.learningpython.com/2006/07/25/writing-a-custom-widget-using-pygtk/
# if this is a hint, then let's get all the necessary
# information, if not it's all we need.
if event.is_hint:
x, y, state = event.window.get_pointer()
else:
x = event.x
y = event.y
state = event.state
rel = (x - self.__mouse_pos[0],
y - self.__mouse_pos[1])
self.__mouse_pos = (x, y)
self.__button_state = [
state & gtk.gdk.BUTTON1_MASK and 1 or 0,
state & gtk.gdk.BUTTON2_MASK and 1 or 0,
state & gtk.gdk.BUTTON3_MASK and 1 or 0,
]
evt = eventwrap.Event(pygame.MOUSEMOTION,
pos=self.__mouse_pos,
rel=rel,
buttons=self.__button_state)
self._post(evt)
return True
def _tick(self):
"""Generate synthetic events for held-down keys"""
cur_time = pygame.time.get_ticks()
for key in self.__held:
delta = cur_time - self.__held_last_time[key]
self.__held_last_time[key] = cur_time
self.__held_time_left[key] -= delta
if self.__held_time_left[key] <= 0:
self.__held_time_left[key] = self.__repeat[1]
self._keyevent(None, _MockEvent(key), pygame.KEYDOWN)
return True
def _set_repeat(self, delay=None, interval=None):
"""Set the key-repetition frequency for held-down keys"""
if delay is not None and self.__repeat[0] is None:
self.__tick_id = gobject.timeout_add(10, self._tick)
elif delay is None and self.__repeat[0] is not None:
gobject.source_remove(self.__tick_id)
self.__repeat = (delay, interval)
def _get_mouse_pos(self):
"""Retrieve the current mouse position as a two-tuple of integers"""
return self.__mouse_pos
def _post(self, evt):
try:
eventwrap.post(evt)
except pygame.error, e:
if str(e) == 'Event queue full':
print "Event queue full!"
pass
else:
raise e
|