event abstraction layer

This commit is contained in:
Andrew "Akari" Alexeyew 2012-08-13 18:50:28 +03:00
parent 4b9b0ca945
commit cf72d8dee3
14 changed files with 372 additions and 210 deletions

View file

@ -17,6 +17,7 @@ set(SRCs
stage.c
replay.c
global.c
events.c
player.c
projectile.c
enemy.c

View file

@ -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++;

View file

@ -9,7 +9,6 @@
#ifndef CREDITS_H
#define CREDITS_H
void credits_input(void);
void credits_loop(void);
void credits_add(char*, int);

View file

@ -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++;
}
}
}

102
src/events.c Normal file
View file

@ -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 <laochailan@web.de>
* Copyright (C) 2012, Alexeyew Andrew <http://akari.thebadasschoobs.org/>
*/
#include <SDL/SDL.h>
#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);
}

47
src/events.h Normal file
View file

@ -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 <laochailan@web.de>
* Copyright (C) 2012, Alexeyew Andrew <http://akari.thebadasschoobs.org/>
*/
#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

View file

@ -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);

View file

@ -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:

View file

@ -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) {

View file

@ -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);
}

View file

@ -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

View file

@ -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) {

View file

@ -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) {

View file

@ -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) {