Tile favorites.
[cantaveria.git] / input.c
blob875f4f960bf2c6d5cb71f6c7b642f9a74a507087
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
27 the input module is an interface to the low level input system
28 plus a mapper from low level input events to abstract game inputs.
29 it has several functions:
30 * generate the next available input, if possible
31 * save and load input maps
32 * remap abstract event to last low level event
33 * convert abstract input to string form
37 #include <SDL/SDL.h>
40 #include <util.h>
41 #include <input.h>
43 #define JOY_MAX 32767
44 #define JOY_MIN -32768
45 #define JOY_THRESH 1000
47 static input NoInput = {NO_INPUT, INVALID_BUTTON, 0};
48 static input SkipInput = {SKIP_INPUT, INVALID_BUTTON, 0};
49 static input EndOfProgram = {END_OF_PROGRAM, INVALID_BUTTON, 0};
51 static SDL_Event last_event;
53 /* controller mappings */
54 struct key_map {
55 SDLKey sym;
57 int player;
58 enum input_button button;
60 struct key_map* next;
62 struct key_map* key_maps = NULL;
65 struct axis_map {
66 Uint8 joystick;
67 Uint8 axis;
68 Sint16 last_value;
70 int player;
71 enum input_button button[2];
73 struct axis_map* next;
75 struct axis_map* axis_maps = NULL;
77 struct jbutton_map {
78 Uint8 joystick;
79 Uint8 jbutton;
81 int player;
82 enum input_button button;
84 struct jbutton_map* next;
86 struct jbutton_map* jbutton_maps = NULL;
89 struct key_map* kmfind(SDLKey sym){
90 struct key_map* ptr = key_maps;
91 while(ptr){
92 if(ptr->sym == sym)
93 return ptr;
94 else
95 ptr = ptr->next;
97 return NULL;
100 struct axis_map* amfind(Uint8 joystick, Uint8 axis){
101 struct axis_map* ptr = axis_maps;
102 while(ptr){
103 if(ptr->joystick == joystick && ptr->axis == axis)
104 return ptr;
105 else
106 ptr = ptr->next;
108 return NULL;
111 struct jbutton_map* jmfind(Uint8 joystick, Uint8 jbutton){
112 struct jbutton_map* ptr = jbutton_maps;
113 while(ptr){
114 if(ptr->joystick == joystick && ptr->jbutton == jbutton)
115 return ptr;
116 else
117 ptr = ptr->next;
119 return NULL;
124 enum input_type kmtype(Uint8 type){
125 switch(type){
126 case SDL_KEYDOWN: return BUTTON_PRESS;
127 case SDL_KEYUP: return BUTTON_RELEASE;
128 default:
129 error_msg("input map_key: invalid SDL event type\n");
130 return INVALID_INPUT;
134 enum input_type jmtype(Uint8 type){
135 switch(type){
136 case SDL_JOYBUTTONDOWN: return BUTTON_PRESS;
137 case SDL_JOYBUTTONUP: return BUTTON_RELEASE;
138 default:
139 error_msg("input map_jbutton: invalid SDL event type\n");
140 return INVALID_INPUT;
144 enum input_button ambutton(int state, struct axis_map* am){
145 switch(state){
146 case -1: return am->button[0];
147 case 1: return am->button[1];
148 case 0:
149 error_msg("input axis_motion: axis state 0 does not imply a button\n");
150 return INVALID_BUTTON;
151 default:
152 error_msg("input axis_motion: invalid axis state (%d)\n", state);
153 return INVALID_BUTTON;
157 input map_key(SDL_Event* e){
158 SDLKey sym = e->key.keysym.sym;
159 struct key_map* km = kmfind(sym);
160 input in;
161 if(km){
162 in.type = kmtype(e->type);
163 in.player = km->player;
164 in.button = km->button;
165 return in;
167 else{
168 in.type = kmtype(e->type);
169 in.player = 0;
170 in.button = NONDESCRIPT_BUTTON;
171 return in;
175 input map_jbutton(SDL_Event* e){
176 Uint8 which = e->jbutton.which;
177 Uint8 jbutton = e->jbutton.button;
178 struct jbutton_map* jm = jmfind(which, jbutton);
179 input in;
181 if(jm){
182 in.type = jmtype(e->type);
183 in.player = jm->player;
184 in.button = jm->button;
185 return in;
187 else{
188 in.type = jmtype(e->type);
189 in.player = 0;
190 in.button = NONDESCRIPT_BUTTON;
191 return in;
195 int axis_state(Sint16 x){
196 if(x < -JOY_THRESH) return -1;
197 else if(x > JOY_THRESH) return 1;
198 else return 0;
201 input axis_motion(Sint16 value, struct axis_map* am){
202 int state0 = axis_state(am->last_value);
203 int state1 = axis_state(value);
204 int diff = state1 - state0;
205 input in;
207 if(abs(diff) == 2){
208 /*stuck FIXME ?
209 set a flag in the am which tells get_input
210 to do a button press
211 note that without this fix, it wont get stuck,
212 the input system will just be slightly inconsistent*/
213 error_msg("input axis_motion: (FIXME) joystick almost got stuck\n");
216 if(diff == 0){
217 return SkipInput;
219 else if(state0 != 0){
220 in.type = BUTTON_RELEASE;
221 in.player = am->player;
222 in.button = ambutton(state0, am);
223 return in;
225 else{ /*(state1 != 0)*/
226 in.type = BUTTON_PRESS;
227 in.player = am->player;
228 in.button = ambutton(state1, am);
229 return in;
233 input map_jaxis(SDL_Event* e){
234 Uint8 which = e->jaxis.which;
235 Uint8 axis = e->jaxis.axis;
236 Sint16 value = e->jaxis.value;
237 struct axis_map* am = amfind(which, axis);
238 if(am){
239 return axis_motion(value, am);
241 else{
242 return SkipInput;
248 void kmadd(int player, enum input_button button, SDLKey sym){
249 struct key_map* km = malloc(sizeof(struct key_map));
250 struct key_map* ptr = key_maps;;
251 km->player = player;
252 km->button = button;
253 km->sym = sym;
254 km->next = NULL;
256 if(!ptr){
257 key_maps = km;
258 return;
261 while(ptr->next) ptr = ptr->next;
263 ptr->next = km;
267 /* *** */
268 input get_input(){
269 SDL_Event e;
270 input in;
272 while(SDL_PollEvent(&e) != 0){
273 last_event = e;
274 switch(e.type){
275 case SDL_KEYDOWN:
276 case SDL_KEYUP:
277 return map_key(&e);
279 case SDL_JOYBUTTONDOWN:
280 case SDL_JOYBUTTONUP:
281 return map_jbutton(&e);
283 case SDL_JOYAXISMOTION:
284 in = map_jaxis(&e);
285 if(in.type == SKIP_INPUT)
286 return in;
287 else
288 break;
290 case SDL_QUIT:
291 return EndOfProgram;
295 return NoInput;
299 void remap_last_input(enum input_button button, int player){
300 SDL_Event e = last_event;
301 switch(e.type){
302 case SDL_KEYDOWN:
303 case SDL_KEYUP:
304 kmadd(player, button, e.key.keysym.sym);
305 break;
306 case SDL_JOYBUTTONDOWN:
307 case SDL_JOYBUTTONUP:
308 //jmadd(player, button, e.jbutton.button);
309 break;
310 case SDL_JOYAXISMOTION:
311 //amadd...
312 break;
318 void input_init(const char* filename){
319 /* set up mappings */
320 // A -> Left
321 // D -> Right
322 // W -> Up
323 kmadd(0, LEFT_BUTTON, SDLK_a);
324 kmadd(0, RIGHT_BUTTON, SDLK_d);
325 kmadd(0, UP_BUTTON, SDLK_w);
326 kmadd(0, DOWN_BUTTON, SDLK_s);
328 kmadd(0, JUMP_BUTTON, SDLK_k);
329 kmadd(0, FIRE_BUTTON, SDLK_j);
330 kmadd(0, INVENTORY_BUTTON, SDLK_i);
331 kmadd(0, SPECIAL_BUTTON, SDLK_l);
333 kmadd(0, L_BUTTON, SDLK_u);
334 kmadd(0, R_BUTTON, SDLK_o);
336 kmadd(0, START_BUTTON, SDLK_q);
337 kmadd(0, SELECT_BUTTON, SDLK_e);
339 kmadd(0, ESCAPE_KEY, SDLK_ESCAPE);
340 kmadd(0, PAUSE_KEY, SDLK_PAUSE);
343 void save_input(const char* filename){
348 const char* input_str(input in){
349 switch(in.button){
350 case START_BUTTON: return "START";
351 case SELECT_BUTTON: return "SELECT";
352 case L_BUTTON: return "L";
353 case R_BUTTON: return "R";
355 case LEFT_BUTTON: return "LEFT";
356 case RIGHT_BUTTON: return "RIGHT";
357 case UP_BUTTON: return "UP";
358 case DOWN_BUTTON: return "DOWN";
360 case FIRE_BUTTON: return "FIRE";
361 case JUMP_BUTTON: return "JUMP";
362 case INVENTORY_BUTTON: return "INVENTORY";
363 case SPECIAL_BUTTON: return "SPECIAL";
365 case ESCAPE_KEY: return "ESCAPE";
366 case PAUSE_KEY: return "PAUSE";
367 case INVALID_BUTTON: return "INVALID";
368 case NONDESCRIPT_BUTTON: return "NONDESCRIPT";
369 default: return "ERROR";
374 void print_last_raw(char* buf, int size){
375 SDL_Event e = last_event;
376 switch(e.type){
377 case SDL_KEYDOWN:
378 case SDL_KEYUP:
379 snprintf(
380 buf,size,
381 SDL_GetKeyName(e.key.keysym.sym)
383 break;
385 case SDL_JOYBUTTONDOWN:
386 case SDL_JOYBUTTONUP:
387 snprintf(
388 buf, size,
389 "J%d_B%d",
390 e.jbutton.which,
391 e.jbutton.button
393 break;
395 case SDL_JOYAXISMOTION:
396 snprintf(
397 buf,size,
398 "J%d_AXIS%d",
399 e.jaxis.which,
400 e.jaxis.axis
402 break;
404 default:
405 snprintf(buf, size, "???");
406 break;