Commit | Line | Data |
---|---|---|
d1dc092f | 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. | |
f89d8471 | 8 | * - MAME license. |
d1dc092f | 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 */ | |
19 | typedef unsigned long keybits_t; | |
20 | #define KEYBITS_WORD_BITS (sizeof(keybits_t) * 8) | |
21 | ||
e3c0b886 | 22 | #ifndef ARRAY_SIZE |
23 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) | |
24 | #endif | |
25 | ||
6407ad5b | 26 | struct in_sdl_state { |
c19e28f6 | 27 | const in_drv_t *drv; |
6407ad5b | 28 | SDL_Joystick *joy; |
29 | int joy_id; | |
ec6c16b1 | 30 | int joy_numaxes; |
31 | int joy_numbuttons; | |
32 | int *joy_axis_keydown; | |
33 | int joy_hat_down; | |
f5e4164a | 34 | unsigned int joy_axis_as_btn; // bitmask; vs axes of centered sticks |
e3c0b886 | 35 | unsigned int redraw:1; |
36 | unsigned int abs_to_udlr:1; | |
37 | unsigned int hat_warned:1; | |
92bd9c36 | 38 | SDL_Event revent; |
7bd23aaf | 39 | SDL_Event mevent; // last mouse event |
6407ad5b | 40 | keybits_t keystate[SDLK_LAST / KEYBITS_WORD_BITS + 1]; |
271f9001 | 41 | // emulator keys should always be processed immediately lest one is lost |
42 | keybits_t emu_keys[SDLK_LAST / KEYBITS_WORD_BITS + 1]; | |
6407ad5b | 43 | }; |
44 | ||
9227a777 | 45 | static void (*ext_event_handler)(void *event); |
46 | ||
d1dc092f | 47 | static 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] = ":", | |
d1f5849c | 80 | [SDLK_SEMICOLON] = ";", |
d1dc092f | 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 | ||
50d625e8 | 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 | ||
d1dc092f | 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", | |
d1dc092f | 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 | ||
ec6c16b1 | 190 | static struct in_sdl_state *state_alloc(int joy_numaxes) |
e3c0b886 | 191 | { |
192 | struct in_sdl_state *state; | |
e3c0b886 | 193 | |
194 | state = calloc(1, sizeof(*state)); | |
195 | if (state == NULL) { | |
196 | fprintf(stderr, "in_sdl: OOM\n"); | |
197 | return NULL; | |
198 | } | |
199 | ||
ec6c16b1 | 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 | } | |
e3c0b886 | 210 | return state; |
211 | } | |
212 | ||
c19e28f6 | 213 | static void in_sdl_probe(const in_drv_t *drv) |
d1dc092f | 214 | { |
d685ce46 PC |
215 | const struct in_pdata *pdata = drv->pdata; |
216 | const char * const * key_names = in_sdl_keys; | |
6407ad5b | 217 | struct in_sdl_state *state; |
218 | SDL_Joystick *joy; | |
f5e4164a | 219 | int i, a, joycount; |
6407ad5b | 220 | char name[256]; |
d1dc092f | 221 | |
d685ce46 PC |
222 | if (pdata->key_names) |
223 | key_names = pdata->key_names; | |
224 | ||
ec6c16b1 | 225 | if (!(state = state_alloc(0))) |
d1dc092f | 226 | return; |
d1dc092f | 227 | |
c19e28f6 | 228 | state->drv = drv; |
6407ad5b | 229 | in_register(IN_SDL_PREFIX "keys", -1, state, SDLK_LAST, |
d685ce46 | 230 | key_names, 0); |
e0d65e94 | 231 | //SDL_EnableUNICODE(1); |
6407ad5b | 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 | ||
ec6c16b1 | 242 | if (!(state = state_alloc(SDL_JoystickNumAxes(joy)))) |
6407ad5b | 243 | break; |
6407ad5b | 244 | state->joy = joy; |
245 | state->joy_id = i; | |
ec6c16b1 | 246 | state->joy_numbuttons = SDL_JoystickNumButtons(joy); |
c19e28f6 | 247 | state->drv = drv; |
f5e4164a | 248 | for (a = 0; a < state->joy_numaxes; a++) |
249 | if (SDL_JoystickGetAxis(joy, a) < -16384) | |
250 | state->joy_axis_as_btn |= 1u << a; | |
6407ad5b | 251 | |
252 | snprintf(name, sizeof(name), IN_SDL_PREFIX "%s", SDL_JoystickName(i)); | |
d685ce46 | 253 | in_register(name, -1, state, SDLK_LAST, key_names, 0); |
f5e4164a | 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); | |
6407ad5b | 259 | } |
260 | ||
261 | if (joycount > 0) | |
262 | SDL_JoystickEventState(SDL_ENABLE); | |
d1dc092f | 263 | } |
264 | ||
265 | static void in_sdl_free(void *drv_data) | |
266 | { | |
6407ad5b | 267 | struct in_sdl_state *state = drv_data; |
d1dc092f | 268 | |
6407ad5b | 269 | if (state != NULL) { |
270 | if (state->joy != NULL) | |
271 | SDL_JoystickClose(state->joy); | |
ec6c16b1 | 272 | free(state->joy_axis_keydown); |
6407ad5b | 273 | free(state); |
274 | } | |
d1dc092f | 275 | } |
276 | ||
277 | static const char * const * | |
d685ce46 | 278 | in_sdl_get_key_names(const in_drv_t *drv, int *count) |
d1dc092f | 279 | { |
d685ce46 | 280 | const struct in_pdata *pdata = drv->pdata; |
d1dc092f | 281 | *count = SDLK_LAST; |
d685ce46 PC |
282 | |
283 | if (pdata->key_names) | |
284 | return pdata->key_names; | |
d1dc092f | 285 | return in_sdl_keys; |
286 | } | |
287 | ||
288 | /* could use SDL_GetKeyState, but this gives better packing */ | |
289 | static 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 | ||
271f9001 | 302 | static 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 | ||
6407ad5b | 312 | static int handle_event(struct in_sdl_state *state, SDL_Event *event, |
271f9001 | 313 | int *kc_out, int *down_out, int *emu_out) |
d1dc092f | 314 | { |
271f9001 | 315 | int emu; |
316 | ||
6407ad5b | 317 | if (event->type != SDL_KEYDOWN && event->type != SDL_KEYUP) |
9227a777 | 318 | return -1; |
d1dc092f | 319 | |
271f9001 | 320 | emu = get_keystate(state->emu_keys, event->key.keysym.sym); |
6407ad5b | 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; | |
bededcb4 | 327 | if (emu_out != NULL) |
271f9001 | 328 | *emu_out = emu; |
6407ad5b | 329 | |
330 | return 1; | |
331 | } | |
d1dc092f | 332 | |
6407ad5b | 333 | static int handle_joy_event(struct in_sdl_state *state, SDL_Event *event, |
271f9001 | 334 | int *kc_out, int *down_out, int *emu_out) |
6407ad5b | 335 | { |
ec6c16b1 | 336 | static const int hat2uldr[4] = { SDLK_UP, SDLK_RIGHT, SDLK_DOWN, SDLK_LEFT }; |
e3c0b886 | 337 | int kc = -1, kc_prev = -1, down = 0, emu = 0, ret = 0, i, val, xor; |
ec6c16b1 | 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; | |
6407ad5b | 341 | |
6407ad5b | 342 | switch (event->type) { |
343 | case SDL_JOYAXISMOTION: | |
ec6c16b1 | 344 | if ((unsigned)event->jaxis.axis >= (unsigned)state->joy_numaxes) |
345 | return 1; | |
18306c32 VL |
346 | if (event->jaxis.which != state->joy_id) |
347 | return -2; | |
e3c0b886 | 348 | if (event->jaxis.value < -16384) { |
ec6c16b1 | 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? :( | |
f5e4164a | 354 | else if (!(state->joy_axis_as_btn & (1u << event->jaxis.axis))) |
355 | kc = kc_axis_base + event->jaxis.axis * 2; | |
6407ad5b | 356 | down = 1; |
6407ad5b | 357 | } |
358 | else if (event->jaxis.value > 16384) { | |
ec6c16b1 | 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; | |
6407ad5b | 363 | down = 1; |
6407ad5b | 364 | } |
ec6c16b1 | 365 | kc_prev = state->joy_axis_keydown[event->jaxis.axis]; |
366 | state->joy_axis_keydown[event->jaxis.axis] = kc; | |
e3c0b886 | 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 | |
ec6c16b1 | 371 | state->joy_axis_keydown[event->jaxis.axis] = -1; |
e3c0b886 | 372 | kc = kc_prev; |
373 | down = 0; | |
374 | } | |
375 | else if (kc_prev >= 0) | |
376 | kc = kc_prev; | |
377 | ret = 1; | |
6407ad5b | 378 | break; |
379 | ||
380 | case SDL_JOYBUTTONDOWN: | |
381 | case SDL_JOYBUTTONUP: | |
18306c32 VL |
382 | if (event->jbutton.which != state->joy_id) |
383 | return -2; | |
ec6c16b1 | 384 | kc = kc_button_base + (int)event->jbutton.button; |
6407ad5b | 385 | down = event->jbutton.state == SDL_PRESSED; |
386 | ret = 1; | |
387 | break; | |
e3c0b886 | 388 | case SDL_JOYHATMOTION: |
389 | if (event->jhat.which != state->joy_id) | |
390 | return -2; | |
ec6c16b1 | 391 | xor = event->jhat.value ^ state->joy_hat_down; |
392 | val = state->joy_hat_down = event->jhat.value; | |
e3c0b886 | 393 | for (i = 0; i < 4; i++, xor >>= 1, val >>= 1) { |
394 | if (xor & 1) { | |
ec6c16b1 | 395 | if (event->jhat.hat) |
396 | kc = kc_hat_base + event->jhat.hat * 4 + i; | |
397 | else | |
398 | kc = hat2uldr[i]; | |
e3c0b886 | 399 | down = val & 1; |
e3c0b886 | 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; | |
9227a777 | 410 | default: |
e3c0b886 | 411 | //printf("joy ev %d\n", event->type); |
9227a777 | 412 | return -1; |
d1dc092f | 413 | } |
414 | ||
271f9001 | 415 | if (ret) { |
416 | emu |= get_keystate(state->emu_keys, kc); | |
6407ad5b | 417 | update_keystate(state->keystate, kc, down); |
271f9001 | 418 | } |
6407ad5b | 419 | if (kc_out != NULL) |
420 | *kc_out = kc; | |
421 | if (down_out != NULL) | |
422 | *down_out = down; | |
271f9001 | 423 | if (emu_out != 0) |
424 | *emu_out = emu; | |
6407ad5b | 425 | |
426 | return ret; | |
427 | } | |
428 | ||
429 | #define JOY_EVENTS (SDL_JOYAXISMOTIONMASK | SDL_JOYBALLMOTIONMASK | SDL_JOYHATMOTIONMASK \ | |
430 | | SDL_JOYBUTTONDOWNMASK | SDL_JOYBUTTONUPMASK) | |
431 | ||
432 | static int collect_events(struct in_sdl_state *state, int *one_kc, int *one_down) | |
433 | { | |
7cddc27a | 434 | SDL_Event events[8]; |
6407ad5b | 435 | Uint32 mask = state->joy ? JOY_EVENTS : (SDL_ALLEVENTS & ~JOY_EVENTS); |
bededcb4 | 436 | int count, maxcount, is_emukey = 0; |
7cddc27a | 437 | int i = 0, ret = 0, retval = 0; |
18306c32 | 438 | SDL_Event *event; |
6407ad5b | 439 | |
6407ad5b | 440 | SDL_PumpEvents(); |
18306c32 | 441 | |
e3c0b886 | 442 | maxcount = ARRAY_SIZE(events); |
7cddc27a | 443 | if ((count = SDL_PeepEvents(events, maxcount, SDL_GETEVENT, mask)) > 0) { |
6407ad5b | 444 | for (i = 0; i < count; i++) { |
18306c32 | 445 | event = &events[i]; |
271f9001 | 446 | if (state->joy) { |
6407ad5b | 447 | ret = handle_joy_event(state, |
271f9001 | 448 | event, one_kc, one_down, &is_emukey); |
449 | } else { | |
6407ad5b | 450 | ret = handle_event(state, |
271f9001 | 451 | event, one_kc, one_down, &is_emukey); |
452 | } | |
18306c32 VL |
453 | if (ret < 0) { |
454 | switch (ret) { | |
455 | case -2: | |
456 | SDL_PushEvent(event); | |
457 | break; | |
458 | default: | |
f0615849 | 459 | if (event->type == SDL_VIDEORESIZE) { |
92bd9c36 | 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; | |
7bd23aaf | 465 | state->revent.type = SDL_VIDEOEXPOSE; |
92bd9c36 | 466 | } |
f0615849 | 467 | } else |
7bd23aaf | 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; | |
ce684c88 | 474 | } else if (event->type == SDL_MOUSEMOTION) { |
475 | event->motion.xrel += state->mevent.motion.xrel; | |
476 | event->motion.yrel += state->mevent.motion.yrel; | |
7bd23aaf | 477 | state->mevent = *event; |
ce684c88 | 478 | } |
7bd23aaf | 479 | else if (ext_event_handler != NULL) |
18306c32 VL |
480 | ext_event_handler(event); |
481 | break; | |
482 | } | |
7cddc27a | 483 | continue; |
9227a777 | 484 | } |
485 | ||
6407ad5b | 486 | retval |= ret; |
bededcb4 | 487 | if ((is_emukey || one_kc != NULL) && retval) |
18306c32 | 488 | { |
7cddc27a | 489 | break; |
18306c32 | 490 | } |
6407ad5b | 491 | } |
492 | } | |
493 | ||
92bd9c36 | 494 | // if the event queue has been emptied and resize/expose events were in it |
495 | if (state->redraw && count == 0) { | |
f0615849 | 496 | if (ext_event_handler != NULL) |
92bd9c36 | 497 | ext_event_handler(&state->revent); |
498 | state->redraw = 0; | |
499 | state->revent.type = SDL_NOEVENT; | |
7cddc27a | 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 | |
c825b167 | 509 | i++; |
7cddc27a | 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); | |
6407ad5b | 513 | return retval; |
514 | } | |
515 | ||
516 | static 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 | ||
d1dc092f | 524 | for (i = 0; i < SDLK_LAST / KEYBITS_WORD_BITS + 1; i++) { |
6407ad5b | 525 | mask = state->keystate[i]; |
d1dc092f | 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 | ||
4acbd7fe | 541 | static int in_sdl_update_kbd(void *drv_data, const int *binds, int *result) |
b047d2e2 | 542 | { |
543 | struct in_sdl_state *state = drv_data; | |
544 | keybits_t mask; | |
842f0c7c | 545 | int i, sym, bit, b = 0; |
b047d2e2 | 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; | |
842f0c7c | 557 | result[b++] = binds[sym]; |
b047d2e2 | 558 | } |
559 | } | |
560 | ||
842f0c7c | 561 | return b; |
b047d2e2 | 562 | } |
563 | ||
9874363e | 564 | static 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; | |
ec6c16b1 | 571 | if ((unsigned)axis_id >= (unsigned)state->joy_numaxes) |
9874363e | 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 | ||
b020891a | 581 | static int in_sdl_update_pointer(void *drv_data, int id, int *result) |
7bd23aaf | 582 | { |
583 | struct in_sdl_state *state = drv_data; | |
584 | int max; | |
585 | ||
7bd23aaf | 586 | *result = 0; |
ce684c88 | 587 | |
b020891a | 588 | switch (id) { |
ce684c88 | 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 | } | |
7bd23aaf | 610 | |
611 | return 0; | |
612 | } | |
b047d2e2 | 613 | |
d1dc092f | 614 | static int in_sdl_update_keycode(void *drv_data, int *is_down) |
615 | { | |
6407ad5b | 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 | ||
d1dc092f | 621 | if (is_down != NULL) |
622 | *is_down = ret_down; | |
623 | ||
624 | return ret_kc; | |
625 | } | |
626 | ||
d1dc092f | 627 | static int in_sdl_menu_translate(void *drv_data, int keycode, char *charcode) |
628 | { | |
6407ad5b | 629 | struct in_sdl_state *state = drv_data; |
c19e28f6 | 630 | const struct in_pdata *pdata = state->drv->pdata; |
d685ce46 | 631 | const char * const * key_names = in_sdl_keys; |
6407ad5b | 632 | const struct menu_keymap *map; |
633 | int map_len; | |
d1dc092f | 634 | int ret = 0; |
635 | int i; | |
636 | ||
d685ce46 PC |
637 | if (pdata->key_names) |
638 | key_names = pdata->key_names; | |
639 | ||
c19e28f6 PC |
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 | } | |
6407ad5b | 647 | |
d1dc092f | 648 | if (keycode < 0) |
649 | { | |
650 | /* menu -> kc */ | |
651 | keycode = -keycode; | |
6407ad5b | 652 | for (i = 0; i < map_len; i++) |
653 | if (map[i].pbtn == keycode) | |
654 | return map[i].key; | |
d1dc092f | 655 | } |
656 | else | |
657 | { | |
bededcb4 | 658 | if (keycode == SDLK_UNKNOWN) |
659 | ret = PBTN_RDRAW; | |
660 | else | |
6407ad5b | 661 | for (i = 0; i < map_len; i++) { |
662 | if (map[i].key == keycode) { | |
663 | ret = map[i].pbtn; | |
d1dc092f | 664 | break; |
665 | } | |
666 | } | |
667 | ||
668 | if (charcode != NULL && (unsigned int)keycode < SDLK_LAST && | |
d685ce46 | 669 | key_names[keycode] != NULL && key_names[keycode][1] == 0) |
d1dc092f | 670 | { |
671 | ret |= PBTN_CHAR; | |
d685ce46 | 672 | *charcode = key_names[keycode][0]; |
d1dc092f | 673 | } |
674 | } | |
675 | ||
676 | return ret; | |
677 | } | |
678 | ||
5d8d9079 | 679 | static int in_sdl_clean_binds(void *drv_data, int *binds, int *def_binds) |
271f9001 | 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)); | |
5d8d9079 | 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]) { | |
271f9001 | 691 | if (t == IN_BINDTYPE_EMU) |
692 | update_keystate(state->emu_keys, i, 1); | |
693 | cnt ++; | |
694 | } | |
5d8d9079 | 695 | } |
696 | } | |
271f9001 | 697 | |
698 | return cnt; | |
699 | } | |
700 | ||
3f4a964c | 701 | static int in_sdl_get_config(void *drv_data, enum in_cfg_opt what, int *val) |
9874363e | 702 | { |
703 | struct in_sdl_state *state = drv_data; | |
704 | ||
705 | switch (what) { | |
706 | case IN_CFG_ABS_AXIS_COUNT: | |
ec6c16b1 | 707 | *val = state->joy_numaxes; |
9874363e | 708 | break; |
e3c0b886 | 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 | ||
719 | static 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; | |
ec6c16b1 | 727 | for (i = 0; !val && i < state->joy_numaxes; i++) { |
728 | if (state->joy_axis_keydown[i] < 0) | |
e3c0b886 | 729 | continue; |
ec6c16b1 | 730 | update_keystate(state->keystate, state->joy_axis_keydown[i], 0); |
731 | state->joy_axis_keydown[i] = -1; | |
e3c0b886 | 732 | } |
733 | break; | |
9874363e | 734 | default: |
735 | return -1; | |
736 | } | |
737 | ||
738 | return 0; | |
739 | } | |
740 | ||
d1dc092f | 741 | static const in_drv_t in_sdl_drv = { |
b047d2e2 | 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, | |
4acbd7fe | 747 | .update_kbd = in_sdl_update_kbd, |
9874363e | 748 | .update_analog = in_sdl_update_analog, |
b020891a | 749 | .update_pointer = in_sdl_update_pointer, |
b047d2e2 | 750 | .update_keycode = in_sdl_update_keycode, |
751 | .menu_translate = in_sdl_menu_translate, | |
752 | .clean_binds = in_sdl_clean_binds, | |
9874363e | 753 | .get_config = in_sdl_get_config, |
e3c0b886 | 754 | .set_config = in_sdl_set_config, |
d1dc092f | 755 | }; |
756 | ||
c19e28f6 | 757 | int in_sdl_init(const struct in_pdata *pdata, void (*handler)(void *event)) |
d1dc092f | 758 | { |
c19e28f6 PC |
759 | if (!pdata) { |
760 | fprintf(stderr, "in_sdl: Missing input platform data\n"); | |
761 | return -1; | |
762 | } | |
763 | ||
4acbd7fe | 764 | in_register_driver(&in_sdl_drv, pdata->defbinds, pdata->kbd_map, pdata); |
9227a777 | 765 | ext_event_handler = handler; |
c19e28f6 | 766 | return 0; |
d1dc092f | 767 | } |