in_sdl: give names to gamepad buttons
[libpicofe.git] / in_sdl.c
... / ...
CommitLineData
1/*
2 * (C) GraÅžvydas "notaz" Ignotas, 2012
3 *
4 * This work is licensed under the terms of any of these licenses
5 * (at your option):
6 * - GNU GPL, version 2 or later.
7 * - GNU LGPL, version 2.1 or later.
8 * - MAME license.
9 * See the COPYING file in the top-level directory.
10 */
11
12#include <stdio.h>
13#include <SDL.h>
14#include "input.h"
15#include "in_sdl.h"
16
17#define IN_SDL_PREFIX "sdl:"
18/* should be machine word for best performace */
19typedef unsigned long keybits_t;
20#define KEYBITS_WORD_BITS (sizeof(keybits_t) * 8)
21
22#ifndef ARRAY_SIZE
23#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
24#endif
25
26struct in_sdl_state {
27 const in_drv_t *drv;
28 SDL_Joystick *joy;
29 int joy_id;
30 int joy_numaxes;
31 int joy_numbuttons;
32 int *joy_axis_keydown;
33 int joy_hat_down;
34 unsigned int joy_axis_as_btn; // bitmask; vs axes of centered sticks
35 unsigned int redraw:1;
36 unsigned int abs_to_udlr:1;
37 unsigned int hat_warned:1;
38 SDL_Event revent;
39 SDL_Event mevent; // last mouse event
40 keybits_t keystate[SDLK_LAST / KEYBITS_WORD_BITS + 1];
41 // emulator keys should always be processed immediately lest one is lost
42 keybits_t emu_keys[SDLK_LAST / KEYBITS_WORD_BITS + 1];
43};
44
45static void (*ext_event_handler)(void *event);
46
47static const char * const in_sdl_keys[SDLK_LAST] = {
48 [SDLK_BACKSPACE] = "backspace",
49 [SDLK_TAB] = "tab",
50 [SDLK_CLEAR] = "clear",
51 [SDLK_RETURN] = "return",
52 [SDLK_PAUSE] = "pause",
53 [SDLK_ESCAPE] = "escape",
54 [SDLK_SPACE] = "space",
55 [SDLK_EXCLAIM] = "!",
56 [SDLK_QUOTEDBL] = "\"",
57 [SDLK_HASH] = "#",
58 [SDLK_DOLLAR] = "$",
59 [SDLK_AMPERSAND] = "&",
60 [SDLK_QUOTE] = "'",
61 [SDLK_LEFTPAREN] = "(",
62 [SDLK_RIGHTPAREN] = ")",
63 [SDLK_ASTERISK] = "*",
64 [SDLK_PLUS] = "+",
65 [SDLK_COMMA] = ",",
66 [SDLK_MINUS] = "-",
67 [SDLK_PERIOD] = ".",
68 [SDLK_SLASH] = "/",
69 [SDLK_0] = "0",
70 [SDLK_1] = "1",
71 [SDLK_2] = "2",
72 [SDLK_3] = "3",
73 [SDLK_4] = "4",
74 [SDLK_5] = "5",
75 [SDLK_6] = "6",
76 [SDLK_7] = "7",
77 [SDLK_8] = "8",
78 [SDLK_9] = "9",
79 [SDLK_COLON] = ":",
80 [SDLK_SEMICOLON] = ";",
81 [SDLK_LESS] = "<",
82 [SDLK_EQUALS] = "=",
83 [SDLK_GREATER] = ">",
84 [SDLK_QUESTION] = "?",
85 [SDLK_AT] = "@",
86 [SDLK_LEFTBRACKET] = "[",
87 [SDLK_BACKSLASH] = "\\",
88 [SDLK_RIGHTBRACKET] = "]",
89 [SDLK_CARET] = "^",
90 [SDLK_UNDERSCORE] = "_",
91 [SDLK_BACKQUOTE] = "`",
92 [SDLK_a] = "a",
93 [SDLK_b] = "b",
94 [SDLK_c] = "c",
95 [SDLK_d] = "d",
96 [SDLK_e] = "e",
97 [SDLK_f] = "f",
98 [SDLK_g] = "g",
99 [SDLK_h] = "h",
100 [SDLK_i] = "i",
101 [SDLK_j] = "j",
102 [SDLK_k] = "k",
103 [SDLK_l] = "l",
104 [SDLK_m] = "m",
105 [SDLK_n] = "n",
106 [SDLK_o] = "o",
107 [SDLK_p] = "p",
108 [SDLK_q] = "q",
109 [SDLK_r] = "r",
110 [SDLK_s] = "s",
111 [SDLK_t] = "t",
112 [SDLK_u] = "u",
113 [SDLK_v] = "v",
114 [SDLK_w] = "w",
115 [SDLK_x] = "x",
116 [SDLK_y] = "y",
117 [SDLK_z] = "z",
118 [SDLK_DELETE] = "delete",
119
120 // gamepad buttons
121 #define B(x) [SDLK_WORLD_##x] = "b"#x
122 B(0), B(1), B(2), B(3), B(4), B(5), B(6), B(7),
123 B(8), B(9), B(10), B(11), B(12), B(13), B(14), B(15),
124 B(16), B(17), B(18), B(19), B(20), B(21), B(22), B(23),
125 B(24), B(25), B(26), B(27), B(28), B(29), B(30), B(31),
126 B(32), B(33), B(34), B(35), B(36), B(37), B(38), B(39),
127 #undef B
128
129 [SDLK_KP0] = "[0]",
130 [SDLK_KP1] = "[1]",
131 [SDLK_KP2] = "[2]",
132 [SDLK_KP3] = "[3]",
133 [SDLK_KP4] = "[4]",
134 [SDLK_KP5] = "[5]",
135 [SDLK_KP6] = "[6]",
136 [SDLK_KP7] = "[7]",
137 [SDLK_KP8] = "[8]",
138 [SDLK_KP9] = "[9]",
139 [SDLK_KP_PERIOD] = "[.]",
140 [SDLK_KP_DIVIDE] = "[/]",
141 [SDLK_KP_MULTIPLY] = "[*]",
142 [SDLK_KP_MINUS] = "[-]",
143 [SDLK_KP_PLUS] = "[+]",
144 [SDLK_KP_ENTER] = "enter",
145 [SDLK_KP_EQUALS] = "equals",
146
147 [SDLK_UP] = "up",
148 [SDLK_DOWN] = "down",
149 [SDLK_RIGHT] = "right",
150 [SDLK_LEFT] = "left",
151 [SDLK_INSERT] = "insert",
152 [SDLK_HOME] = "home",
153 [SDLK_END] = "end",
154 [SDLK_PAGEUP] = "page up",
155 [SDLK_PAGEDOWN] = "page down",
156
157 [SDLK_F1] = "f1",
158 [SDLK_F2] = "f2",
159 [SDLK_F3] = "f3",
160 [SDLK_F4] = "f4",
161 [SDLK_F5] = "f5",
162 [SDLK_F6] = "f6",
163 [SDLK_F7] = "f7",
164 [SDLK_F8] = "f8",
165 [SDLK_F9] = "f9",
166 [SDLK_F10] = "f10",
167 [SDLK_F11] = "f11",
168 [SDLK_F12] = "f12",
169 [SDLK_F13] = "f13",
170 [SDLK_F14] = "f14",
171 [SDLK_F15] = "f15",
172
173 [SDLK_NUMLOCK] = "numlock",
174 [SDLK_CAPSLOCK] = "caps lock",
175 [SDLK_SCROLLOCK] = "scroll lock",
176 [SDLK_RSHIFT] = "right shift",
177 [SDLK_LSHIFT] = "left shift",
178 [SDLK_RCTRL] = "right ctrl",
179 [SDLK_LCTRL] = "left ctrl",
180 [SDLK_RALT] = "right alt",
181 [SDLK_LALT] = "left alt",
182 [SDLK_RMETA] = "right meta",
183 [SDLK_LMETA] = "left meta",
184 [SDLK_LSUPER] = "left super", /* "Windows" keys */
185 [SDLK_RSUPER] = "right super",
186 [SDLK_MODE] = "alt gr",
187 [SDLK_COMPOSE] = "compose",
188};
189
190static struct in_sdl_state *state_alloc(int joy_numaxes)
191{
192 struct in_sdl_state *state;
193
194 state = calloc(1, sizeof(*state));
195 if (state == NULL) {
196 fprintf(stderr, "in_sdl: OOM\n");
197 return NULL;
198 }
199
200 if (joy_numaxes) {
201 state->abs_to_udlr = 1;
202 state->joy_numaxes = joy_numaxes;
203 state->joy_axis_keydown = malloc(joy_numaxes * sizeof(state->joy_axis_keydown[0]));
204 if (!state->joy_axis_keydown) {
205 free(state);
206 return NULL;
207 }
208 memset(state->joy_axis_keydown, 0xff, joy_numaxes * sizeof(state->joy_axis_keydown[0]));
209 }
210 return state;
211}
212
213static void in_sdl_probe(const in_drv_t *drv)
214{
215 const struct in_pdata *pdata = drv->pdata;
216 const char * const * key_names = in_sdl_keys;
217 struct in_sdl_state *state;
218 SDL_Joystick *joy;
219 int i, a, joycount;
220 char name[256];
221
222 if (pdata->key_names)
223 key_names = pdata->key_names;
224
225 if (!(state = state_alloc(0)))
226 return;
227
228 state->drv = drv;
229 in_register(IN_SDL_PREFIX "keys", -1, state, SDLK_LAST,
230 key_names, 0);
231 //SDL_EnableUNICODE(1);
232
233 /* joysticks go here too */
234 SDL_InitSubSystem(SDL_INIT_JOYSTICK);
235
236 joycount = SDL_NumJoysticks();
237 for (i = 0; i < joycount; i++) {
238 joy = SDL_JoystickOpen(i);
239 if (joy == NULL)
240 continue;
241
242 if (!(state = state_alloc(SDL_JoystickNumAxes(joy))))
243 break;
244 state->joy = joy;
245 state->joy_id = i;
246 state->joy_numbuttons = SDL_JoystickNumButtons(joy);
247 state->drv = drv;
248 for (a = 0; a < state->joy_numaxes; a++)
249 if (SDL_JoystickGetAxis(joy, a) < -16384)
250 state->joy_axis_as_btn |= 1u << a;
251
252 snprintf(name, sizeof(name), IN_SDL_PREFIX "%s", SDL_JoystickName(i));
253 in_register(name, -1, state, SDLK_LAST, key_names, 0);
254
255 printf(" %s: %d buttons %d axes %d hat(s), "
256 "guessed axis_as_btn mask: %x\n",
257 name, state->joy_numbuttons, state->joy_numaxes,
258 SDL_JoystickNumHats(joy), state->joy_axis_as_btn);
259 }
260
261 if (joycount > 0)
262 SDL_JoystickEventState(SDL_ENABLE);
263}
264
265static void in_sdl_free(void *drv_data)
266{
267 struct in_sdl_state *state = drv_data;
268
269 if (state != NULL) {
270 if (state->joy != NULL)
271 SDL_JoystickClose(state->joy);
272 free(state->joy_axis_keydown);
273 free(state);
274 }
275}
276
277static const char * const *
278in_sdl_get_key_names(const in_drv_t *drv, int *count)
279{
280 const struct in_pdata *pdata = drv->pdata;
281 *count = SDLK_LAST;
282
283 if (pdata->key_names)
284 return pdata->key_names;
285 return in_sdl_keys;
286}
287
288/* could use SDL_GetKeyState, but this gives better packing */
289static void update_keystate(keybits_t *keystate, int sym, int is_down)
290{
291 keybits_t *ks_word, mask;
292
293 mask = 1;
294 mask <<= sym & (KEYBITS_WORD_BITS - 1);
295 ks_word = keystate + sym / KEYBITS_WORD_BITS;
296 if (is_down)
297 *ks_word |= mask;
298 else
299 *ks_word &= ~mask;
300}
301
302static int get_keystate(keybits_t *keystate, int sym)
303{
304 keybits_t *ks_word, mask;
305
306 mask = 1;
307 mask <<= sym & (KEYBITS_WORD_BITS - 1);
308 ks_word = keystate + sym / KEYBITS_WORD_BITS;
309 return !!(*ks_word & mask);
310}
311
312static int handle_event(struct in_sdl_state *state, SDL_Event *event,
313 int *kc_out, int *down_out, int *emu_out)
314{
315 int emu;
316
317 if (event->type != SDL_KEYDOWN && event->type != SDL_KEYUP)
318 return -1;
319
320 emu = get_keystate(state->emu_keys, event->key.keysym.sym);
321 update_keystate(state->keystate, event->key.keysym.sym,
322 event->type == SDL_KEYDOWN);
323 if (kc_out != NULL)
324 *kc_out = event->key.keysym.sym;
325 if (down_out != NULL)
326 *down_out = event->type == SDL_KEYDOWN;
327 if (emu_out != NULL)
328 *emu_out = emu;
329
330 return 1;
331}
332
333static int handle_joy_event(struct in_sdl_state *state, SDL_Event *event,
334 int *kc_out, int *down_out, int *emu_out)
335{
336 static const int hat2uldr[4] = { SDLK_UP, SDLK_RIGHT, SDLK_DOWN, SDLK_LEFT };
337 int kc = -1, kc_prev = -1, down = 0, emu = 0, ret = 0, i, val, xor;
338 int kc_button_base = SDLK_WORLD_0;
339 int kc_axis_base = kc_button_base + state->joy_numbuttons;
340 int kc_hat_base = kc_axis_base + state->joy_numaxes;
341
342 switch (event->type) {
343 case SDL_JOYAXISMOTION:
344 if ((unsigned)event->jaxis.axis >= (unsigned)state->joy_numaxes)
345 return 1;
346 if (event->jaxis.which != state->joy_id)
347 return -2;
348 if (event->jaxis.value < -16384) {
349 if (state->abs_to_udlr && event->jaxis.axis < 2)
350 kc = event->jaxis.axis ? SDLK_UP : SDLK_LEFT;
351 // some pressure sensitive buttons appear as an axis that goes
352 // from -32768 (released) to 32767 (pressed) and there is no
353 // way to distinguish from ones centered at 0? :(
354 else if (!(state->joy_axis_as_btn & (1u << event->jaxis.axis)))
355 kc = kc_axis_base + event->jaxis.axis * 2;
356 down = 1;
357 }
358 else if (event->jaxis.value > 16384) {
359 if (state->abs_to_udlr && event->jaxis.axis < 2)
360 kc = event->jaxis.axis ? SDLK_DOWN : SDLK_RIGHT;
361 else
362 kc = kc_axis_base + event->jaxis.axis * 2 + 1;
363 down = 1;
364 }
365 kc_prev = state->joy_axis_keydown[event->jaxis.axis];
366 state->joy_axis_keydown[event->jaxis.axis] = kc;
367 if (kc == kc_prev)
368 return -1; // no simulated key change
369 if (kc >= 0 && kc_prev >= 0) {
370 // must release the old key first
371 state->joy_axis_keydown[event->jaxis.axis] = -1;
372 kc = kc_prev;
373 down = 0;
374 }
375 else if (kc_prev >= 0)
376 kc = kc_prev;
377 ret = 1;
378 break;
379
380 case SDL_JOYBUTTONDOWN:
381 case SDL_JOYBUTTONUP:
382 if (event->jbutton.which != state->joy_id)
383 return -2;
384 kc = kc_button_base + (int)event->jbutton.button;
385 down = event->jbutton.state == SDL_PRESSED;
386 ret = 1;
387 break;
388 case SDL_JOYHATMOTION:
389 if (event->jhat.which != state->joy_id)
390 return -2;
391 xor = event->jhat.value ^ state->joy_hat_down;
392 val = state->joy_hat_down = event->jhat.value;
393 for (i = 0; i < 4; i++, xor >>= 1, val >>= 1) {
394 if (xor & 1) {
395 if (event->jhat.hat)
396 kc = kc_hat_base + event->jhat.hat * 4 + i;
397 else
398 kc = hat2uldr[i];
399 down = val & 1;
400 ret = 1;
401 break;
402 }
403 }
404 if ((!ret || (xor >> ret)) && !state->hat_warned) {
405 // none, more than 1, or upper bits changed
406 fprintf(stderr, "in_sdl: unexpected hat behavior\n");
407 state->hat_warned = 1;
408 }
409 break;
410 default:
411 //printf("joy ev %d\n", event->type);
412 return -1;
413 }
414
415 if (ret) {
416 emu |= get_keystate(state->emu_keys, kc);
417 update_keystate(state->keystate, kc, down);
418 }
419 if (kc_out != NULL)
420 *kc_out = kc;
421 if (down_out != NULL)
422 *down_out = down;
423 if (emu_out != 0)
424 *emu_out = emu;
425
426 return ret;
427}
428
429#define JOY_EVENTS (SDL_JOYAXISMOTIONMASK | SDL_JOYBALLMOTIONMASK | SDL_JOYHATMOTIONMASK \
430 | SDL_JOYBUTTONDOWNMASK | SDL_JOYBUTTONUPMASK)
431
432static int collect_events(struct in_sdl_state *state, int *one_kc, int *one_down)
433{
434 SDL_Event events[8];
435 Uint32 mask = state->joy ? JOY_EVENTS : (SDL_ALLEVENTS & ~JOY_EVENTS);
436 int count, maxcount, is_emukey = 0;
437 int i = 0, ret = 0, retval = 0;
438 SDL_Event *event;
439
440 SDL_PumpEvents();
441
442 maxcount = ARRAY_SIZE(events);
443 if ((count = SDL_PeepEvents(events, maxcount, SDL_GETEVENT, mask)) > 0) {
444 for (i = 0; i < count; i++) {
445 event = &events[i];
446 if (state->joy) {
447 ret = handle_joy_event(state,
448 event, one_kc, one_down, &is_emukey);
449 } else {
450 ret = handle_event(state,
451 event, one_kc, one_down, &is_emukey);
452 }
453 if (ret < 0) {
454 switch (ret) {
455 case -2:
456 SDL_PushEvent(event);
457 break;
458 default:
459 if (event->type == SDL_VIDEORESIZE) {
460 state->redraw = 1;
461 state->revent = *event;
462 } else if (event->type == SDL_VIDEOEXPOSE) {
463 if (state->revent.type == SDL_NOEVENT) {
464 state->redraw = 1;
465 state->revent.type = SDL_VIDEOEXPOSE;
466 }
467 } else
468 if ((event->type == SDL_MOUSEBUTTONDOWN) ||
469 (event->type == SDL_MOUSEBUTTONUP)) {
470 int mask = SDL_BUTTON(event->button.button);
471 if (event->button.state == SDL_PRESSED)
472 state->mevent.motion.state |= mask;
473 else state->mevent.motion.state &= ~mask;
474 } else if (event->type == SDL_MOUSEMOTION) {
475 event->motion.xrel += state->mevent.motion.xrel;
476 event->motion.yrel += state->mevent.motion.yrel;
477 state->mevent = *event;
478 }
479 else if (ext_event_handler != NULL)
480 ext_event_handler(event);
481 break;
482 }
483 continue;
484 }
485
486 retval |= ret;
487 if ((is_emukey || one_kc != NULL) && retval)
488 {
489 break;
490 }
491 }
492 }
493
494 // if the event queue has been emptied and resize/expose events were in it
495 if (state->redraw && count == 0) {
496 if (ext_event_handler != NULL)
497 ext_event_handler(&state->revent);
498 state->redraw = 0;
499 state->revent.type = SDL_NOEVENT;
500 // dummy key event to force returning from the key loop,
501 // so the application has a chance to redraw the window
502 if (one_kc != NULL) {
503 *one_kc = SDLK_UNKNOWN;
504 retval |= 1;
505 }
506 if (one_down != NULL)
507 *one_down = 1;
508 } else
509 i++;
510 // don't lose events other devices might want to handle
511 if (i < count)
512 SDL_PeepEvents(events+i, count-i, SDL_ADDEVENT, mask);
513 return retval;
514}
515
516static int in_sdl_update(void *drv_data, const int *binds, int *result)
517{
518 struct in_sdl_state *state = drv_data;
519 keybits_t mask;
520 int i, sym, bit, b;
521
522 collect_events(state, NULL, NULL);
523
524 for (i = 0; i < SDLK_LAST / KEYBITS_WORD_BITS + 1; i++) {
525 mask = state->keystate[i];
526 if (mask == 0)
527 continue;
528 for (bit = 0; mask != 0; bit++, mask >>= 1) {
529 if ((mask & 1) == 0)
530 continue;
531 sym = i * KEYBITS_WORD_BITS + bit;
532
533 for (b = 0; b < IN_BINDTYPE_COUNT; b++)
534 result[b] |= binds[IN_BIND_OFFS(sym, b)];
535 }
536 }
537
538 return 0;
539}
540
541static int in_sdl_update_kbd(void *drv_data, const int *binds, int *result)
542{
543 struct in_sdl_state *state = drv_data;
544 keybits_t mask;
545 int i, sym, bit, b = 0;
546
547 collect_events(state, NULL, NULL);
548
549 for (i = 0; i < SDLK_LAST / KEYBITS_WORD_BITS + 1; i++) {
550 mask = state->keystate[i];
551 if (mask == 0)
552 continue;
553 for (bit = 0; mask != 0; bit++, mask >>= 1) {
554 if ((mask & 1) == 0)
555 continue;
556 sym = i * KEYBITS_WORD_BITS + bit;
557 result[b++] = binds[sym];
558 }
559 }
560
561 return b;
562}
563
564static int in_sdl_update_analog(void *drv_data, int axis_id, int *result)
565{
566 struct in_sdl_state *state = drv_data;
567 int v;
568
569 if (!state || !state->joy || !result)
570 return -1;
571 if ((unsigned)axis_id >= (unsigned)state->joy_numaxes)
572 return -1;
573
574 v = SDL_JoystickGetAxis(state->joy, axis_id);
575
576 // -32768...32767 -> -IN_ABS_RANGE...IN_ABS_RANGE
577 *result = (v + ((v >> 31) | 1)) / (32768 / IN_ABS_RANGE);
578 return 0;
579}
580
581static int in_sdl_update_pointer(void *drv_data, int id, int *result)
582{
583 struct in_sdl_state *state = drv_data;
584 int max;
585
586 *result = 0;
587
588 switch (id) {
589 // absolute position, clipped at the window/screen border
590 case 0: if ((max = state->revent.resize.w))
591 *result = state->mevent.motion.x * 2*1024/max - 1024;
592 break;
593 case 1: if ((max = state->revent.resize.h))
594 *result = state->mevent.motion.y * 2*1024/max - 1024;
595 break;
596 // relative mouse movements since last query
597 case 2: if ((max = state->revent.resize.w))
598 *result = state->mevent.motion.xrel * 2*1024/max;
599 state->mevent.motion.xrel = 0;
600 break;
601 case 3: if ((max = state->revent.resize.h))
602 *result = state->mevent.motion.yrel * 2*1024/max;
603 state->mevent.motion.yrel = 0;
604 break;
605 // buttons
606 case -1: *result = state->mevent.motion.state;
607 break;
608 default: return -1;
609 }
610
611 return 0;
612}
613
614static int in_sdl_update_keycode(void *drv_data, int *is_down)
615{
616 struct in_sdl_state *state = drv_data;
617 int ret_kc = -1, ret_down = 0;
618
619 collect_events(state, &ret_kc, &ret_down);
620
621 if (is_down != NULL)
622 *is_down = ret_down;
623
624 return ret_kc;
625}
626
627static int in_sdl_menu_translate(void *drv_data, int keycode, char *charcode)
628{
629 struct in_sdl_state *state = drv_data;
630 const struct in_pdata *pdata = state->drv->pdata;
631 const char * const * key_names = in_sdl_keys;
632 const struct menu_keymap *map;
633 int map_len;
634 int ret = 0;
635 int i;
636
637 if (pdata->key_names)
638 key_names = pdata->key_names;
639
640 if (state->joy) {
641 map = pdata->joy_map;
642 map_len = pdata->jmap_size;
643 } else {
644 map = pdata->key_map;
645 map_len = pdata->kmap_size;
646 }
647
648 if (keycode < 0)
649 {
650 /* menu -> kc */
651 keycode = -keycode;
652 for (i = 0; i < map_len; i++)
653 if (map[i].pbtn == keycode)
654 return map[i].key;
655 }
656 else
657 {
658 if (keycode == SDLK_UNKNOWN)
659 ret = PBTN_RDRAW;
660 else
661 for (i = 0; i < map_len; i++) {
662 if (map[i].key == keycode) {
663 ret = map[i].pbtn;
664 break;
665 }
666 }
667
668 if (charcode != NULL && (unsigned int)keycode < SDLK_LAST &&
669 key_names[keycode] != NULL && key_names[keycode][1] == 0)
670 {
671 ret |= PBTN_CHAR;
672 *charcode = key_names[keycode][0];
673 }
674 }
675
676 return ret;
677}
678
679static int in_sdl_clean_binds(void *drv_data, int *binds, int *def_binds)
680{
681 struct in_sdl_state *state = drv_data;
682 int i, t, cnt = 0;
683
684 memset(state->emu_keys, 0, sizeof(state->emu_keys));
685 for (t = 0; t < IN_BINDTYPE_COUNT; t++) {
686 for (i = 0; i < SDLK_LAST; i++) {
687 int offs = IN_BIND_OFFS(i, t);
688 if (state->joy && i < SDLK_WORLD_0)
689 binds[offs] = def_binds[offs] = 0;
690 if (binds[offs]) {
691 if (t == IN_BINDTYPE_EMU)
692 update_keystate(state->emu_keys, i, 1);
693 cnt ++;
694 }
695 }
696 }
697
698 return cnt;
699}
700
701static int in_sdl_get_config(void *drv_data, enum in_cfg_opt what, int *val)
702{
703 struct in_sdl_state *state = drv_data;
704
705 switch (what) {
706 case IN_CFG_ABS_AXIS_COUNT:
707 *val = state->joy_numaxes;
708 break;
709 case IN_CFG_ANALOG_MAP_ULDR:
710 *val = state->abs_to_udlr;
711 break;
712 default:
713 return -1;
714 }
715
716 return 0;
717}
718
719static int in_sdl_set_config(void *drv_data, enum in_cfg_opt what, int val)
720{
721 struct in_sdl_state *state = drv_data;
722 size_t i;
723
724 switch (what) {
725 case IN_CFG_ANALOG_MAP_ULDR:
726 state->abs_to_udlr = val ? 1 : 0;
727 for (i = 0; !val && i < state->joy_numaxes; i++) {
728 if (state->joy_axis_keydown[i] < 0)
729 continue;
730 update_keystate(state->keystate, state->joy_axis_keydown[i], 0);
731 state->joy_axis_keydown[i] = -1;
732 }
733 break;
734 default:
735 return -1;
736 }
737
738 return 0;
739}
740
741static const in_drv_t in_sdl_drv = {
742 .prefix = IN_SDL_PREFIX,
743 .probe = in_sdl_probe,
744 .free = in_sdl_free,
745 .get_key_names = in_sdl_get_key_names,
746 .update = in_sdl_update,
747 .update_kbd = in_sdl_update_kbd,
748 .update_analog = in_sdl_update_analog,
749 .update_pointer = in_sdl_update_pointer,
750 .update_keycode = in_sdl_update_keycode,
751 .menu_translate = in_sdl_menu_translate,
752 .clean_binds = in_sdl_clean_binds,
753 .get_config = in_sdl_get_config,
754 .set_config = in_sdl_set_config,
755};
756
757int in_sdl_init(const struct in_pdata *pdata, void (*handler)(void *event))
758{
759 if (!pdata) {
760 fprintf(stderr, "in_sdl: Missing input platform data\n");
761 return -1;
762 }
763
764 in_register_driver(&in_sdl_drv, pdata->defbinds, pdata->kbd_map, pdata);
765 ext_event_handler = handler;
766 return 0;
767}