frontend: input: pass default binds as argument
[pcsx_rearmed.git] / frontend / common / in_sdl.c
CommitLineData
7badc935 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 * See the COPYING file in the top-level directory.
9 */
10
11#include <stdio.h>
12#include <SDL.h>
13#include "input.h"
14#include "in_sdl.h"
15
16#define IN_SDL_PREFIX "sdl:"
17/* should be machine word for best performace */
18typedef unsigned long keybits_t;
19#define KEYBITS_WORD_BITS (sizeof(keybits_t) * 8)
20
21static const char * const in_sdl_keys[SDLK_LAST] = {
22 [SDLK_BACKSPACE] = "backspace",
23 [SDLK_TAB] = "tab",
24 [SDLK_CLEAR] = "clear",
25 [SDLK_RETURN] = "return",
26 [SDLK_PAUSE] = "pause",
27 [SDLK_ESCAPE] = "escape",
28 [SDLK_SPACE] = "space",
29 [SDLK_EXCLAIM] = "!",
30 [SDLK_QUOTEDBL] = "\"",
31 [SDLK_HASH] = "#",
32 [SDLK_DOLLAR] = "$",
33 [SDLK_AMPERSAND] = "&",
34 [SDLK_QUOTE] = "'",
35 [SDLK_LEFTPAREN] = "(",
36 [SDLK_RIGHTPAREN] = ")",
37 [SDLK_ASTERISK] = "*",
38 [SDLK_PLUS] = "+",
39 [SDLK_COMMA] = ",",
40 [SDLK_MINUS] = "-",
41 [SDLK_PERIOD] = ".",
42 [SDLK_SLASH] = "/",
43 [SDLK_0] = "0",
44 [SDLK_1] = "1",
45 [SDLK_2] = "2",
46 [SDLK_3] = "3",
47 [SDLK_4] = "4",
48 [SDLK_5] = "5",
49 [SDLK_6] = "6",
50 [SDLK_7] = "7",
51 [SDLK_8] = "8",
52 [SDLK_9] = "9",
53 [SDLK_COLON] = ":",
54 [SDLK_SEMICOLON] = ",",
55 [SDLK_LESS] = "<",
56 [SDLK_EQUALS] = "=",
57 [SDLK_GREATER] = ">",
58 [SDLK_QUESTION] = "?",
59 [SDLK_AT] = "@",
60 [SDLK_LEFTBRACKET] = "[",
61 [SDLK_BACKSLASH] = "\\",
62 [SDLK_RIGHTBRACKET] = "]",
63 [SDLK_CARET] = "^",
64 [SDLK_UNDERSCORE] = "_",
65 [SDLK_BACKQUOTE] = "`",
66 [SDLK_a] = "a",
67 [SDLK_b] = "b",
68 [SDLK_c] = "c",
69 [SDLK_d] = "d",
70 [SDLK_e] = "e",
71 [SDLK_f] = "f",
72 [SDLK_g] = "g",
73 [SDLK_h] = "h",
74 [SDLK_i] = "i",
75 [SDLK_j] = "j",
76 [SDLK_k] = "k",
77 [SDLK_l] = "l",
78 [SDLK_m] = "m",
79 [SDLK_n] = "n",
80 [SDLK_o] = "o",
81 [SDLK_p] = "p",
82 [SDLK_q] = "q",
83 [SDLK_r] = "r",
84 [SDLK_s] = "s",
85 [SDLK_t] = "t",
86 [SDLK_u] = "u",
87 [SDLK_v] = "v",
88 [SDLK_w] = "w",
89 [SDLK_x] = "x",
90 [SDLK_y] = "y",
91 [SDLK_z] = "z",
92 [SDLK_DELETE] = "delete",
93
94 [SDLK_KP0] = "[0]",
95 [SDLK_KP1] = "[1]",
96 [SDLK_KP2] = "[2]",
97 [SDLK_KP3] = "[3]",
98 [SDLK_KP4] = "[4]",
99 [SDLK_KP5] = "[5]",
100 [SDLK_KP6] = "[6]",
101 [SDLK_KP7] = "[7]",
102 [SDLK_KP8] = "[8]",
103 [SDLK_KP9] = "[9]",
104 [SDLK_KP_PERIOD] = "[.]",
105 [SDLK_KP_DIVIDE] = "[/]",
106 [SDLK_KP_MULTIPLY] = "[*]",
107 [SDLK_KP_MINUS] = "[-]",
108 [SDLK_KP_PLUS] = "[+]",
109 [SDLK_KP_ENTER] = "enter",
110 [SDLK_KP_EQUALS] = "equals",
111
112 [SDLK_UP] = "up",
113 [SDLK_DOWN] = "down",
114 [SDLK_RIGHT] = "right",
115 [SDLK_LEFT] = "left",
116 [SDLK_DOWN] = "down",
117 [SDLK_INSERT] = "insert",
118 [SDLK_HOME] = "home",
119 [SDLK_END] = "end",
120 [SDLK_PAGEUP] = "page up",
121 [SDLK_PAGEDOWN] = "page down",
122
123 [SDLK_F1] = "f1",
124 [SDLK_F2] = "f2",
125 [SDLK_F3] = "f3",
126 [SDLK_F4] = "f4",
127 [SDLK_F5] = "f5",
128 [SDLK_F6] = "f6",
129 [SDLK_F7] = "f7",
130 [SDLK_F8] = "f8",
131 [SDLK_F9] = "f9",
132 [SDLK_F10] = "f10",
133 [SDLK_F11] = "f11",
134 [SDLK_F12] = "f12",
135 [SDLK_F13] = "f13",
136 [SDLK_F14] = "f14",
137 [SDLK_F15] = "f15",
138
139 [SDLK_NUMLOCK] = "numlock",
140 [SDLK_CAPSLOCK] = "caps lock",
141 [SDLK_SCROLLOCK] = "scroll lock",
142 [SDLK_RSHIFT] = "right shift",
143 [SDLK_LSHIFT] = "left shift",
144 [SDLK_RCTRL] = "right ctrl",
145 [SDLK_LCTRL] = "left ctrl",
146 [SDLK_RALT] = "right alt",
147 [SDLK_LALT] = "left alt",
148 [SDLK_RMETA] = "right meta",
149 [SDLK_LMETA] = "left meta",
150 [SDLK_LSUPER] = "left super", /* "Windows" keys */
151 [SDLK_RSUPER] = "right super",
152 [SDLK_MODE] = "alt gr",
153 [SDLK_COMPOSE] = "compose",
154};
155
156static void in_sdl_probe(void)
157{
158 keybits_t *keystate;
159
160 keystate = calloc(SDLK_LAST / KEYBITS_WORD_BITS + 1, 1);
161 if (keystate == NULL) {
162 fprintf(stderr, "in_sdl: OOM\n");
163 return;
164 }
165
166 in_register(IN_SDL_PREFIX "keys", -1, keystate, SDLK_LAST,
167 in_sdl_keys, 0);
168}
169
170static void in_sdl_free(void *drv_data)
171{
172 keybits_t *keystate = drv_data;
173
174 if (keystate != NULL)
175 free(keystate);
176}
177
178static const char * const *
179in_sdl_get_key_names(int *count)
180{
181 *count = SDLK_LAST;
182 return in_sdl_keys;
183}
184
185/* could use SDL_GetKeyState, but this gives better packing */
186static void update_keystate(keybits_t *keystate, int sym, int is_down)
187{
188 keybits_t *ks_word, mask;
189
190 mask = 1;
191 mask <<= sym & (KEYBITS_WORD_BITS - 1);
192 ks_word = keystate + sym / KEYBITS_WORD_BITS;
193 if (is_down)
194 *ks_word |= mask;
195 else
196 *ks_word &= ~mask;
197}
198
199static int in_sdl_update(void *drv_data, const int *binds, int *result)
200{
201 keybits_t *keystate = drv_data, mask;
202 SDL_Event event;
203 int i, sym, bit, b;
204
205 while (SDL_PollEvent(&event)) {
206 if (event.type != SDL_KEYDOWN && event.type != SDL_KEYUP)
207 continue;
208
209 update_keystate(keystate, event.key.keysym.sym,
210 event.type == SDL_KEYDOWN);
211 }
212
213 for (i = 0; i < SDLK_LAST / KEYBITS_WORD_BITS + 1; i++) {
214 mask = keystate[i];
215 if (mask == 0)
216 continue;
217 for (bit = 0; mask != 0; bit++, mask >>= 1) {
218 if ((mask & 1) == 0)
219 continue;
220 sym = i * KEYBITS_WORD_BITS + bit;
221
222 for (b = 0; b < IN_BINDTYPE_COUNT; b++)
223 result[b] |= binds[IN_BIND_OFFS(sym, b)];
224 }
225 }
226
227 return 0;
228}
229
230static int in_sdl_update_keycode(void *drv_data, int *is_down)
231{
232 int ret, ret_kc = -1, ret_down = 0;
233 SDL_Event event;
234
235 ret = SDL_PollEvent(&event);
236 if (ret == 0)
237 goto out;
238 if (event.type != SDL_KEYDOWN && event.type != SDL_KEYUP)
239 goto out;
240
241 if (event.key.type == SDL_KEYDOWN)
242 ret_down = 1;
243 ret_kc = event.key.keysym.sym;
244 update_keystate(drv_data, ret_kc, ret_down);
245out:
246 if (is_down != NULL)
247 *is_down = ret_down;
248
249 return ret_kc;
250}
251
252static const struct {
253 short key;
254 short pbtn;
255} key_pbtn_map[] =
256{
257 { SDLK_UP, PBTN_UP },
258 { SDLK_DOWN, PBTN_DOWN },
259 { SDLK_LEFT, PBTN_LEFT },
260 { SDLK_RIGHT, PBTN_RIGHT },
261 /* XXX: maybe better set this from it's plat code somehow */
262 { SDLK_RETURN, PBTN_MOK },
263 { SDLK_ESCAPE, PBTN_MBACK },
264 { SDLK_a, PBTN_MA2 },
265 { SDLK_s, PBTN_MA3 },
266 { SDLK_BACKSLASH, PBTN_MENU },
267 { SDLK_LEFTBRACKET, PBTN_L },
268 { SDLK_RIGHTBRACKET, PBTN_R },
269};
270
271#define KEY_PBTN_MAP_SIZE (sizeof(key_pbtn_map) / sizeof(key_pbtn_map[0]))
272
273static int in_sdl_menu_translate(void *drv_data, int keycode)
274{
275 int i;
276
277 if (keycode < 0)
278 {
279 /* menu -> kc */
280 keycode = -keycode;
281 for (i = 0; i < KEY_PBTN_MAP_SIZE; i++)
282 if (key_pbtn_map[i].pbtn == keycode)
283 return key_pbtn_map[i].key;
284 }
285 else
286 {
287 for (i = 0; i < KEY_PBTN_MAP_SIZE; i++)
288 if (key_pbtn_map[i].key == keycode)
289 return key_pbtn_map[i].pbtn;
290 }
291
292 return 0;
293}
294
295static const in_drv_t in_sdl_drv = {
296 .prefix = IN_SDL_PREFIX,
297 .probe = in_sdl_probe,
298 .free = in_sdl_free,
299 .get_key_names = in_sdl_get_key_names,
300 .update = in_sdl_update,
301 .update_keycode = in_sdl_update_keycode,
302 .menu_translate = in_sdl_menu_translate,
303};
304
b07c18e8 305void in_sdl_init(const struct in_default_bind *defbinds)
7badc935 306{
b07c18e8 307 in_register_driver(&in_sdl_drv, defbinds);
7badc935 308}
309