import time import weakref import pygame def _getWeakRef(fn): if not hasattr(fn, "__func__"): return None if hasattr(fn, "__self__"): return weakref.WeakMethod(fn) return weakref.ref(fn) class EventError(Exception): pass class _Events: def __init__(self): self._signals = {} def _ClearUnreferenced(self): def isempty(r): return r() is not None for signal, sigs in self._signals: self._signals[signal] = filter(isempty, sigs) def listen(self, signal, fn): ref = _getWeakRef(fn) if ref is None or ref() is None: raise EventError("Expected a function callback.") if not signal in self._signals: self._signals[signal] = [] if not ref in self._signals[signal]: self._signal[signal].append(ref) def unlisten(self, signal, fn): ref = _getWeakRef(fn) if res is None or ref() is None: return # Not a function. Nothing to do. if signal in self._signals: if ref in self._signals[signal]: self._signals[signal].remove(ref) def unlisten_all(self, signal): if signal in self._signals: del self._signals[signal] def emit(self, signal, data): if signal in self._signals: for r in self._signals[signal]: fn = r() if fn is not None: fn(signal, data) self._ClearUnreferenced() # Create the actual Events instance :) Events = _Events() _ClickDelayMax=500 # in Milliseconds _DOWNKEYS=[] _DOWNMBUTTONS=[] _DOWNJBUTTONS=[] def _WatchKey(key): global _DOWNKEYS for k in _DOWNKEYS: if k[0] == key: return # Already watching. Technically, this should never happen. _DOWNKEYS.append((key, int(round(time.time()*1000)))) def _ReleaseKey(key): global _DOWNKEYS, _ClickDelayMax tick = int(round(time.time()*1000)) for k in _DOWNKEYS: if k[0] == key: lastTick = k[1] _DOWNKEYS.remove(k) if tick - lastTick <= _ClickDelayMax: Events.emit("KEYPRESSED", {key:key, mod:pygame.key.get_mods()}) return # Done. # We found nothing, boss. def _WatchButton(device, button): global _DOWNMBUTTONS, _DOWNJBUTTONS tick = int(round(time.time()*1000)) btnsrc = _DOWNMBUTTONS if device >= 0: btnsrc = _DOWNJBUTTONS for b in btnsrc: if b[0] == device and b[1] == button: return # Already Watching... btnsrc.append((device, button, tick)) def _ReleaseButton(device, button): global _DOWNMBUTTONS, _DOWNJBUTTONS, _ClickDelayMax tick = int(round(time.time()*1000)) btnsrc = _DOWNMBUTTONS if device >= 0: btnsrc = _DOWNJBUTTONS for b in btnsrc: if b[0] == device and b[1] == button: lastTick = b[2] btnsrc.remove(b) if tick - lastTick <= _ClickDelayMax: if device >= 0: Events.emit("JOYBUTTONPRESSED", {joy:device, button:button}) else: Events.emit("MOUSEBUTTONPRESSED", {pos:pygame.mouse.get_pos(), button:button}) return # Done. # We found nothing, boss. def pollEmitter(): global Events, _WatchKey, _ReleaseKey, _WatchButton, _ReleaseButton for event in pygame.event.get(): if event.type == pygame.QUIT: Events.emit("QUIT", {}) elif event.type == pygame.KEYDOWN: _WatchKey(event.key) Events.emit("KEYDOWN", {unicode:event.unicode, key:event.key, mod:event.mod}) elif event.type == pygame.KEYUP: Events.emit("KEYUP", {key:event.key, mod:event.mod}) _ReleaseKey(event.key) elif event.type == pygame.MOUSEMOTION: Events.emit("MOUSEMOTION", {pos:event.pos, rel:event.rel, buttons:event.buttons}) elif event.type == pygame.MOUSEBUTTONUP: Events.emit("MOUSEBUTTONUP", {pos:event.pos, button:event.button}) _ReleaseButton(-1, event.button) elif event.type == pygame.MOUSEBUTTONDOWN: _WatchButton(-1, event.button) Events.emit("MOUSEBUTTONDOWN", {pos:event.pos, button:event.button}) elif event.type == pygame.VIDEORESIZE: Events.emit("VIDEORESIZE", {size:event.size, w:event.w, h:event.h}) elif event.type == pygame.VIDEOEXPOSE: Events.emit("VIDEOEXPOSE", {}) elif event.type == pygame.JOYAXISMOTION: Events.emit("JOYAXISMOTION", {joy:event.joy, axis:event.axis, value:event.value}) elif event.type == pygame.JOYBALLMOTION: Events.emit("JOYBALLMOTION", {joy:event.joy, ball:event.ball, res:event.rel}) elif event.type == pygame.JOYHATMOTION: Events.emit("JOYHATMOTION", {joy:event.joy, hat:event.hat, value:event.value}) elif event.type == pygame.JOYBUTTONUP: Events.emit("JOYBUTTONUP", {joy:event.joy, button:event.button}) _ReleaseButton(event.joy, event.button) elif event.type == pygame.JOYBUTTONDOWN: _WatchButton(event.joy, event.button) Events.emit("JOYBUTTONDOWN", {joy:event.joy, button:event.button}) else: Events.emit("PYGUSER_{}".format(event.code), {})