midi.c has better error checking and better error messages.
[cantaveria.git] / input.c
blob62e93867fea4c0718e378f0b125d7f789be3209d
1 /*
2 Cantaveria - action adventure platform game
3 Copyright (C) 2009 2010 Evan Rinehart
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to
18 The Free Software Foundation, Inc.
19 51 Franklin Street, Fifth Floor
20 Boston, MA 02110-1301, USA
22 evanrinehart@gmail.com
24 #include <SDL/SDL.h>
27 #include <util.h>
28 #include <input.h>
30 #define JOY_MAX 32767
31 #define JOY_MIN -32768
32 #define JOY_THRESH 1000
34 static input NoInput = {NO_INPUT, INVALID_BUTTON, 0};
35 static input SkipInput = {SKIP_INPUT, INVALID_BUTTON, 0};
36 static input EndOfProgram = {END_OF_PROGRAM, INVALID_BUTTON, 0};
38 static SDL_Event last_event;
40 /* controller mappings */
41 struct key_map {
42 SDLKey sym;
44 int player;
45 enum input_button button;
47 struct key_map* next;
49 struct key_map* key_maps = NULL;
52 struct axis_map {
53 Uint8 joystick;
54 Uint8 axis;
55 Sint16 last_value;
57 int player;
58 enum input_button button[2];
60 struct axis_map* next;
62 struct axis_map* axis_maps = NULL;
64 struct jbutton_map {
65 Uint8 joystick;
66 Uint8 jbutton;
68 int player;
69 enum input_button button;
71 struct jbutton_map* next;
73 struct jbutton_map* jbutton_maps = NULL;
76 struct key_map* kmfind(SDLKey sym){
77 struct key_map* ptr = key_maps;
78 while(ptr){
79 if(ptr->sym == sym)
80 return ptr;
81 else
82 ptr = ptr->next;
84 return NULL;
87 struct axis_map* amfind(Uint8 joystick, Uint8 axis){
88 struct axis_map* ptr = axis_maps;
89 while(ptr){
90 if(ptr->joystick == joystick && ptr->axis == axis)
91 return ptr;
92 else
93 ptr = ptr->next;
95 return NULL;
98 struct jbutton_map* jmfind(Uint8 joystick, Uint8 jbutton){
99 struct jbutton_map* ptr = jbutton_maps;
100 while(ptr){
101 if(ptr->joystick == joystick && ptr->jbutton == jbutton)
102 return ptr;
103 else
104 ptr = ptr->next;
106 return NULL;
111 enum input_type kmtype(Uint8 type){
112 switch(type){
113 case SDL_KEYDOWN: return BUTTON_PRESS;
114 case SDL_KEYUP: return BUTTON_RELEASE;
115 default:
116 error_msg("input map_key: invalid SDL event type\n");
117 return INVALID_INPUT;
121 enum input_type jmtype(Uint8 type){
122 switch(type){
123 case SDL_JOYBUTTONDOWN: return BUTTON_PRESS;
124 case SDL_JOYBUTTONUP: return BUTTON_RELEASE;
125 default:
126 error_msg("input map_jbutton: invalid SDL event type\n");
127 return INVALID_INPUT;
131 enum input_button ambutton(int state, struct axis_map* am){
132 switch(state){
133 case -1: return am->button[0];
134 case 1: return am->button[1];
135 case 0:
136 error_msg("input axis_motion: axis state 0 does not imply a button\n");
137 return INVALID_BUTTON;
138 default:
139 error_msg("input axis_motion: invalid axis state (%d)\n", state);
140 return INVALID_BUTTON;
144 input map_key(SDL_Event* e){
145 SDLKey sym = e->key.keysym.sym;
146 struct key_map* km = kmfind(sym);
147 input in;
148 if(km){
149 in.type = kmtype(e->type);
150 in.player = km->player;
151 in.button = km->button;
152 return in;
154 else{
155 in.type = kmtype(e->type);
156 in.player = 0;
157 in.button = NONDESCRIPT_BUTTON;
158 return in;
162 input map_jbutton(SDL_Event* e){
163 Uint8 which = e->jbutton.which;
164 Uint8 jbutton = e->jbutton.button;
165 struct jbutton_map* jm = jmfind(which, jbutton);
166 input in;
168 if(jm){
169 in.type = jmtype(e->type);
170 in.player = jm->player;
171 in.button = jm->button;
172 return in;
174 else{
175 in.type = jmtype(e->type);
176 in.player = 0;
177 in.button = NONDESCRIPT_BUTTON;
178 return in;
182 int axis_state(Sint16 x){
183 if(x < -JOY_THRESH) return -1;
184 else if(x > JOY_THRESH) return 1;
185 else return 0;
188 input axis_motion(Sint16 value, struct axis_map* am){
189 int state0 = axis_state(am->last_value);
190 int state1 = axis_state(value);
191 int diff = state1 - state0;
192 input in;
194 if(abs(diff) == 2){
195 /*stuck FIXME ?
196 set a flag in the am which tells get_input
197 to do a button press
198 note that without this fix, it wont get stuck,
199 the input system will just be slightly inconsistent*/
200 error_msg("input axis_motion: (FIXME) joystick almost got stuck\n");
203 if(diff == 0){
204 return SkipInput;
206 else if(state0 != 0){
207 in.type = BUTTON_RELEASE;
208 in.player = am->player;
209 in.button = ambutton(state0, am);
210 return in;
212 else{ /*(state1 != 0)*/
213 in.type = BUTTON_PRESS;
214 in.player = am->player;
215 in.button = ambutton(state1, am);
216 return in;
220 input map_jaxis(SDL_Event* e){
221 Uint8 which = e->jaxis.which;
222 Uint8 axis = e->jaxis.axis;
223 Sint16 value = e->jaxis.value;
224 struct axis_map* am = amfind(which, axis);
225 if(am){
226 return axis_motion(value, am);
228 else{
229 return SkipInput;
235 void kmadd(int player, enum input_button button, SDLKey sym){
236 struct key_map* km = malloc(sizeof(struct key_map));
237 struct key_map* ptr = key_maps;;
238 km->player = player;
239 km->button = button;
240 km->sym = sym;
241 km->next = NULL;
243 if(!ptr){
244 key_maps = km;
245 return;
248 while(ptr->next) ptr = ptr->next;
250 ptr->next = km;
254 /* *** */
255 input get_input(){
256 SDL_Event e;
257 input in;
259 while(SDL_PollEvent(&e) != 0){
260 last_event = e;
261 switch(e.type){
262 case SDL_KEYDOWN:
263 case SDL_KEYUP:
264 return map_key(&e);
266 case SDL_JOYBUTTONDOWN:
267 case SDL_JOYBUTTONUP:
268 return map_jbutton(&e);
270 case SDL_JOYAXISMOTION:
271 in = map_jaxis(&e);
272 if(in.type == SKIP_INPUT)
273 return in;
274 else
275 break;
277 case SDL_QUIT:
278 return EndOfProgram;
282 return NoInput;
286 void remap_last_input(enum input_button button, int player){
287 SDL_Event e = last_event;
288 switch(e.type){
289 case SDL_KEYDOWN:
290 case SDL_KEYUP:
291 kmadd(player, button, e.key.keysym.sym);
292 break;
293 case SDL_JOYBUTTONDOWN:
294 case SDL_JOYBUTTONUP:
295 //jmadd(player, button, e.jbutton.button);
296 break;
297 case SDL_JOYAXISMOTION:
298 //amadd...
299 break;
305 void input_init(const char* filename){
306 /* set up mappings */
307 // A -> Left
308 // D -> Right
309 // W -> Up
310 kmadd(0, LEFT_BUTTON, SDLK_a);
311 kmadd(0, RIGHT_BUTTON, SDLK_d);
312 kmadd(0, UP_BUTTON, SDLK_w);
313 kmadd(0, DOWN_BUTTON, SDLK_s);
315 kmadd(0, JUMP_BUTTON, SDLK_k);
316 kmadd(0, FIRE_BUTTON, SDLK_j);
317 kmadd(0, INVENTORY_BUTTON, SDLK_i);
318 kmadd(0, SPECIAL_BUTTON, SDLK_l);
320 kmadd(0, L_BUTTON, SDLK_u);
321 kmadd(0, R_BUTTON, SDLK_o);
323 kmadd(0, START_BUTTON, SDLK_q);
324 kmadd(0, SELECT_BUTTON, SDLK_e);
326 kmadd(0, ESCAPE_KEY, SDLK_ESCAPE);
327 kmadd(0, PAUSE_KEY, SDLK_PAUSE);
330 void save_input(const char* filename){
335 const char* input_str(input in){
336 switch(in.button){
337 case START_BUTTON: return "START";
338 case SELECT_BUTTON: return "SELECT";
339 case L_BUTTON: return "L";
340 case R_BUTTON: return "R";
342 case LEFT_BUTTON: return "LEFT";
343 case RIGHT_BUTTON: return "RIGHT";
344 case UP_BUTTON: return "UP";
345 case DOWN_BUTTON: return "DOWN";
347 case FIRE_BUTTON: return "FIRE";
348 case JUMP_BUTTON: return "JUMP";
349 case INVENTORY_BUTTON: return "INVENTORY";
350 case SPECIAL_BUTTON: return "SPECIAL";
352 case ESCAPE_KEY: return "ESCAPE";
353 case PAUSE_KEY: return "PAUSE";
354 case INVALID_BUTTON: return "INVALID";
355 case NONDESCRIPT_BUTTON: return "NONDESCRIPT";
356 default: return "ERROR";
361 void print_last_raw(char* buf, int size){
362 SDL_Event e = last_event;
363 switch(e.type){
364 case SDL_KEYDOWN:
365 case SDL_KEYUP:
366 snprintf(
367 buf,size,
368 SDL_GetKeyName(e.key.keysym.sym)
370 break;
372 case SDL_JOYBUTTONDOWN:
373 case SDL_JOYBUTTONUP:
374 snprintf(
375 buf, size,
376 "J%d_B%d",
377 e.jbutton.which,
378 e.jbutton.button
380 break;
382 case SDL_JOYAXISMOTION:
383 snprintf(
384 buf,size,
385 "J%d_AXIS%d",
386 e.jaxis.which,
387 e.jaxis.axis
389 break;
391 default:
392 snprintf(buf, size, "???");
393 break;