6#if defined(SDL_LIBRETRO_IMPLEMENTATION) && !defined(SDL_LIBRETRO_INPUT_IMPL_ONCE)
7#define SDL_LIBRETRO_INPUT_IMPL_ONCE
15static SDL_GamepadButton SDL_Libretro_RetroJoypadToGamepadButton(
unsigned button) {
17 case RETRO_DEVICE_ID_JOYPAD_B:
return SDL_GAMEPAD_BUTTON_SOUTH;
18 case RETRO_DEVICE_ID_JOYPAD_Y:
return SDL_GAMEPAD_BUTTON_WEST;
19 case RETRO_DEVICE_ID_JOYPAD_SELECT:
return SDL_GAMEPAD_BUTTON_BACK;
20 case RETRO_DEVICE_ID_JOYPAD_START:
return SDL_GAMEPAD_BUTTON_START;
21 case RETRO_DEVICE_ID_JOYPAD_UP:
return SDL_GAMEPAD_BUTTON_DPAD_UP;
22 case RETRO_DEVICE_ID_JOYPAD_DOWN:
return SDL_GAMEPAD_BUTTON_DPAD_DOWN;
23 case RETRO_DEVICE_ID_JOYPAD_LEFT:
return SDL_GAMEPAD_BUTTON_DPAD_LEFT;
24 case RETRO_DEVICE_ID_JOYPAD_RIGHT:
return SDL_GAMEPAD_BUTTON_DPAD_RIGHT;
25 case RETRO_DEVICE_ID_JOYPAD_A:
return SDL_GAMEPAD_BUTTON_EAST;
26 case RETRO_DEVICE_ID_JOYPAD_X:
return SDL_GAMEPAD_BUTTON_NORTH;
27 case RETRO_DEVICE_ID_JOYPAD_L:
return SDL_GAMEPAD_BUTTON_LEFT_SHOULDER;
28 case RETRO_DEVICE_ID_JOYPAD_R:
return SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER;
29 case RETRO_DEVICE_ID_JOYPAD_L2:
return SDL_GAMEPAD_BUTTON_LEFT_PADDLE1;
30 case RETRO_DEVICE_ID_JOYPAD_R2:
return SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1;
31 case RETRO_DEVICE_ID_JOYPAD_L3:
return SDL_GAMEPAD_BUTTON_LEFT_STICK;
32 case RETRO_DEVICE_ID_JOYPAD_R3:
return SDL_GAMEPAD_BUTTON_RIGHT_STICK;
33 default:
return SDL_GAMEPAD_BUTTON_INVALID;
44static SDL_Scancode SDL_Libretro_RetroKeyToScancode(
unsigned key) {
46 case RETROK_BACKSPACE:
return SDL_SCANCODE_BACKSPACE;
47 case RETROK_TAB:
return SDL_SCANCODE_TAB;
48 case RETROK_RETURN:
return SDL_SCANCODE_RETURN;
49 case RETROK_ESCAPE:
return SDL_SCANCODE_ESCAPE;
50 case RETROK_SPACE:
return SDL_SCANCODE_SPACE;
51 case RETROK_EXCLAIM:
return SDL_SCANCODE_1;
52 case RETROK_QUOTEDBL:
return SDL_SCANCODE_APOSTROPHE;
53 case RETROK_HASH:
return SDL_SCANCODE_3;
54 case RETROK_DOLLAR:
return SDL_SCANCODE_4;
55 case RETROK_AMPERSAND:
return SDL_SCANCODE_7;
56 case RETROK_QUOTE:
return SDL_SCANCODE_APOSTROPHE;
57 case RETROK_LEFTPAREN:
return SDL_SCANCODE_9;
58 case RETROK_RIGHTPAREN:
return SDL_SCANCODE_0;
59 case RETROK_ASTERISK:
return SDL_SCANCODE_8;
60 case RETROK_PLUS:
return SDL_SCANCODE_EQUALS;
61 case RETROK_COMMA:
return SDL_SCANCODE_COMMA;
62 case RETROK_MINUS:
return SDL_SCANCODE_MINUS;
63 case RETROK_PERIOD:
return SDL_SCANCODE_PERIOD;
64 case RETROK_SLASH:
return SDL_SCANCODE_SLASH;
65 case RETROK_0:
return SDL_SCANCODE_0;
66 case RETROK_1:
return SDL_SCANCODE_1;
67 case RETROK_2:
return SDL_SCANCODE_2;
68 case RETROK_3:
return SDL_SCANCODE_3;
69 case RETROK_4:
return SDL_SCANCODE_4;
70 case RETROK_5:
return SDL_SCANCODE_5;
71 case RETROK_6:
return SDL_SCANCODE_6;
72 case RETROK_7:
return SDL_SCANCODE_7;
73 case RETROK_8:
return SDL_SCANCODE_8;
74 case RETROK_9:
return SDL_SCANCODE_9;
75 case RETROK_SEMICOLON:
return SDL_SCANCODE_SEMICOLON;
76 case RETROK_EQUALS:
return SDL_SCANCODE_EQUALS;
77 case RETROK_LEFTBRACKET:
return SDL_SCANCODE_LEFTBRACKET;
78 case RETROK_BACKSLASH:
return SDL_SCANCODE_BACKSLASH;
79 case RETROK_RIGHTBRACKET:
return SDL_SCANCODE_RIGHTBRACKET;
80 case RETROK_BACKQUOTE:
return SDL_SCANCODE_GRAVE;
81 case RETROK_a:
return SDL_SCANCODE_A;
82 case RETROK_b:
return SDL_SCANCODE_B;
83 case RETROK_c:
return SDL_SCANCODE_C;
84 case RETROK_d:
return SDL_SCANCODE_D;
85 case RETROK_e:
return SDL_SCANCODE_E;
86 case RETROK_f:
return SDL_SCANCODE_F;
87 case RETROK_g:
return SDL_SCANCODE_G;
88 case RETROK_h:
return SDL_SCANCODE_H;
89 case RETROK_i:
return SDL_SCANCODE_I;
90 case RETROK_j:
return SDL_SCANCODE_J;
91 case RETROK_k:
return SDL_SCANCODE_K;
92 case RETROK_l:
return SDL_SCANCODE_L;
93 case RETROK_m:
return SDL_SCANCODE_M;
94 case RETROK_n:
return SDL_SCANCODE_N;
95 case RETROK_o:
return SDL_SCANCODE_O;
96 case RETROK_p:
return SDL_SCANCODE_P;
97 case RETROK_q:
return SDL_SCANCODE_Q;
98 case RETROK_r:
return SDL_SCANCODE_R;
99 case RETROK_s:
return SDL_SCANCODE_S;
100 case RETROK_t:
return SDL_SCANCODE_T;
101 case RETROK_u:
return SDL_SCANCODE_U;
102 case RETROK_v:
return SDL_SCANCODE_V;
103 case RETROK_w:
return SDL_SCANCODE_W;
104 case RETROK_x:
return SDL_SCANCODE_X;
105 case RETROK_y:
return SDL_SCANCODE_Y;
106 case RETROK_z:
return SDL_SCANCODE_Z;
107 case RETROK_DELETE:
return SDL_SCANCODE_DELETE;
108 case RETROK_KP0:
return SDL_SCANCODE_KP_0;
109 case RETROK_KP1:
return SDL_SCANCODE_KP_1;
110 case RETROK_KP2:
return SDL_SCANCODE_KP_2;
111 case RETROK_KP3:
return SDL_SCANCODE_KP_3;
112 case RETROK_KP4:
return SDL_SCANCODE_KP_4;
113 case RETROK_KP5:
return SDL_SCANCODE_KP_5;
114 case RETROK_KP6:
return SDL_SCANCODE_KP_6;
115 case RETROK_KP7:
return SDL_SCANCODE_KP_7;
116 case RETROK_KP8:
return SDL_SCANCODE_KP_8;
117 case RETROK_KP9:
return SDL_SCANCODE_KP_9;
118 case RETROK_KP_PERIOD:
return SDL_SCANCODE_KP_PERIOD;
119 case RETROK_KP_DIVIDE:
return SDL_SCANCODE_KP_DIVIDE;
120 case RETROK_KP_MULTIPLY:
return SDL_SCANCODE_KP_MULTIPLY;
121 case RETROK_KP_MINUS:
return SDL_SCANCODE_KP_MINUS;
122 case RETROK_KP_PLUS:
return SDL_SCANCODE_KP_PLUS;
123 case RETROK_KP_ENTER:
return SDL_SCANCODE_KP_ENTER;
124 case RETROK_KP_EQUALS:
return SDL_SCANCODE_KP_EQUALS;
125 case RETROK_UP:
return SDL_SCANCODE_UP;
126 case RETROK_DOWN:
return SDL_SCANCODE_DOWN;
127 case RETROK_RIGHT:
return SDL_SCANCODE_RIGHT;
128 case RETROK_LEFT:
return SDL_SCANCODE_LEFT;
129 case RETROK_INSERT:
return SDL_SCANCODE_INSERT;
130 case RETROK_HOME:
return SDL_SCANCODE_HOME;
131 case RETROK_END:
return SDL_SCANCODE_END;
132 case RETROK_PAGEUP:
return SDL_SCANCODE_PAGEUP;
133 case RETROK_PAGEDOWN:
return SDL_SCANCODE_PAGEDOWN;
134 case RETROK_F1:
return SDL_SCANCODE_F1;
135 case RETROK_F2:
return SDL_SCANCODE_F2;
136 case RETROK_F3:
return SDL_SCANCODE_F3;
137 case RETROK_F4:
return SDL_SCANCODE_F4;
138 case RETROK_F5:
return SDL_SCANCODE_F5;
139 case RETROK_F6:
return SDL_SCANCODE_F6;
140 case RETROK_F7:
return SDL_SCANCODE_F7;
141 case RETROK_F8:
return SDL_SCANCODE_F8;
142 case RETROK_F9:
return SDL_SCANCODE_F9;
143 case RETROK_F10:
return SDL_SCANCODE_F10;
144 case RETROK_F11:
return SDL_SCANCODE_F11;
145 case RETROK_F12:
return SDL_SCANCODE_F12;
146 case RETROK_F13:
return SDL_SCANCODE_F13;
147 case RETROK_F14:
return SDL_SCANCODE_F14;
148 case RETROK_F15:
return SDL_SCANCODE_F15;
149 case RETROK_NUMLOCK:
return SDL_SCANCODE_NUMLOCKCLEAR;
150 case RETROK_CAPSLOCK:
return SDL_SCANCODE_CAPSLOCK;
151 case RETROK_SCROLLOCK:
return SDL_SCANCODE_SCROLLLOCK;
152 case RETROK_RSHIFT:
return SDL_SCANCODE_RSHIFT;
153 case RETROK_LSHIFT:
return SDL_SCANCODE_LSHIFT;
154 case RETROK_RCTRL:
return SDL_SCANCODE_RCTRL;
155 case RETROK_LCTRL:
return SDL_SCANCODE_LCTRL;
156 case RETROK_RALT:
return SDL_SCANCODE_RALT;
157 case RETROK_LALT:
return SDL_SCANCODE_LALT;
158 case RETROK_RMETA:
return SDL_SCANCODE_RGUI;
159 case RETROK_LMETA:
return SDL_SCANCODE_LGUI;
160 case RETROK_RSUPER:
return SDL_SCANCODE_RGUI;
161 case RETROK_LSUPER:
return SDL_SCANCODE_LGUI;
162 case RETROK_MENU:
return SDL_SCANCODE_MENU;
163 default:
return SDL_SCANCODE_UNKNOWN;
174static unsigned SDL_Libretro_ScancodeToRetroKey(SDL_Scancode scancode) {
176 case SDL_SCANCODE_BACKSPACE:
return RETROK_BACKSPACE;
177 case SDL_SCANCODE_TAB:
return RETROK_TAB;
178 case SDL_SCANCODE_RETURN:
return RETROK_RETURN;
179 case SDL_SCANCODE_ESCAPE:
return RETROK_ESCAPE;
180 case SDL_SCANCODE_SPACE:
return RETROK_SPACE;
181 case SDL_SCANCODE_APOSTROPHE:
return RETROK_QUOTE;
182 case SDL_SCANCODE_COMMA:
return RETROK_COMMA;
183 case SDL_SCANCODE_MINUS:
return RETROK_MINUS;
184 case SDL_SCANCODE_PERIOD:
return RETROK_PERIOD;
185 case SDL_SCANCODE_SLASH:
return RETROK_SLASH;
186 case SDL_SCANCODE_0:
return RETROK_0;
187 case SDL_SCANCODE_1:
return RETROK_1;
188 case SDL_SCANCODE_2:
return RETROK_2;
189 case SDL_SCANCODE_3:
return RETROK_3;
190 case SDL_SCANCODE_4:
return RETROK_4;
191 case SDL_SCANCODE_5:
return RETROK_5;
192 case SDL_SCANCODE_6:
return RETROK_6;
193 case SDL_SCANCODE_7:
return RETROK_7;
194 case SDL_SCANCODE_8:
return RETROK_8;
195 case SDL_SCANCODE_9:
return RETROK_9;
196 case SDL_SCANCODE_SEMICOLON:
return RETROK_SEMICOLON;
197 case SDL_SCANCODE_EQUALS:
return RETROK_EQUALS;
198 case SDL_SCANCODE_LEFTBRACKET:
return RETROK_LEFTBRACKET;
199 case SDL_SCANCODE_BACKSLASH:
return RETROK_BACKSLASH;
200 case SDL_SCANCODE_RIGHTBRACKET:
return RETROK_RIGHTBRACKET;
201 case SDL_SCANCODE_GRAVE:
return RETROK_BACKQUOTE;
202 case SDL_SCANCODE_A:
return RETROK_a;
203 case SDL_SCANCODE_B:
return RETROK_b;
204 case SDL_SCANCODE_C:
return RETROK_c;
205 case SDL_SCANCODE_D:
return RETROK_d;
206 case SDL_SCANCODE_E:
return RETROK_e;
207 case SDL_SCANCODE_F:
return RETROK_f;
208 case SDL_SCANCODE_G:
return RETROK_g;
209 case SDL_SCANCODE_H:
return RETROK_h;
210 case SDL_SCANCODE_I:
return RETROK_i;
211 case SDL_SCANCODE_J:
return RETROK_j;
212 case SDL_SCANCODE_K:
return RETROK_k;
213 case SDL_SCANCODE_L:
return RETROK_l;
214 case SDL_SCANCODE_M:
return RETROK_m;
215 case SDL_SCANCODE_N:
return RETROK_n;
216 case SDL_SCANCODE_O:
return RETROK_o;
217 case SDL_SCANCODE_P:
return RETROK_p;
218 case SDL_SCANCODE_Q:
return RETROK_q;
219 case SDL_SCANCODE_R:
return RETROK_r;
220 case SDL_SCANCODE_S:
return RETROK_s;
221 case SDL_SCANCODE_T:
return RETROK_t;
222 case SDL_SCANCODE_U:
return RETROK_u;
223 case SDL_SCANCODE_V:
return RETROK_v;
224 case SDL_SCANCODE_W:
return RETROK_w;
225 case SDL_SCANCODE_X:
return RETROK_x;
226 case SDL_SCANCODE_Y:
return RETROK_y;
227 case SDL_SCANCODE_Z:
return RETROK_z;
228 case SDL_SCANCODE_DELETE:
return RETROK_DELETE;
229 case SDL_SCANCODE_KP_0:
return RETROK_KP0;
230 case SDL_SCANCODE_KP_1:
return RETROK_KP1;
231 case SDL_SCANCODE_KP_2:
return RETROK_KP2;
232 case SDL_SCANCODE_KP_3:
return RETROK_KP3;
233 case SDL_SCANCODE_KP_4:
return RETROK_KP4;
234 case SDL_SCANCODE_KP_5:
return RETROK_KP5;
235 case SDL_SCANCODE_KP_6:
return RETROK_KP6;
236 case SDL_SCANCODE_KP_7:
return RETROK_KP7;
237 case SDL_SCANCODE_KP_8:
return RETROK_KP8;
238 case SDL_SCANCODE_KP_9:
return RETROK_KP9;
239 case SDL_SCANCODE_KP_PERIOD:
return RETROK_KP_PERIOD;
240 case SDL_SCANCODE_KP_DIVIDE:
return RETROK_KP_DIVIDE;
241 case SDL_SCANCODE_KP_MULTIPLY:
return RETROK_KP_MULTIPLY;
242 case SDL_SCANCODE_KP_MINUS:
return RETROK_KP_MINUS;
243 case SDL_SCANCODE_KP_PLUS:
return RETROK_KP_PLUS;
244 case SDL_SCANCODE_KP_ENTER:
return RETROK_KP_ENTER;
245 case SDL_SCANCODE_KP_EQUALS:
return RETROK_KP_EQUALS;
246 case SDL_SCANCODE_UP:
return RETROK_UP;
247 case SDL_SCANCODE_DOWN:
return RETROK_DOWN;
248 case SDL_SCANCODE_RIGHT:
return RETROK_RIGHT;
249 case SDL_SCANCODE_LEFT:
return RETROK_LEFT;
250 case SDL_SCANCODE_INSERT:
return RETROK_INSERT;
251 case SDL_SCANCODE_HOME:
return RETROK_HOME;
252 case SDL_SCANCODE_END:
return RETROK_END;
253 case SDL_SCANCODE_PAGEUP:
return RETROK_PAGEUP;
254 case SDL_SCANCODE_PAGEDOWN:
return RETROK_PAGEDOWN;
255 case SDL_SCANCODE_F1:
return RETROK_F1;
256 case SDL_SCANCODE_F2:
return RETROK_F2;
257 case SDL_SCANCODE_F3:
return RETROK_F3;
258 case SDL_SCANCODE_F4:
return RETROK_F4;
259 case SDL_SCANCODE_F5:
return RETROK_F5;
260 case SDL_SCANCODE_F6:
return RETROK_F6;
261 case SDL_SCANCODE_F7:
return RETROK_F7;
262 case SDL_SCANCODE_F8:
return RETROK_F8;
263 case SDL_SCANCODE_F9:
return RETROK_F9;
264 case SDL_SCANCODE_F10:
return RETROK_F10;
265 case SDL_SCANCODE_F11:
return RETROK_F11;
266 case SDL_SCANCODE_F12:
return RETROK_F12;
267 case SDL_SCANCODE_F13:
return RETROK_F13;
268 case SDL_SCANCODE_F14:
return RETROK_F14;
269 case SDL_SCANCODE_F15:
return RETROK_F15;
270 case SDL_SCANCODE_NUMLOCKCLEAR:
return RETROK_NUMLOCK;
271 case SDL_SCANCODE_CAPSLOCK:
return RETROK_CAPSLOCK;
272 case SDL_SCANCODE_SCROLLLOCK:
return RETROK_SCROLLOCK;
273 case SDL_SCANCODE_RSHIFT:
return RETROK_RSHIFT;
274 case SDL_SCANCODE_LSHIFT:
return RETROK_LSHIFT;
275 case SDL_SCANCODE_RCTRL:
return RETROK_RCTRL;
276 case SDL_SCANCODE_LCTRL:
return RETROK_LCTRL;
277 case SDL_SCANCODE_RALT:
return RETROK_RALT;
278 case SDL_SCANCODE_LALT:
return RETROK_LALT;
279 case SDL_SCANCODE_RGUI:
return RETROK_RMETA;
280 case SDL_SCANCODE_LGUI:
return RETROK_LMETA;
281 case SDL_SCANCODE_MENU:
return RETROK_MENU;
282 default:
return RETROK_UNKNOWN;
291static uint16_t SDL_Libretro_KeymodToRetroMod(SDL_Keymod mod) {
292 uint16_t retromod = RETROKMOD_NONE;
293 if (mod & SDL_KMOD_SHIFT) retromod |= RETROKMOD_SHIFT;
294 if (mod & SDL_KMOD_CTRL) retromod |= RETROKMOD_CTRL;
295 if (mod & SDL_KMOD_ALT) retromod |= RETROKMOD_ALT;
296 if (mod & SDL_KMOD_GUI) retromod |= RETROKMOD_META;
297 if (mod & SDL_KMOD_NUM) retromod |= RETROKMOD_NUMLOCK;
298 if (mod & SDL_KMOD_CAPS) retromod |= RETROKMOD_CAPSLOCK;
299 if (mod & SDL_KMOD_SCROLL) retromod |= RETROKMOD_SCROLLOCK;
303static void SDL_Libretro_InputPoll(
void) {
304 SDL_Libretro* lr = SDL_Libretro_active;
307 lr->core.inputLastMouseX = lr->core.inputMouseX;
308 lr->core.inputLastMouseY = lr->core.inputMouseY;
309 SDL_GetMouseState(&lr->core.inputMouseX, &lr->core.inputMouseY);
312static bool SDL_Libretro_IsKeyDown(SDL_Libretro* lr, SDL_Scancode scancode) {
313 if (scancode == SDL_SCANCODE_UNKNOWN)
return false;
314 const bool* state = SDL_GetKeyboardState(NULL);
315 return state[scancode];
318static int16_t SDL_Libretro_InputState(
unsigned port,
unsigned device,
unsigned index,
unsigned id) {
319 SDL_Libretro* lr = SDL_Libretro_active;
324 if (lr->rewindActive)
return 0;
326 unsigned baseDevice = device & RETRO_DEVICE_MASK;
328 switch (baseDevice) {
329 case RETRO_DEVICE_JOYPAD: {
330 if (
id == RETRO_DEVICE_ID_JOYPAD_MASK) {
332 for (
unsigned b = 0; b <= RETRO_DEVICE_ID_JOYPAD_R3; b++) {
333 if (SDL_Libretro_InputState(port, device, index, b)) {
341 if (port == 0 && id < 16 && lr->core.virtualJoypadState[
id]) {
346 if (port == 0 &&
id <= RETRO_DEVICE_ID_JOYPAD_R3) {
347 if (SDL_Libretro_IsKeyDown(lr, lr->keyboardPlayer1[
id])) {
353 if (port < 16 && lr->gamepads[port]) {
355 if (
id == RETRO_DEVICE_ID_JOYPAD_L2) {
356 Sint16 val = SDL_GetGamepadAxis(lr->gamepads[port], SDL_GAMEPAD_AXIS_LEFT_TRIGGER);
357 return val > 8192 ? 1 : 0;
359 if (
id == RETRO_DEVICE_ID_JOYPAD_R2) {
360 Sint16 val = SDL_GetGamepadAxis(lr->gamepads[port], SDL_GAMEPAD_AXIS_RIGHT_TRIGGER);
361 return val > 8192 ? 1 : 0;
364 SDL_GamepadButton btn = SDL_Libretro_RetroJoypadToGamepadButton(
id);
365 if (btn != SDL_GAMEPAD_BUTTON_INVALID) {
366 return SDL_GetGamepadButton(lr->gamepads[port], btn) ? 1 : 0;
372 case RETRO_DEVICE_ANALOG: {
373 if (port < 16 && lr->gamepads[port]) {
374 SDL_GamepadAxis axis = SDL_GAMEPAD_AXIS_INVALID;
375 if (index == RETRO_DEVICE_INDEX_ANALOG_LEFT) {
376 axis = (
id == RETRO_DEVICE_ID_ANALOG_X) ? SDL_GAMEPAD_AXIS_LEFTX : SDL_GAMEPAD_AXIS_LEFTY;
377 }
else if (index == RETRO_DEVICE_INDEX_ANALOG_RIGHT) {
378 axis = (
id == RETRO_DEVICE_ID_ANALOG_X) ? SDL_GAMEPAD_AXIS_RIGHTX : SDL_GAMEPAD_AXIS_RIGHTY;
380 if (axis != SDL_GAMEPAD_AXIS_INVALID) {
381 return SDL_GetGamepadAxis(lr->gamepads[port], axis);
387 case RETRO_DEVICE_KEYBOARD: {
388 SDL_Scancode sc = SDL_Libretro_RetroKeyToScancode(
id);
389 return SDL_Libretro_IsKeyDown(lr, sc) ? 1 : 0;
392 case RETRO_DEVICE_MOUSE: {
394 case RETRO_DEVICE_ID_MOUSE_X:
395 return (int16_t)(lr->core.inputMouseX - lr->core.inputLastMouseX);
396 case RETRO_DEVICE_ID_MOUSE_Y:
397 return (int16_t)(lr->core.inputMouseY - lr->core.inputLastMouseY);
398 case RETRO_DEVICE_ID_MOUSE_LEFT: {
399 Uint32 state = SDL_GetMouseState(NULL, NULL);
400 return (state & SDL_BUTTON_LMASK) ? 1 : 0;
402 case RETRO_DEVICE_ID_MOUSE_RIGHT: {
403 Uint32 state = SDL_GetMouseState(NULL, NULL);
404 return (state & SDL_BUTTON_RMASK) ? 1 : 0;
406 case RETRO_DEVICE_ID_MOUSE_MIDDLE: {
407 Uint32 state = SDL_GetMouseState(NULL, NULL);
408 return (state & SDL_BUTTON_MMASK) ? 1 : 0;
414 case RETRO_DEVICE_POINTER: {
415 if (index > 0)
return 0;
417 float mx = lr->core.inputMouseX;
418 float my = lr->core.inputMouseY;
419 SDL_FRect r = lr->core.renderDstRect;
420 bool inside = r.w > 0 && r.h > 0 &&
421 mx >= r.x && mx < r.x + r.w &&
422 my >= r.y && my < r.y + r.h;
425 case RETRO_DEVICE_ID_POINTER_X:
426 case RETRO_DEVICE_ID_POINTER_Y: {
427 if (r.w <= 0.0f || r.h <= 0.0f)
return 0;
430 float sx = (mx - r.x) / r.w;
431 float sy = (my - r.y) / r.h;
437 switch (lr->core.rotation & 3) {
438 case 1: u = 1.0f - sy; v = sx;
break;
439 case 2: u = 1.0f - sx; v = 1.0f - sy;
break;
440 case 3: u = sy; v = 1.0f - sx;
break;
441 default: u = sx; v = sy;
break;
444 float n = (
id == RETRO_DEVICE_ID_POINTER_X ? u : v) * 2.0f - 1.0f;
445 return (int16_t)(SDL_clamp(n, -1.0f, 1.0f) * 0x7FFF);
447 case RETRO_DEVICE_ID_POINTER_PRESSED:
448 case RETRO_DEVICE_ID_POINTER_COUNT: {
449 Uint32 state = SDL_GetMouseState(NULL, NULL);
450 return (state & SDL_BUTTON_LMASK) ? 1 : 0;
452 case RETRO_DEVICE_ID_POINTER_IS_OFFSCREEN:
453 return inside ? 0 : 1;
458 case RETRO_DEVICE_LIGHTGUN: {
459 if (
id == RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X ||
id == RETRO_DEVICE_ID_LIGHTGUN_X) {
461 if (lr->window) SDL_GetWindowSize(lr->window, &w, &h);
462 if (w > 0)
return (int16_t)((lr->core.inputMouseX / (float)w) * 32767.0f * 2.0f - 32767.0f);
464 if (
id == RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y ||
id == RETRO_DEVICE_ID_LIGHTGUN_Y) {
466 if (lr->window) SDL_GetWindowSize(lr->window, &w, &h);
467 if (h > 0)
return (int16_t)((lr->core.inputMouseY / (float)h) * 32767.0f * 2.0f - 32767.0f);
469 if (
id == RETRO_DEVICE_ID_LIGHTGUN_TRIGGER) {
470 Uint32 state = SDL_GetMouseState(NULL, NULL);
471 return (state & SDL_BUTTON_LMASK) ? 1 : 0;
485 if (!lr || !event)
return;
487 switch (event->type) {
488 case SDL_EVENT_GAMEPAD_ADDED: {
489 SDL_JoystickID jid =
event->gdevice.which;
490 SDL_Gamepad* gp = SDL_OpenGamepad(jid);
492 for (
unsigned i = 0; i < 16; i++) {
493 if (!lr->gamepads[i]) {
494 lr->gamepads[i] = gp;
495 const char* name = SDL_GetGamepadName(gp);
496 if (i + 1 > lr->gamepadCount) lr->gamepadCount = i + 1;
497 SDL_Log(
"[SDL_Libretro] Gamepad added: #%u %s", i + 1, name ? name :
"");
504 case SDL_EVENT_GAMEPAD_REMOVED: {
505 SDL_JoystickID jid =
event->gdevice.which;
506 for (
unsigned i = 0; i < 16; i++) {
507 if (lr->gamepads[i] && SDL_GetGamepadID(lr->gamepads[i]) == jid) {
508 const char* name = SDL_GetGamepadName(lr->gamepads[i]);
509 SDL_Log(
"[SDL_Libretro] Gamepad removed: #%u %s", i + 1, name ? name :
"");
510 SDL_CloseGamepad(lr->gamepads[i]);
511 lr->gamepads[i] = NULL;
517 case SDL_EVENT_KEY_DOWN:
518 case SDL_EVENT_KEY_UP: {
519 if (lr->core.keyboard_event) {
520 bool down = (
event->type == SDL_EVENT_KEY_DOWN);
521 unsigned retrokey = SDL_Libretro_ScancodeToRetroKey(event->key.scancode);
522 uint16_t modmask = SDL_Libretro_KeymodToRetroMod(event->key.mod);
525 uint32_t character = 0;
526 if (event->key.key > 0x20 && event->key.key < 0x110000 &&
527 !(event->key.key & SDLK_SCANCODE_MASK)) {
528 character = (uint32_t)event->key.key;
531 lr->core.keyboard_event(down, retrokey, character, modmask);
540bool SDL_Libretro_SetPortDevice(SDL_Libretro* lr,
unsigned port,
unsigned device) {
541 if (!lr || port >= 16)
return false;
542 lr->core.portDeviceMap[port] = device;
543 if (lr->core.loaded) {
544 lr->core.symbols.retro_set_controller_port_device(port, device);
560 if (!lr || port >= 16)
return RETRO_DEVICE_NONE;
561 return lr->core.portDeviceMap[port];
564void SDL_Libretro_SetKeyboardMapping(SDL_Libretro* lr,
int retroButton, SDL_Scancode scancode) {
565 if (!lr || retroButton < 0 || retroButton > RETRO_DEVICE_ID_JOYPAD_R3)
return;
566 lr->keyboardPlayer1[retroButton] = scancode;
569void SDL_Libretro_SetVirtualButton(SDL_Libretro* lr,
unsigned port,
int button,
bool pressed) {
570 if (!lr || port >= 16 || button < 0 || button >= 16)
return;
571 lr->core.virtualJoypadState[button] = pressed;
584 return (lr && lr->core.loaded) ? lr->core.inputDescriptorCount : 0;
606 if (!lr || !lr->core.loaded || index >= lr->core.inputDescriptorCount)
return false;
607 const struct retro_input_descriptor* d = &lr->core.inputDescriptors[index];
608 if (port) *port = d->port;
609 if (device) *device = d->device;
611 if (description) *description = d->description;
617static SDL_Sensor* SDL_Libretro_OpenSensorByType(SDL_SensorType type) {
619 SDL_SensorID* sensors = SDL_GetSensors(&count);
620 if (!sensors)
return NULL;
621 SDL_Sensor* result = NULL;
622 for (
int i = 0; i < count; i++) {
623 if (SDL_GetSensorTypeForID(sensors[i]) == type) {
624 result = SDL_OpenSensor(sensors[i]);
632static bool SDL_Libretro_SetSensorState(
unsigned port,
enum retro_sensor_action action,
unsigned rate) {
633 SDL_Libretro* lr = SDL_Libretro_active;
634 if (!lr || port >= SDL_LIBRETRO_SENSOR_PORTS)
return false;
638 case RETRO_SENSOR_ACCELEROMETER_ENABLE:
639 if (!lr->core.sensorAccel[port]) {
640 lr->core.sensorAccel[port] = SDL_Libretro_OpenSensorByType(SDL_SENSOR_ACCEL);
642 return lr->core.sensorAccel[port] != NULL;
643 case RETRO_SENSOR_ACCELEROMETER_DISABLE:
644 if (lr->core.sensorAccel[port]) {
645 SDL_CloseSensor(lr->core.sensorAccel[port]);
646 lr->core.sensorAccel[port] = NULL;
648 SDL_memset(lr->core.sensorAccelData[port], 0,
sizeof(lr->core.sensorAccelData[port]));
650 case RETRO_SENSOR_GYROSCOPE_ENABLE:
651 if (!lr->core.sensorGyro[port]) {
652 lr->core.sensorGyro[port] = SDL_Libretro_OpenSensorByType(SDL_SENSOR_GYRO);
654 return lr->core.sensorGyro[port] != NULL;
655 case RETRO_SENSOR_GYROSCOPE_DISABLE:
656 if (lr->core.sensorGyro[port]) {
657 SDL_CloseSensor(lr->core.sensorGyro[port]);
658 lr->core.sensorGyro[port] = NULL;
660 SDL_memset(lr->core.sensorGyroData[port], 0,
sizeof(lr->core.sensorGyroData[port]));
670static float SDL_Libretro_GetSensorInput(
unsigned port,
unsigned id) {
671 SDL_Libretro* lr = SDL_Libretro_active;
672 if (!lr || port >= SDL_LIBRETRO_SENSOR_PORTS)
return 0.0f;
675 if (
id >= RETRO_SENSOR_ACCELEROMETER_X && id <= RETRO_SENSOR_ACCELEROMETER_Z && lr->core.sensorAccel[port]) {
677 if (SDL_GetSensorData(lr->core.sensorAccel[port], data, 3)) {
678 lr->core.sensorAccelData[port][0] = data[0] / SDL_STANDARD_GRAVITY;
679 lr->core.sensorAccelData[port][1] = data[1] / SDL_STANDARD_GRAVITY;
680 lr->core.sensorAccelData[port][2] = data[2] / SDL_STANDARD_GRAVITY;
682 return lr->core.sensorAccelData[port][
id - RETRO_SENSOR_ACCELEROMETER_X];
686 if (
id >= RETRO_SENSOR_GYROSCOPE_X && id <= RETRO_SENSOR_GYROSCOPE_Z && lr->core.sensorGyro[port]) {
688 if (SDL_GetSensorData(lr->core.sensorGyro[port], data, 3)) {
689 lr->core.sensorGyroData[port][0] = data[0];
690 lr->core.sensorGyroData[port][1] = data[1];
691 lr->core.sensorGyroData[port][2] = data[2];
693 return lr->core.sensorGyroData[port][
id - RETRO_SENSOR_GYROSCOPE_X];
701static void SDL_Libretro_CloseSensors(SDL_Libretro* lr) {
704 for (
unsigned i = 0; i < SDL_LIBRETRO_SENSOR_PORTS; i++) {
706 if (lr->core.sensorAccel[i]) {
707 SDL_CloseSensor(lr->core.sensorAccel[i]);
708 lr->core.sensorAccel[i] = NULL;
710 lr->core.sensorAccelData[i][0] = 0.0f;
711 lr->core.sensorAccelData[i][1] = 0.0f;
712 lr->core.sensorAccelData[i][2] = 0.0f;
715 if (lr->core.sensorGyro[i]) {
716 SDL_CloseSensor(lr->core.sensorGyro[i]);
717 lr->core.sensorGyro[i] = NULL;
719 lr->core.sensorGyroData[i][0] = 0.0f;
720 lr->core.sensorGyroData[i][1] = 0.0f;
721 lr->core.sensorGyroData[i][2] = 0.0f;
unsigned SDL_Libretro_GetInputDescriptorCount(const SDL_Libretro *lr)
Retrieve the number of input descriptors provided by a Libretro core.
unsigned SDL_Libretro_GetPortDevice(const SDL_Libretro *lr, unsigned port)
Get the device type assigned to a controller port.
bool SDL_Libretro_GetInputDescriptor(const SDL_Libretro *lr, unsigned index, unsigned *port, unsigned *device, unsigned *id, const char **description)
Retrieve an input descriptor by index.
void SDL_Libretro_HandleEvent(SDL_Libretro *lr, const SDL_Event *event)
Call this function within the SDL_PollEvent() loop to ensure libretro knows of important events.