From cf72d8dee3a1d709c565fec2f4760f33e4f146fd Mon Sep 17 00:00:00 2001 From: "Andrew \"Akari\" Alexeyew" Date: Mon, 13 Aug 2012 18:50:28 +0300 Subject: [PATCH] event abstraction layer --- src/CMakeLists.txt | 1 + src/credits.c | 8 +- src/credits.h | 1 - src/ending.c | 5 +- src/events.c | 102 +++++++++++++++++++++++++ src/events.h | 47 ++++++++++++ src/global.c | 18 ----- src/global.h | 3 +- src/menu/charselect.c | 55 +++++++------- src/menu/menu.c | 61 ++++++++------- src/menu/menu.h | 5 ++ src/menu/options.c | 169 ++++++++++++++++++++++++++---------------- src/menu/savereplay.c | 25 +++---- src/stage.c | 82 ++++++++++---------- 14 files changed, 372 insertions(+), 210 deletions(-) create mode 100644 src/events.c create mode 100644 src/events.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e69b2b9b..6a580580 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -17,6 +17,7 @@ set(SRCs stage.c replay.c global.c + events.c player.c projectile.c enemy.c diff --git a/src/credits.c b/src/credits.c index 16a0b018..2ed90ad7 100644 --- a/src/credits.c +++ b/src/credits.c @@ -237,12 +237,6 @@ void credits_process(void) { } } -void credits_input(void) { - SDL_Event event; - while(SDL_PollEvent(&event)) - global_processevent(&event); -} - void credits_free(void) { int i, j; for(i = 0; i < credits.ecount; ++i) { @@ -258,7 +252,7 @@ void credits_free(void) { void credits_loop(void) { credits_init(); while(credits.fadeout <= 1) { - credits_input(); + handle_events(NULL, 0, NULL); credits_process(); credits_draw(); global.frames++; diff --git a/src/credits.h b/src/credits.h index 37c15cbc..6f1e59f2 100644 --- a/src/credits.h +++ b/src/credits.h @@ -9,7 +9,6 @@ #ifndef CREDITS_H #define CREDITS_H -void credits_input(void); void credits_loop(void); void credits_add(char*, int); diff --git a/src/ending.c b/src/ending.c index 169c258c..dd1a2bce 100644 --- a/src/ending.c +++ b/src/ending.c @@ -8,7 +8,6 @@ #include "ending.h" #include "global.h" -#include "credits.h" void add_ending_entry(Ending *e, int dur, char *msg, char *tex) { EndingEntry *entry; @@ -131,7 +130,7 @@ void ending_loop(void) { set_ortho(); while(e.pos < e.count-1) { - credits_input(); + handle_events(NULL, 0, NULL); ending_draw(&e); global.frames++; @@ -141,4 +140,4 @@ void ending_loop(void) { if(global.frames >= e.entries[e.pos+1].time) e.pos++; } -} \ No newline at end of file +} diff --git a/src/events.c b/src/events.c new file mode 100644 index 00000000..e34f9468 --- /dev/null +++ b/src/events.c @@ -0,0 +1,102 @@ +/* + * This software is licensed under the terms of the MIT-License + * See COPYING for further information. + * --- + * Copyright (C) 2011, Lukas Weber + * Copyright (C) 2012, Alexeyew Andrew + */ + +#include +#include "events.h" +#include "config.h" +#include "global.h" +#include "video.h" + +void handle_events(EventHandler handler, EventFlags flags, void *arg) { + SDL_Event event; + Uint8 *keys = SDL_GetKeyState(NULL); + + int kbd = flags & EF_Keyboard; + int text = flags & EF_Text; + int menu = flags & EF_Menu; + int game = flags & EF_Game; + + if(text) SDL_EnableUNICODE(True); + while(SDL_PollEvent(&event)) { + int sym = event.key.keysym.sym; + int uni = event.key.keysym.unicode; + + switch(event.type) { + case SDL_KEYDOWN: + if(sym == tconfig.intval[KEY_SCREENSHOT]) { + take_screenshot(); + break; + } + + if((sym == SDLK_RETURN && (keys[SDLK_LALT] || keys[SDLK_RALT])) || sym == tconfig.intval[KEY_FULLSCREEN]) { + video_toggle_fullscreen(); + break; + } + + if(kbd) + handler(E_KeyDown, sym, arg); + + if(menu) { + if(sym == tconfig.intval[KEY_DOWN] || sym == SDLK_DOWN) { + handler(E_CursorDown, 0, arg); + } else if(sym == tconfig.intval[KEY_UP] || sym == SDLK_UP) { + handler(E_CursorUp, 0, arg); + } else if(sym == tconfig.intval[KEY_RIGHT] || sym == SDLK_RIGHT) { + handler(E_CursorRight, 0, arg); + } else if(sym == tconfig.intval[KEY_LEFT] || sym == SDLK_LEFT) { + handler(E_CursorLeft, 0, arg); + } else if(sym == tconfig.intval[KEY_SHOT] || sym == SDLK_RETURN) { + handler(E_MenuAccept, 0, arg); + } else if(sym == SDLK_ESCAPE) { + handler(E_MenuAbort, 0, arg); + } + } + + if(game) { + if(sym == SDLK_ESCAPE) + handler(E_Pause, 0, arg); + else { + int key = config_sym2key(sym); + if(key >= 0) + handler(E_PlrKeyDown, key, arg); + } + } + + if(text) { + if(sym == SDLK_ESCAPE) + handler(E_CancelText, 0, arg); + else if(sym == SDLK_RETURN) + handler(E_SubmitText, 0, arg); + else if(sym == SDLK_BACKSPACE) + handler(E_CharErased, 0, arg); + else if(uni && sym != SDLK_TAB) { + handler(E_CharTyped, uni, arg); + } + } + + break; + + case SDL_KEYUP: + if(kbd) + handler(E_KeyUp, sym, arg); + + if(game) { + int key = config_sym2key(sym); + if(key >= 0) + handler(E_PlrKeyUp, key, arg); + } + + break; + + case SDL_QUIT: + exit(0); + break; + } + } + if(text) SDL_EnableUNICODE(False); +} diff --git a/src/events.h b/src/events.h new file mode 100644 index 00000000..0f920a58 --- /dev/null +++ b/src/events.h @@ -0,0 +1,47 @@ +/* + * This software is licensed under the terms of the MIT-License + * See COPYING for further information. + * --- + * Copyright (C) 2011, Lukas Weber + * Copyright (C) 2012, Alexeyew Andrew + */ + +#ifndef EVENTS_H +#define EVENTS_H + +typedef enum { + EF_Keyboard = 1, + EF_Text = 2, + EF_Menu = 4, + EF_Game = 8 +} EventFlags; + +typedef enum { + // EF_Keyboard + E_KeyDown, + E_KeyUp, + + // EF_Text + E_CharTyped, + E_CharErased, + E_SubmitText, + E_CancelText, + + // EF_Menu + E_CursorUp, + E_CursorDown, + E_CursorLeft, + E_CursorRight, + E_MenuAccept, + E_MenuAbort, + + // EF_Game + E_PlrKeyDown, + E_PlrKeyUp, + E_Pause +} EventType; + +typedef void(*EventHandler)(EventType, int, void*); +void handle_events(EventHandler handler, EventFlags flags, void *arg); + +#endif diff --git a/src/global.c b/src/global.c index 106d30cb..db850ef9 100644 --- a/src/global.c +++ b/src/global.c @@ -211,24 +211,6 @@ void take_screenshot(void) fclose(out); } -void global_processevent(SDL_Event *event) -{ - int sym = event->key.keysym.sym; - Uint8 *keys; - - keys = SDL_GetKeyState(NULL); - - if(event->type == SDL_KEYDOWN) - { - if(sym == tconfig.intval[KEY_SCREENSHOT]) - take_screenshot(); - if((sym == SDLK_RETURN && (keys[SDLK_LALT] || keys[SDLK_RALT])) || sym == tconfig.intval[KEY_FULLSCREEN]) - video_toggle_fullscreen(); - } else if(event->type == SDL_QUIT) { - exit(0); - } -} - int strendswith(char *s, char *e) { int ls = strlen(s); int le = strlen(e); diff --git a/src/global.h b/src/global.h index 1a0d82e6..ac461002 100644 --- a/src/global.h +++ b/src/global.h @@ -31,6 +31,7 @@ #include "resource/resource.h" #include "replay.h" #include "random.h" +#include "events.h" #define FILE_PREFIX PREFIX "/share/taisei/" #define CONFIG_FILE "config" @@ -133,8 +134,6 @@ void calc_fps(FPSCounter *fps); void set_ortho(void); void colorfill(float r, float g, float b, float a); void fade_out(float f); - -void global_processevent(SDL_Event*); void take_screenshot(void); // needed for mingw compatibility: diff --git a/src/menu/charselect.c b/src/menu/charselect.c index fa20a43a..6e990dcd 100644 --- a/src/menu/charselect.c +++ b/src/menu/charselect.c @@ -123,38 +123,33 @@ void draw_char_menu(MenuData *menu) { glColor3f(1,1,1); } -void char_menu_input(MenuData *menu) { - SDL_Event event; +void char_menu_input_event(EventType type, int state, void *arg) { + MenuData *menu = arg; + MenuData *mod = menu->context; - MenuData *mod = menu->context; - - while(SDL_PollEvent(&event)) { - int sym = event.key.keysym.sym; - Uint8 *keys = SDL_GetKeyState(NULL); - - global_processevent(&event); - if(event.type == SDL_KEYDOWN) { - if(sym == tconfig.intval[KEY_RIGHT] || sym == SDLK_RIGHT) { - menu->cursor++; - } else if(sym == tconfig.intval[KEY_LEFT] || sym == SDLK_LEFT) { - menu->cursor--; - } else if(sym == tconfig.intval[KEY_DOWN] || sym == SDLK_DOWN) { - mod->cursor++; - } else if(sym == tconfig.intval[KEY_UP] || sym == SDLK_UP) { - mod->cursor--; - } else if((sym == tconfig.intval[KEY_SHOT] || (sym == SDLK_RETURN && !keys[SDLK_LALT] && !keys[SDLK_RALT])) && menu->entries[menu->cursor].action) { - close_menu(menu); - menu->selected = menu->cursor; - close_menu(mod); - mod->selected = mod->cursor; - } else if(sym == SDLK_ESCAPE) { - close_menu(menu); - } - - menu->cursor = (menu->cursor % menu->ecount) + menu->ecount*(menu->cursor < 0); - mod->cursor = (mod->cursor % mod->ecount) + mod->ecount*(mod->cursor < 0); - } + if(type == E_CursorRight) + menu->cursor++; + else if(type == E_CursorLeft) + menu->cursor--; + else if(type == E_CursorDown) + mod->cursor++; + else if(type == E_CursorUp) + mod->cursor--; + else if(type == E_MenuAccept) { + close_menu(menu); + menu->selected = menu->cursor; + close_menu(menu); + mod->selected = mod->cursor; + } else if(type == E_MenuAbort) { + close_menu(menu); } + + menu->cursor = (menu->cursor % menu->ecount) + menu->ecount*(menu->cursor < 0); + mod->cursor = (mod->cursor % mod->ecount) + mod->ecount*(mod->cursor < 0); +} + +void char_menu_input(MenuData *menu) { + handle_events(char_menu_input_event, EF_Menu, menu); } void free_char_menu(MenuData *menu) { diff --git a/src/menu/menu.c b/src/menu/menu.c index 3a67479a..ba2e9ef7 100644 --- a/src/menu/menu.c +++ b/src/menu/menu.c @@ -66,39 +66,44 @@ float menu_fade(MenuData *menu) { return 0.0; } -void menu_key_action(MenuData *menu, int sym) { - Uint8 *keys = SDL_GetKeyState(NULL); +void menu_event(EventType type, int state, void *arg) { + MenuData *menu = arg; + + switch(type) { + case E_CursorDown: + do { + if(++menu->cursor >= menu->ecount) + menu->cursor = 0; + } while(menu->entries[menu->cursor].action == NULL); + break; - if(sym == tconfig.intval[KEY_DOWN] || sym == SDLK_DOWN) { - do { - if(++menu->cursor >= menu->ecount) - menu->cursor = 0; - } while(menu->entries[menu->cursor].action == NULL); - } else if(sym == tconfig.intval[KEY_UP] || sym == SDLK_UP) { - do { - if(--menu->cursor < 0) - menu->cursor = menu->ecount - 1; - } while(menu->entries[menu->cursor].action == NULL); - } else if((sym == tconfig.intval[KEY_SHOT] || (sym == SDLK_RETURN && !keys[SDLK_LALT] && !keys[SDLK_RALT])) && menu->entries[menu->cursor].action) { - menu->selected = menu->cursor; + case E_CursorUp: + do { + if(--menu->cursor < 0) + menu->cursor = menu->ecount - 1; + } while(menu->entries[menu->cursor].action == NULL); + break; - close_menu(menu); - } else if(sym == SDLK_ESCAPE && menu->flags & MF_Abortable) { - menu->selected = -1; - close_menu(menu); + case E_MenuAccept: + if(menu->entries[menu->cursor].action) { + menu->selected = menu->cursor; + close_menu(menu); + } + break; + + case E_MenuAbort: + if(menu->flags & MF_Abortable) { + menu->selected = -1; + close_menu(menu); + } + break; + + default: break; } } void menu_input(MenuData *menu) { - SDL_Event event; - - while(SDL_PollEvent(&event)) { - int sym = event.key.keysym.sym; - - global_processevent(&event); - if(event.type == SDL_KEYDOWN) - menu_key_action(menu,sym); - } + handle_events(menu_event, EF_Menu, (void*)menu); } void menu_logic(MenuData *menu) { @@ -158,4 +163,4 @@ void draw_menu_selector(float x, float y, float w, float h, float t) { void draw_menu_title(MenuData *m, char *title) { draw_text(AL_Right, (stringwidth(title, _fonts.mainmenu) + 10) * (1.0-menu_fade(m)), 30, title, _fonts.mainmenu); } - \ No newline at end of file + diff --git a/src/menu/menu.h b/src/menu/menu.h index ef52158f..22715fa6 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -12,6 +12,8 @@ #define TS_KR_DELAY SDL_DEFAULT_REPEAT_DELAY #define TS_KR_INTERVAL (SDL_DEFAULT_REPEAT_INTERVAL*2) +#include "events.h" + enum { FADE_TIME = 15 }; @@ -83,4 +85,7 @@ float menu_fade(MenuData *menu); void draw_menu_selector(float x, float y, float w, float h, float t); void draw_menu_title(MenuData *m, char *title); + +void menu_event(EventType type, int state, void *arg); + #endif diff --git a/src/menu/options.c b/src/menu/options.c index 46505066..bc895695 100644 --- a/src/menu/options.c +++ b/src/menu/options.c @@ -578,60 +578,115 @@ void draw_options_menu(MenuData *menu) { // --- Input processing --- // -void bind_input(MenuData *menu, OptionBinding *b) -{ - SDL_Event event; +void bind_input_event(EventType type, int state, void *arg) { + OptionBinding *b = arg; - SDL_EnableUNICODE(True); - while(SDL_PollEvent(&event)) { - int sym = event.key.keysym.sym; - int uni = event.key.keysym.unicode; + int sym = state; + char c = (char)(((Uint16)state) & 0x7F); + char *dest = b->type == BT_StrValue? *b->values : NULL; + + switch(type) { + case E_KeyDown: + if(sym != SDLK_ESCAPE) + tconfig.intval[b->configentry] = sym; + b->blockinput = False; + break; - if(event.type == SDL_KEYDOWN) { - switch(b->type) { - case BT_KeyBinding: - if(sym != SDLK_ESCAPE) - tconfig.intval[b->configentry] = sym; - b->blockinput = False; - break; - - case BT_StrValue: { - // Very basic editor for string config values - // b->values is a pointer to the editor buffer string here (char**) - // Normally it's used to store the value names for BT_IntValue binds, though. - // TODO: implement a cursor here (so we can use arrow keys for editing) - - char c = (char)(uni & 0x7F); - char *dest = *b->values; - - if(sym == SDLK_RETURN) { - if(strlen(dest)) - stralloc(&(tconfig.strval[b->configentry]), dest); - else - strncpy(dest, tconfig.strval[b->configentry], 128); - b->blockinput = False; - } else if(sym == SDLK_BACKSPACE) { - if(strlen(dest)) - dest[strlen(dest)-1] = 0; - } else if(sym == SDLK_ESCAPE) { - strncpy(dest, tconfig.strval[b->configentry], 128); - b->blockinput = False; - } else if(uni && sym != SDLK_TAB && c != ':') { // we use ':' as a separator for replays (and might use it as such somewhere else), and I don't feel like escaping it. - strncat(dest, &c, 128); - dest[strlen(dest)-1] = 0; - } - break; - } - - default: // should never get there anyway - b->blockinput = False; - break; + case E_CharTyped: + if(c != ':') { + char s[] = {c, 0}; + strncat(dest, s, 128); } - } + break; + + case E_CharErased: + if(strlen(dest)) + dest[strlen(dest)-1] = 0; + break; + + case E_SubmitText: + if(strlen(dest)) + stralloc(&(tconfig.strval[b->configentry]), dest); + else + strncpy(dest, tconfig.strval[b->configentry], 128); + b->blockinput = False; + break; + + case E_CancelText: + strncpy(dest, tconfig.strval[b->configentry], 128); + b->blockinput = False; + break; + + default: break; } - SDL_EnableUNICODE(False); } +#define SHOULD_SKIP (!menu->entries[menu->cursor].action || (((OptionBinding*)menu->context)[menu->cursor].enabled && !bind_isactive(&(((OptionBinding*)menu->context)[menu->cursor])))) +static void options_input_event(EventType type, int state, void *arg) { + MenuData *menu = arg; + OptionBinding *binds = menu->context; + OptionBinding *bind = &(binds[menu->cursor]); + + switch(type) { + case E_CursorDown: + menu->drawdata[3] = 10; + do { + menu->cursor++; + if(menu->cursor >= menu->ecount) + menu->cursor = 0; + } while SHOULD_SKIP; + break; + + case E_CursorUp: + menu->drawdata[3] = 10; + do { + menu->cursor--; + if(menu->cursor < 0) + menu->cursor = menu->ecount - 1; + } while SHOULD_SKIP; + break; + + case E_CursorLeft: + if(bind->enabled && (bind->type == BT_IntValue || bind->type == BT_Resolution)) + bind_setprev(bind); + break; + + case E_CursorRight: + if(bind->enabled && (bind->type == BT_IntValue || bind->type == BT_Resolution)) + bind_setnext(bind); + break; + + case E_MenuAccept: + menu->selected = menu->cursor; + + if(bind->enabled) switch(bind->type) { + case BT_KeyBinding: + bind->blockinput = True; + break; + + case BT_StrValue: + bind->selected = strlen(tconfig.strval[bind->configentry]); + bind->blockinput = True; + break; + + default: + break; + } else close_menu(menu); + break; + + case E_MenuAbort: + menu->selected = -1; + close_menu(menu); + break; + + default: break; + } + + menu->cursor = (menu->cursor % menu->ecount) + menu->ecount*(menu->cursor < 0); +} +#undef SHOULD_SKIP + +/* static void options_key_action(MenuData *menu, int sym) { #define SHOULD_SKIP (!menu->entries[menu->cursor].action || (((OptionBinding*)menu->context)[menu->cursor].enabled && !bind_isactive(&(((OptionBinding*)menu->context)[menu->cursor])))) Uint8 *keys = SDL_GetKeyState(NULL); @@ -687,24 +742,14 @@ static void options_key_action(MenuData *menu, int sym) { menu->cursor = (menu->cursor % menu->ecount) + menu->ecount*(menu->cursor < 0); } - +*/ void options_menu_input(MenuData *menu) { - SDL_Event event; OptionBinding *b; if((b = get_input_blocking_binding(menu)) != NULL) - { - bind_input(menu, b); - return; - } - - while(SDL_PollEvent(&event)) { - int sym = event.key.keysym.sym; - - global_processevent(&event); - if(event.type == SDL_KEYDOWN) - options_key_action(menu, sym); - } + handle_events(bind_input_event, b->type == BT_StrValue? EF_Text : EF_Keyboard, b); + else + handle_events(options_input_event, EF_Menu, menu); } int options_menu_loop(MenuData *menu) { diff --git a/src/menu/savereplay.c b/src/menu/savereplay.c index 8af5d1ae..b7fa5554 100755 --- a/src/menu/savereplay.c +++ b/src/menu/savereplay.c @@ -82,22 +82,17 @@ void draw_saverpy_menu(MenuData *m) { glPopMatrix(); } +void saverpy_input_event(EventType type, int state, void *arg) { + if(type == E_CursorLeft) + menu_event(E_CursorUp, state, arg); + else if(type == E_CursorRight) + menu_event(E_CursorDown, state, arg); + else + menu_event(type, state, arg); +} + void saverpy_menu_input(MenuData *menu) { - SDL_Event event; - - while(SDL_PollEvent(&event)) { - int sym = event.key.keysym.sym; - - global_processevent(&event); - if(event.type == SDL_KEYDOWN) { - if(sym == SDLK_LEFT) - menu_key_action(menu, SDLK_UP); - else if(sym == SDLK_RIGHT) - menu_key_action(menu, SDLK_DOWN); - else - menu_key_action(menu,sym); - } - } + handle_events(saverpy_input_event, EF_Menu, menu); } int saverpy_menu_loop(MenuData *m) { diff --git a/src/stage.c b/src/stage.c index ecbe3347..92396ea3 100644 --- a/src/stage.c +++ b/src/stage.c @@ -57,22 +57,48 @@ void stage_ingamemenu(void) { ingame_menu_loop(&menu); } -void replay_input(void) { - SDL_Event event; - while(SDL_PollEvent(&event)) { - int sym = event.key.keysym.sym; - global_processevent(&event); - - if(event.type == SDL_KEYDOWN) { - if(sym == SDLK_ESCAPE) - stage_ingamemenu(); +void stage_input_event(EventType type, int key, void *arg) { + switch(type) { + case E_PlrKeyDown: + if(global.dialog && (key == KEY_SHOT || key == KEY_BOMB)) { + page_dialog(&global.dialog); + replay_event(&global.replay, EV_PRESS, key); + } else { + player_event(&global.plr, EV_PRESS, key); + replay_event(&global.replay, EV_PRESS, key); + + if(key == KEY_SKIP && global.dialog) + global.dialog->skip = True; + } break; - } - } + case E_PlrKeyUp: + player_event(&global.plr, EV_RELEASE, key); + replay_event(&global.replay, EV_RELEASE, key); + + if(key == KEY_SKIP && global.dialog) + global.dialog->skip = False; + break; + + case E_Pause: + stage_ingamemenu(); + break; + + default: break; + } +} + +void stage_replay_event(EventType type, int state, void *arg) { + if(type == E_Pause) + stage_ingamemenu(); +} + +void replay_input(void) { ReplayStage *s = global.replay.current; int i; + handle_events(stage_replay_event, EF_Game, NULL); + for(i = s->playpos; i < s->ecount; ++i) { ReplayEvent *e = &(s->events[i]); @@ -100,39 +126,7 @@ void replay_input(void) { } void stage_input(void) { - - SDL_Event event; - while(SDL_PollEvent(&event)) { - int sym = event.key.keysym.sym; - int key = config_sym2key(sym); - global_processevent(&event); - - switch(event.type) { - case SDL_KEYDOWN: - if(global.dialog && (key == KEY_SHOT || key == KEY_BOMB)) { - page_dialog(&global.dialog); - replay_event(&global.replay, EV_PRESS, key); - } else if(sym == SDLK_ESCAPE) { - stage_ingamemenu(); - } else { - player_event(&global.plr, EV_PRESS, key); - replay_event(&global.replay, EV_PRESS, key); - - if(key == KEY_SKIP && global.dialog) - global.dialog->skip = True; - } - - break; - - case SDL_KEYUP: - player_event(&global.plr,EV_RELEASE, key); - replay_event(&global.replay, EV_RELEASE, key); - - if(key == KEY_SKIP && global.dialog) - global.dialog->skip = False; - break; - } - } + handle_events(stage_input_event, EF_Game, NULL); // workaround if(global.dialog && global.dialog->skip) {