Files
2014-07-07 18:18:56 -07:00

518 lines
16 KiB
Python

import pygame
import pygame.locals as pygame_consts
from UncasedDict import UncasedDict
DICT_EVENT_IB = {
"QUIT": pygame_consts.QUIT,
"ACTIVE_EVENT": pygame_consts.ACTIVEEVENT,
"KEY_DOWN": pygame_consts.KEYDOWN,
"KEY_UP": pygame_consts.KEYUP,
"MOUSE_MOTION": pygame_consts.MOUSEMOTION,
"MOUSE_BUTTON_UP": pygame_consts.MOUSEBUTTONUP,
"MOUSE_BUTTON_DOWN": pygame_consts.MOUSEBUTTONDOWN,
"JOY_AXIS_MOTION": pygame_consts.JOYAXISMOTION,
"JOY_BALL_MOTION": pygame_consts.JOYBALLMOTION,
"JOY_HAT_MOTION": pygame_consts.JOYHATMOTION,
"JOY_BUTTON_UP": pygame_consts.JOYBUTTONUP,
"JOY_BUTTOND_OWN": pygame_consts.JOYBUTTONDOWN,
"VIDEO_RESIZE": pygame_consts.VIDEORESIZE,
"VIDEO_EXPOSE": pygame_consts.VIDEOEXPOSE,
# "USER_EVENT": pygame_consts.USEREVENT,
# think of begin_step, step and end_step
}
DICT_KEYS = {
r"BACKSPACE": pygame_consts.K_BACKSPACE,
r"TAB": pygame_consts.K_TAB,
r"CLEAR": pygame_consts.K_CLEAR,
r"RETURN": pygame_consts.K_RETURN,
r"PAUSE": pygame_consts.K_PAUSE,
r"ESCAPE": pygame_consts.K_ESCAPE,
r"SPACE": pygame_consts.K_SPACE,
r"EXCLAIM": pygame_consts.K_EXCLAIM,
r"QUOTEDBL": pygame_consts.K_QUOTEDBL,
r"HASH": pygame_consts.K_HASH,
r"DOLLAR": pygame_consts.K_DOLLAR,
r"AMPERSAND": pygame_consts.K_AMPERSAND,
r"QUOTE": pygame_consts.K_QUOTE,
r"LEFTPAREN": pygame_consts.K_LEFTPAREN,
r"RIGHTPAREN": pygame_consts.K_RIGHTPAREN,
r"ASTERISK": pygame_consts.K_ASTERISK,
r"PLUS": pygame_consts.K_PLUS,
r"COMMA": pygame_consts.K_COMMA,
r"MINUS": pygame_consts.K_MINUS,
r"PERIOD": pygame_consts.K_PERIOD,
r"SLASH": pygame_consts.K_SLASH,
r"0": pygame_consts.K_0,
r"1": pygame_consts.K_1,
r"2": pygame_consts.K_2,
r"3": pygame_consts.K_3,
r"4": pygame_consts.K_4,
r"5": pygame_consts.K_5,
r"6": pygame_consts.K_6,
r"7": pygame_consts.K_7,
r"8": pygame_consts.K_8,
r"9": pygame_consts.K_9,
r"COLON": pygame_consts.K_COLON,
r"SEMICOLON": pygame_consts.K_SEMICOLON,
r"LESS": pygame_consts.K_LESS,
r"EQUALS": pygame_consts.K_EQUALS,
r"GREATER": pygame_consts.K_GREATER,
r"QUESTION": pygame_consts.K_QUESTION,
r"AT": pygame_consts.K_AT,
r"LEFTBRACKET": pygame_consts.K_LEFTBRACKET,
r"BACKSLASH": pygame_consts.K_BACKSLASH,
r"RIGHTBRACKET": pygame_consts.K_RIGHTBRACKET,
r"CARET": pygame_consts.K_CARET,
r"UNDERSCORE": pygame_consts.K_UNDERSCORE,
r"BACKQUOTE": pygame_consts.K_BACKQUOTE,
r"a": pygame_consts.K_a,
r"b": pygame_consts.K_b,
r"c": pygame_consts.K_c,
r"d": pygame_consts.K_d,
r"e": pygame_consts.K_e,
r"f": pygame_consts.K_f,
r"g": pygame_consts.K_g,
r"h": pygame_consts.K_h,
r"i": pygame_consts.K_i,
r"j": pygame_consts.K_j,
r"k": pygame_consts.K_k,
r"l": pygame_consts.K_l,
r"m": pygame_consts.K_m,
r"n": pygame_consts.K_n,
r"o": pygame_consts.K_o,
r"p": pygame_consts.K_p,
r"q": pygame_consts.K_q,
r"r": pygame_consts.K_r,
r"s": pygame_consts.K_s,
r"t": pygame_consts.K_t,
r"u": pygame_consts.K_u,
r"v": pygame_consts.K_v,
r"w": pygame_consts.K_w,
r"x": pygame_consts.K_x,
r"y": pygame_consts.K_y,
r"z": pygame_consts.K_z,
r"DELETE": pygame_consts.K_DELETE,
r"KP0": pygame_consts.K_KP0,
r"KP1": pygame_consts.K_KP1,
r"KP2": pygame_consts.K_KP2,
r"KP3": pygame_consts.K_KP3,
r"KP4": pygame_consts.K_KP4,
r"KP5": pygame_consts.K_KP5,
r"KP6": pygame_consts.K_KP6,
r"KP7": pygame_consts.K_KP7,
r"KP8": pygame_consts.K_KP8,
r"KP9": pygame_consts.K_KP9,
r"KP_PERIOD": pygame_consts.K_KP_PERIOD,
r"KP_DIVIDE": pygame_consts.K_KP_DIVIDE,
r"KP_MULTIPLY": pygame_consts.K_KP_MULTIPLY,
r"KP_MINUS": pygame_consts.K_KP_MINUS,
r"KP_PLUS": pygame_consts.K_KP_PLUS,
r"KP_ENTER": pygame_consts.K_KP_ENTER,
r"KP_EQUALS": pygame_consts.K_KP_EQUALS,
r"UP": pygame_consts.K_UP,
r"DOWN": pygame_consts.K_DOWN,
r"RIGHT": pygame_consts.K_RIGHT,
r"LEFT": pygame_consts.K_LEFT,
r"INSERT": pygame_consts.K_INSERT,
r"HOME": pygame_consts.K_HOME,
r"END": pygame_consts.K_END,
r"PAGEUP": pygame_consts.K_PAGEUP,
r"PAGEDOWN": pygame_consts.K_PAGEDOWN,
r"F1": pygame_consts.K_F1,
r"F2": pygame_consts.K_F2,
r"F3": pygame_consts.K_F3,
r"F4": pygame_consts.K_F4,
r"F5": pygame_consts.K_F5,
r"F6": pygame_consts.K_F6,
r"F7": pygame_consts.K_F7,
r"F8": pygame_consts.K_F8,
r"F9": pygame_consts.K_F9,
r"F10": pygame_consts.K_F10,
r"F11": pygame_consts.K_F11,
r"F12": pygame_consts.K_F12,
r"F13": pygame_consts.K_F13,
r"F14": pygame_consts.K_F14,
r"F15": pygame_consts.K_F15,
r"NUMLOCK": pygame_consts.K_NUMLOCK,
r"CAPSLOCK": pygame_consts.K_CAPSLOCK,
r"SCROLLOCK": pygame_consts.K_SCROLLOCK,
r"RSHIFT": pygame_consts.K_RSHIFT,
r"LSHIFT": pygame_consts.K_LSHIFT,
r"RCTRL": pygame_consts.K_RCTRL,
r"LCTRL": pygame_consts.K_LCTRL,
r"RALT": pygame_consts.K_RALT,
r"LALT": pygame_consts.K_LALT,
r"RMETA": pygame_consts.K_RMETA,
r"LMETA": pygame_consts.K_LMETA,
r"LSUPER": pygame_consts.K_LSUPER,
r"RSUPER": pygame_consts.K_RSUPER,
r"MODE": pygame_consts.K_MODE,
r"HELP": pygame_consts.K_HELP,
r"PRINT": pygame_consts.K_PRINT,
r"SYSREQ": pygame_consts.K_SYSREQ,
r"BREAK": pygame_consts.K_BREAK,
r"MENU": pygame_consts.K_MENU,
r"POWER": pygame_consts.K_POWER,
r"EURO": pygame_consts.K_EURO,
}
LIST_EVENTS_GAME_PRE = ["BEGIN_STEP"]
# Custom events to be registered here
LIST_EVENTS_GAME_POST = ["STEP", "DRAW", "END_STEP"]
LIST_EVENTS_CUSTOM = [
"KEY_PRESS", "MOUSE_PRESS", "Instance_Create", "Instance_Destroy"]
dict_event_name = UncasedDict()
list_event = []
list_event_old = []
list_state_key = []
list_state_key_old = []
list_state_mouse, list_state_mouse_old = [], []
def register_event_name(ev_name, ev_id=None):
if (ev_name in dict_event_name):
raise TypeError(
"ev_name={0} is already registered".format(ev_name))
if (ev_id is None):
ev_id = max(
pygame_consts.USEREVENT + 1, max(dict_event_name.values()) + 1)
dict_event_name[ev_name] = ev_id
def add_each_event(ev):
if not (ev.ev_name in dict_event_name):
return TypeError("ev_name not registered")
else:
# make list_event_accessible
list_event.append(ev)
def add_returned_events(ev_or_ev_list):
# fix below cond
if hasattr(ev_or_ev_list, "__iter__"):
# list of events
for each_ev in ev_or_ev_list:
add_each_event(each_ev)
else:
# single event
add_each_event(ev_or_ev_list)
def get_event_name(ev_id):
for ev_name in dict_event_name:
if dict_event_name[ev_name] == ev_id:
return ev_name
def get_event_id(ev_name):
return dict_event_name.get(ev_name)
def get_key_name(key_id):
for key_name in DICT_KEYS:
if DICT_KEYS[key_name] == key_id:
return key_name
def get_key_id(key_name):
return DICT_KEYS.get(key_name)
def get_mouse_btn_name(btn_id):
# btn_id can be 0, 1 or 2
if btn_id == 0:
return "left"
elif btn_id == 1:
return "middle"
elif btn_id == 2:
return "right"
else:
raise ValueError("btn_id must be 0, 1 or 2")
# No sort_events, event_generators should be pushed in correct order
def fuzzy_match_event_name(string_, event_or_action):
str_upper = string_.upper()
if not (str_upper in dict_event_name):
event_or_action = event_or_action.lower()
if event_or_action == "event" or event_or_action == "action":
# STR_STARTER becomes event_ or action_
STR_STARTER = event_or_action.upper() + "_"
else:
raise TypeError(
"event_or_action arg must be 'event' or 'action'.")
str_normalized = str_upper[
str_upper.find(STR_STARTER) + len(STR_STARTER):]
for tmp_event_name in dict_event_name:
# tmp event is the event_name, keys of KW_EVENTS
tmp_event_name_normalized = tmp_event_name.upper().replace("_", "")
if str_normalized.startswith(tmp_event_name) or str_normalized.startswith(tmp_event_name_normalized):
return tmp_event_name
else:
return str_upper
def add_ev_name_GAME_PRE():
for ev_name in LIST_EVENTS_GAME_PRE:
register_event_name(ev_name)
def add_ev_name_IB():
for ev_name in DICT_EVENT_IB:
register_event_name(ev_name, DICT_EVENT_IB[ev_name])
def add_ev_name_GAME_POST():
for ev_name in LIST_EVENTS_GAME_POST:
register_event_name(ev_name)
def add_ev_name_CUSTOM():
for ev_name in LIST_EVENTS_CUSTOM:
register_event_name(ev_name)
# event_generators
def gen_event_GAME_PRE():
return [Event(ev_name) for ev_name in LIST_EVENTS_GAME_PRE]
def gen_event_IB():
# move current list to old list
list_event_IB = pygame.event.get()
# Above list contains pygame_events, cant be modified
# But need to replace type with ev_name
new_list_ev = []
for each_ev in list_event_IB:
ev_name = get_event_name(each_ev.type)
tmp_ev = Event(ev_name, each_ev.dict)
new_list_ev.append(tmp_ev)
return new_list_ev
def gen_event_GAME_POST():
return [Event(ev_name) for ev_name in LIST_EVENTS_GAME_POST]
def gen_event_KEY_PRESS():
global list_state_key, list_state_key_old
list_state_key_old = list_state_key
list_state_key = pygame.key.get_pressed()
list_key_press_event = []
for tmp_key_id, bool_pressed in enumerate(list_state_key):
if bool_pressed:
tmp_key_name = get_key_name(tmp_key_id)
list_key_press_event.append(
Event("KEY_PRESS", {"key_name": tmp_key_name.lower(), "key_id": tmp_key_id}))
return list_key_press_event
def gen_event_MOUSE_PRESS():
global list_state_mouse, list_state_mouse_old
list_state_mouse_old = list_state_mouse
list_state_mouse = pygame.mouse.get_pressed()
list_mouse_press_event = []
for tmp_mouse_btn_id, bool_pressed in enumerate(list_state_mouse):
if bool_pressed:
tmp_btn_name = get_mouse_btn_name(tmp_mouse_btn_id)
list_mouse_press_event.append(
Event("MOUSE_PRESS", {"btn_name": tmp_btn_name.lower(), "btn_id": tmp_mouse_btn_id}))
return list_mouse_press_event
# pygame.mouse.get_pressed
# add ev_names
# Ordered list of name adders
LIST_ADDER_EV_NAME = [
add_ev_name_IB, add_ev_name_GAME_PRE, add_ev_name_GAME_POST, add_ev_name_CUSTOM]
for each_adder_func in LIST_ADDER_EV_NAME:
each_adder_func()
# add event generators
# Ordered list of generators
list_ordered_custom_generator = [gen_event_KEY_PRESS, gen_event_MOUSE_PRESS]
list_ordered_generators = [
gen_event_GAME_PRE, gen_event_IB, list_ordered_custom_generator, gen_event_GAME_POST]
def register_custom_event_generator(ev_func):
''' ev_func will be run in each step before step event and after begin step event and should return a / a list of dicts
each with ev_name (to be registered beforehand) and other props'''
global list_ordered_custom_generator
list_ordered_custom_generator.append(ev_func)
def get_event_generators():
return_list = []
for gen_or_list in list_ordered_generators:
if hasattr(gen_or_list, "__iter__"):
return_list.extend(gen_or_list)
else:
return_list.append(gen_or_list)
return return_list
# Todo: Howto programatically register at the right position of generator list
# Event collector
def collect_events():
# First, clear the old ev list
global list_event, list_event_old
list_event_old = list_event
list_event = []
for each_gen in get_event_generators():
add_returned_events(each_gen())
# Event dispatcher
# To be used by appr. classes
def dispatch_events_class(cls):
# cls.list_class must be available
for each_class in cls.list_class:
each_class.dispatch_events_instance(list_event)
def dispatch_events_instance(cls, list_event):
for each_instance in cls.list_instance:
each_instance.dispatch_events_self(list_event)
def dispatch_events_self(self, list_event):
for each_ev in list_event:
if each_ev.ev_name.upper() in self.dict_action_func:
self.dispatch_events_local()
for each_action in self.dict_action_func[each_ev.ev_name]:
# similar as self.action_step(each_ev)
each_action(self, each_ev)
def dispatch_events_local(self):
for each_ev in self.list_event_local:
if each_ev.ev_name.upper() in self.dict_action_func:
for each_action in self.dict_action_func[each_ev.ev_name]:
# similar as self.action_step(each_ev)
each_action(self, each_ev)
self.clear_event_local()
def push_event_local(self, ev_or_ev_list):
if hasattr(ev_or_ev_list, "__iter__"):
# list of events
for each_ev in ev_or_ev_list:
self._push_event_local_single(each_ev)
else:
# single event
self._push_event_local_single(ev_or_ev_list)
def clear_event_local(self):
self.list_event_local = []
def _push_event_local_single(self, ev):
self.list_event_local.append(ev)
class Event(object):
def __init__(self, ev_name, dict_=None):
super(Event, self).__init__()
self.ev_name = ev_name
self.dict = dict_
def _check_event(ev_name, new_or_old):
''' ev_name_or_type => name_or_type(numb)_of_event
new_or_old => current_event_list or old_event_list '''
global list_event, list_event_old
matched_events = []
if new_or_old == "new":
list_to_check = list_event
elif new_or_old == "old":
list_to_check = list_event_old
else:
raise AttributeError("new_or_old must be 'new' or 'old'.")
ev_name = fuzzy_match_event_name(ev_name, "event")
for ev in list_to_check:
if ev.ev_name == ev_name:
matched_events.append(ev)
return matched_events
def check_event(ev_name):
return _check_event(ev_name, "new")
def check_event_old(ev_name):
return _check_event(ev_name, "old")
def _get_key_press(key_name=None, new_or_old=None):
''' Returns list of dict with key_name and key_id, if key_name matches.
If key_name is None, all key preeses are allowed.'''
global list_state_key, list_state_key_old
if new_or_old == "new":
list_to_check = list_state_key
elif new_or_old == "old":
list_to_check = list_state_key_old
else:
raise TypeError("new_or_old must be 'new' or 'old', CANT be None")
list_key_press_event = []
for tmp_key_id, bool_pressed in enumerate(list_to_check):
if bool_pressed:
tmp_key_name = get_key_name(tmp_key_id)
if (key_name is None) or (tmp_key_name.lower() == key_name.lower()):
# Todo: Cant match event_name directly, need a fuzzy key name
# search func
list_key_press_event.append(
{"key_name": tmp_key_name.lower(), "key_id": tmp_key_id})
return list_key_press_event
def _get_mouse_press(btn_name=None, new_or_old=None):
global list_state_mouse, list_state_mouse_old
if new_or_old == "new":
list_to_check = list_state_mouse
elif new_or_old == "old":
list_to_check = list_state_mouse_old
else:
raise TypeError("new_or_old must be 'new' or 'old', CANT be None")
list_mouse_press_event = []
for tmp_mouse_btn_id, bool_pressed in enumerate(list_to_check):
if bool_pressed:
tmp_btn_name = get_mouse_btn_name(tmp_mouse_btn_id)
if (btn_name is None) or (btn_name.lower() == tmp_btn_name.lower()):
list_mouse_press_event.append(
{"btn_name": tmp_btn_name.lower(), "btn_id": tmp_mouse_btn_id})
return list_mouse_press_event
def get_key_press(key_name=None):
return _get_key_press(key_name, "new")
def get_key_press_old(key_name=None):
return _get_key_press(key_name, "old")
def get_mouse_press(btn_name=None):
return _get_mouse_press(btn_name, "new")
def get_mouse_press_old(btn_name=None):
return _get_mouse_press(btn_name, "old")