1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Mupen64plus - eventloop.c *
3 * Mupen64Plus homepage: https://mupen64plus.org/ *
4 * Copyright (C) 2008-2009 Richard Goedeken *
5 * Copyright (C) 2008 Ebenblues Nmn Okaygo Tillin9 *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
21 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
22
23#include <SDL.h>
24#include <SDL_syswm.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#if ! SDL_VERSION_ATLEAST(1,3,0)
29
30#define SDL_SCANCODE_ESCAPE SDLK_ESCAPE
31#define SDL_NUM_SCANCODES SDLK_LAST
32#define SDL_SCANCODE_F5 SDLK_F5
33#define SDL_SCANCODE_F7 SDLK_F7
34#define SDL_SCANCODE_F9 SDLK_F9
35#define SDL_SCANCODE_F10 SDLK_F10
36#define SDL_SCANCODE_F11 SDLK_F11
37#define SDL_SCANCODE_F12 SDLK_F12
38#define SDL_SCANCODE_P SDLK_p
39#define SDL_SCANCODE_M SDLK_m
40#define SDL_SCANCODE_RIGHTBRACKET SDLK_RIGHTBRACKET
41#define SDL_SCANCODE_LEFTBRACKET SDLK_LEFTBRACKET
42#define SDL_SCANCODE_F SDLK_f
43#define SDL_SCANCODE_SLASH SDLK_SLASH
44#define SDL_SCANCODE_G SDLK_g
45#define SDL_SCANCODE_RETURN SDLK_RETURN
46#define SDL_SCANCODE_0 SDLK_0
47#define SDL_SCANCODE_1 SDLK_1
48#define SDL_SCANCODE_2 SDLK_2
49#define SDL_SCANCODE_3 SDLK_3
50#define SDL_SCANCODE_4 SDLK_4
51#define SDL_SCANCODE_5 SDLK_5
52#define SDL_SCANCODE_6 SDLK_6
53#define SDL_SCANCODE_7 SDLK_7
54#define SDL_SCANCODE_8 SDLK_8
55#define SDL_SCANCODE_9 SDLK_9
56#define SDL_SCANCODE_UNKNOWN SDLK_UNKNOWN
57
58#define SDL_SetEventFilter(func, data) SDL_SetEventFilter(func)
59#define event_sdl_filter(userdata, event) event_sdl_filter(const event)
60
61#else
62 SDL_JoystickID l_iJoyInstanceID[10];
63#endif
64
65#define M64P_CORE_PROTOTYPES 1
66#include "api/callbacks.h"
67#include "api/config.h"
68#include "api/m64p_config.h"
69#include "api/m64p_types.h"
70#include "eventloop.h"
71#include "main.h"
72#include "plugin/plugin.h"
73#include "sdl_key_converter.h"
74#include "util.h"
75
76/* version number for CoreEvents config section */
77#define CONFIG_PARAM_VERSION 1.00
78
79static m64p_handle l_CoreEventsConfig = NULL;
80
81/*********************************************************************************************************
82* static variables and definitions for eventloop.c
83*/
84
85#define kbdFullscreen "Kbd Mapping Fullscreen"
86#define kbdStop "Kbd Mapping Stop"
87#define kbdPause "Kbd Mapping Pause"
88#define kbdSave "Kbd Mapping Save State"
89#define kbdLoad "Kbd Mapping Load State"
90#define kbdIncrement "Kbd Mapping Increment Slot"
91#define kbdReset "Kbd Mapping Reset"
92#define kbdSpeeddown "Kbd Mapping Speed Down"
93#define kbdSpeedup "Kbd Mapping Speed Up"
94#define kbdScreenshot "Kbd Mapping Screenshot"
95#define kbdMute "Kbd Mapping Mute"
96#define kbdIncrease "Kbd Mapping Increase Volume"
97#define kbdDecrease "Kbd Mapping Decrease Volume"
98#define kbdForward "Kbd Mapping Fast Forward"
99#define kbdAdvance "Kbd Mapping Frame Advance"
100#define kbdGameshark "Kbd Mapping Gameshark"
101
102typedef enum {joyFullscreen,
103 joyStop,
104 joyPause,
105 joySave,
106 joyLoad,
107 joyIncrement,
108 joyReset,
109 joySpeedDown,
110 joySpeedUp,
111 joyScreenshot,
112 joyMute,
113 joyIncrease,
114 joyDecrease,
115 joyForward,
116 joyAdvance,
117 joyGameshark
118} eJoyCommand;
119
120static const char *JoyCmdName[] = { "Joy Mapping Fullscreen",
121 "Joy Mapping Stop",
122 "Joy Mapping Pause",
123 "Joy Mapping Save State",
124 "Joy Mapping Load State",
125 "Joy Mapping Increment Slot",
126 "Joy Mapping Reset",
127 "Joy Mapping Speed Down",
128 "Joy Mapping Speed Up",
129 "Joy Mapping Screenshot",
130 "Joy Mapping Mute",
131 "Joy Mapping Increase Volume",
132 "Joy Mapping Decrease Volume",
133 "Joy Mapping Fast Forward",
134 "Joy Mapping Frame Advance",
135 "Joy Mapping Gameshark"};
136
137static const int NumJoyCommands = sizeof(JoyCmdName) / sizeof(const char *);
138
139static int JoyCmdActive[16][2]; /* if extra joystick commands are added above, make sure there is enough room in this array */
140 /* [i][0] is Command Active, [i][1] is Hotkey Active */
141
142static int GamesharkActive = 0;
143
144/*********************************************************************************************************
145* static functions for eventloop.c
146*/
147
148/** MatchJoyCommand
149 * This function processes an SDL event and updates the JoyCmdActive array if the
150 * event matches with the given command.
151 *
152 * If the event activates a joystick command which was not previously active, then
153 * a 1 is returned. If the event de-activates an command, a -1 is returned. Otherwise
154 * (if the event does not match the command or active status didn't change), a 0 is returned.
155 */
156static int MatchJoyCommand(const SDL_Event *event, eJoyCommand cmd)
157{
158 const char *multi_event_str = ConfigGetParamString(l_CoreEventsConfig, JoyCmdName[cmd]);
159 const int orig_cmd_value = (JoyCmdActive[cmd][1] << 1) | JoyCmdActive[cmd][0];
160 int dev_number, input_number, input_value;
161 char axis_direction;
162
163 /* Empty string or non-joystick command */
164 if (multi_event_str == NULL || strlen(multi_event_str) < 4 || multi_event_str[0] != 'J')
165 return 0;
166
167 /* Make copy of the event config string that we can hack it up with strtok */
168 char tokenized_event_str[128];
169 strncpy(tokenized_event_str, multi_event_str, 127);
170 tokenized_event_str[127] = '\0';
171
172 /* Iterate over comma-separated config phrases */
173 char *phrase_str = strtok(tokenized_event_str, ",");
174 while (phrase_str != NULL)
175 {
176 int iHotkey, has_hotkey = 0;
177
178 /* Check for invalid phrase */
179 if (strlen(phrase_str) < 4 || phrase_str[0] != 'J')
180 {
181 phrase_str = strtok(NULL, ",");
182 continue;
183 }
184
185 /* Get device (joystick) number */
186 if (phrase_str[1] == '*')
187 {
188 dev_number = -1;
189 }
190 else if (phrase_str[1] >= '0' && phrase_str[1] <= '9')
191 {
192 dev_number = phrase_str[1] - '0';
193#if SDL_VERSION_ATLEAST(2,0,0)
194 dev_number = l_iJoyInstanceID[dev_number];
195#endif
196 }
197 else
198 {
199 phrase_str = strtok(NULL, ",");
200 continue;
201 }
202
203 /* Iterate over JoyAction/JoyHotkey action fields */
204 for (iHotkey = 0; iHotkey < 2; iHotkey++)
205 {
206 const char *action_str = NULL;
207 if (iHotkey == 0)
208 {
209 action_str = phrase_str + 2;
210 }
211 else
212 {
213 char *hotkey_str = strchr(phrase_str, '/');
214 if (hotkey_str == NULL || strlen(hotkey_str) < 3)
215 {
216 break;
217 }
218 action_str = hotkey_str+1;
219 has_hotkey = 1;
220 }
221
222 /* Evaluate action based on type of joystick input expected */
223 switch (action_str[0])
224 {
225 /* Axis */
226 case 'A':
227 if (event->type != SDL_JOYAXISMOTION)
228 break;
229 if (sscanf(action_str, "A%d%c", &input_number, &axis_direction) != 2)
230 break;
231 if ((dev_number != 1 && dev_number != event->jaxis.which) || input_number != event->jaxis.axis)
232 break;
233 if (axis_direction == '+')
234 {
235 if (event->jaxis.value >= 15000)
236 JoyCmdActive[cmd][iHotkey] = 1;
237 else if (event->jaxis.value <= 8000)
238 JoyCmdActive[cmd][iHotkey] = 0;
239 break;
240 }
241 else if (axis_direction == '-')
242 {
243 if (event->jaxis.value <= -15000)
244 JoyCmdActive[cmd][iHotkey] = 1;
245 else if (event->jaxis.value >= -8000)
246 JoyCmdActive[cmd][iHotkey] = 0;
247 break;
248 }
249 break;
250 /* Hat */
251 case 'H':
252 if (event->type != SDL_JOYHATMOTION)
253 break;
254 if (sscanf(action_str, "H%dV%d", &input_number, &input_value) != 2)
255 break;
256 if ((dev_number != -1 && dev_number != event->jhat.which) || input_number != event->jhat.hat)
257 break;
258 if ((event->jhat.value & input_value) == input_value)
259 JoyCmdActive[cmd][iHotkey] = 1;
260 else if ((event->jhat.value & input_value) != input_value)
261 JoyCmdActive[cmd][iHotkey] = 0;
262 break;
263 /* Button. */
264 case 'B':
265 if (event->type != SDL_JOYBUTTONDOWN && event->type != SDL_JOYBUTTONUP)
266 break;
267 if (sscanf(action_str, "B%d", &input_number) != 1)
268 break;
269 if ((dev_number != -1 && dev_number != event->jbutton.which) || input_number != event->jbutton.button)
270 break;
271 if (event->type == SDL_JOYBUTTONDOWN)
272 JoyCmdActive[cmd][iHotkey] = 1;
273 else if (event->type == SDL_JOYBUTTONUP)
274 JoyCmdActive[cmd][iHotkey] = 0;
275 break;
276 default:
277 /* bad configuration parameter */
278 break;
279 }
280 } /* Iterate over JoyAction/JoyHotkey action fields */
281
282 /* Detect changes in command activation status */
283 const int new_cmd_value = (JoyCmdActive[cmd][1] << 1) | JoyCmdActive[cmd][0];
284 const int active_mask = has_hotkey ? 3 : 1;
285 if ((orig_cmd_value & active_mask) != active_mask && (new_cmd_value & active_mask) == active_mask)
286 return 1;
287 if ((orig_cmd_value & active_mask) == active_mask && (new_cmd_value & active_mask) != active_mask)
288 return -1;
289
290 /* get next comma-separated command phrase from event string */
291 phrase_str = strtok(NULL, ",");
292 } /* Iterate over comma-separated config phrases */
293
294 /* nothing found */
295 return 0;
296}
297
298/*********************************************************************************************************
299* sdl event filter
300*/
301static int SDLCALL event_sdl_filter(void *userdata, SDL_Event *event)
302{
303 int cmd, action;
304
305 switch(event->type)
306 {
307 // user clicked on window close button
308 case SDL_QUIT:
309 main_stop();
310 break;
311
312 case SDL_KEYDOWN:
313#if SDL_VERSION_ATLEAST(1,3,0)
314 if (event->key.repeat)
315 return 0;
316
317 event_sdl_keydown(event->key.keysym.scancode, event->key.keysym.mod);
318#else
319 event_sdl_keydown(event->key.keysym.sym, event->key.keysym.mod);
320#endif
321 return 0;
322 case SDL_KEYUP:
323#if SDL_VERSION_ATLEAST(1,3,0)
324 event_sdl_keyup(event->key.keysym.scancode, event->key.keysym.mod);
325#else
326 event_sdl_keyup(event->key.keysym.sym, event->key.keysym.mod);
327#endif
328 return 0;
329
330#if SDL_VERSION_ATLEAST(1,3,0)
331 case SDL_WINDOWEVENT:
332 switch (event->window.event) {
333 case SDL_WINDOWEVENT_RESIZED:
334 // call the video plugin. if the video plugin supports resizing, it will resize its viewport and call
335 // VidExt_ResizeWindow to update the window manager handling our opengl output window
336 gfx.resizeVideoOutput(event->window.data1, event->window.data2);
337 return 0; // consumed the event
338 break;
339
340 case SDL_WINDOWEVENT_MOVED:
341 gfx.moveScreen(event->window.data1, event->window.data2);
342 return 0; // consumed the event
343 break;
344 }
345 break;
346#else
347 case SDL_VIDEORESIZE:
348 // call the video plugin. if the video plugin supports resizing, it will resize its viewport and call
349 // VidExt_ResizeWindow to update the window manager handling our opengl output window
350 gfx.resizeVideoOutput(event->resize.w, event->resize.h);
351 return 0; // consumed the event
352 break;
353
354#ifdef WIN32
355 case SDL_SYSWMEVENT:
356 if(event->syswm.msg->msg == WM_MOVE)
357 gfx.moveScreen(0,0); // The video plugin is responsible for getting the new window position
358 return 0; // consumed the event
359 break;
360#endif
361#endif
362
363 // if joystick action is detected, check if it's mapped to a special function
364 case SDL_JOYAXISMOTION:
365 case SDL_JOYBUTTONDOWN:
366 case SDL_JOYBUTTONUP:
367 case SDL_JOYHATMOTION:
368 for (cmd = 0; cmd < NumJoyCommands; cmd++)
369 {
370 action = MatchJoyCommand(event, (eJoyCommand) cmd);
371 if (action == 1) /* command was just activated (button down, etc) */
372 {
373 if (cmd == joyFullscreen)
374 gfx.changeWindow();
375 else if (cmd == joyStop)
376 main_stop();
377 else if (cmd == joyPause)
378 main_toggle_pause();
379 else if (cmd == joySave)
380 main_state_save(1, NULL); /* save in mupen64plus format using current slot */
381 else if (cmd == joyLoad)
382 main_state_load(NULL); /* load using current slot */
383 else if (cmd == joyIncrement)
384 main_state_inc_slot();
385 else if (cmd == joyReset)
386 main_reset(0);
387 else if (cmd == joySpeedDown)
388 main_speeddown(5);
389 else if (cmd == joySpeedUp)
390 main_speedup(5);
391 else if (cmd == joyScreenshot)
392 main_take_next_screenshot();
393 else if (cmd == joyMute)
394 main_volume_mute();
395 else if (cmd == joyDecrease)
396 main_volume_down();
397 else if (cmd == joyIncrease)
398 main_volume_up();
399 else if (cmd == joyForward)
400 main_set_fastforward(1);
401 else if (cmd == joyAdvance)
402 main_advance_one();
403 else if (cmd == joyGameshark)
404 event_set_gameshark(1);
405 }
406 else if (action == -1) /* command was just de-activated (button up, etc) */
407 {
408 if (cmd == joyForward)
409 main_set_fastforward(0);
410 else if (cmd == joyGameshark)
411 event_set_gameshark(0);
412 }
413 }
414
415 return 0;
416 break;
417 }
418
419 return 1; // add this event to SDL queue
420}
421
422/*********************************************************************************************************
423* global functions
424*/
425
426void event_initialize(void)
427{
428 int i, j;
429
430 /* set initial state of all joystick commands to 'off' */
431 for (i = 0; i < NumJoyCommands; i++)
432 for (j = 0; j < 2; j++)
433 JoyCmdActive[i][j] = 0;
434
435 /* activate any joysticks which are referenced in the joystick event command strings */
436 const int NumJoysticks = SDL_NumJoysticks();
437 if (NumJoysticks > 0)
438 {
439 for (i = 0; i < NumJoyCommands; i++)
440 {
441 const char *multi_event_str = ConfigGetParamString(l_CoreEventsConfig, JoyCmdName[i]);
442 /* Empty string or invalid command */
443 if (multi_event_str == NULL || strlen(multi_event_str) < 4 || multi_event_str[0] != 'J')
444 continue;
445 /* Make copy of the event config string that we can hack it up with strtok */
446 char tokenized_event_str[128];
447 strncpy(tokenized_event_str, multi_event_str, 127);
448 tokenized_event_str[127] = '\0';
449 /* Iterate over comma-separated config phrases */
450 char *phrase_str = strtok(tokenized_event_str, ",");
451 while (phrase_str != NULL)
452 {
453 /* Check for invalid phrase */
454 if (strlen(phrase_str) < 4 || phrase_str[0] != 'J')
455 {
456 phrase_str = strtok(NULL, ",");
457 continue;
458 }
459 /* Get device (joystick) number(s) to initialize */
460 int joy_min, joy_max;
461 if (phrase_str[1] == '*')
462 {
463 joy_min = 0;
464 joy_max = NumJoysticks - 1;
465 }
466 else if (phrase_str[1] >= '0' && phrase_str[1] <= '9')
467 {
468 joy_min = joy_max = phrase_str[1] - '0';
469 }
470 else
471 {
472 phrase_str = strtok(NULL, ",");
473 continue;
474 }
475 /* initialize them */
476 int device;
477 for (device = joy_min; device <= joy_max; device++)
478 {
479 if (!SDL_WasInit(SDL_INIT_JOYSTICK))
480 SDL_InitSubSystem(SDL_INIT_JOYSTICK);
481#if SDL_VERSION_ATLEAST(2,0,0)
482 SDL_Joystick *thisJoy = SDL_JoystickOpen(device);
483 l_iJoyInstanceID[device] = SDL_JoystickInstanceID(thisJoy);
484#else
485 if (!SDL_JoystickOpened(device))
486 SDL_JoystickOpen(device);
487#endif
488 }
489
490 phrase_str = strtok(NULL, ",");
491 } /* Iterate over comma-separated config phrases */
492 }
493 }
494
495 /* set up SDL event filter and disable key repeat */
496#if !SDL_VERSION_ATLEAST(2,0,0)
497 SDL_EnableKeyRepeat(0, 0);
498#endif
499 SDL_SetEventFilter(event_sdl_filter, NULL);
500
501#if defined(WIN32) && !SDL_VERSION_ATLEAST(1,3,0)
502 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
503
504 if (SDL_EventState(SDL_SYSWMEVENT, SDL_QUERY) != SDL_ENABLE)
505 DebugMessage(M64MSG_WARNING, "Failed to change event state: %s", SDL_GetError());
506#endif
507}
508
509int event_set_core_defaults(void)
510{
511 float fConfigParamsVersion;
512
513 if (ConfigOpenSection("CoreEvents", &l_CoreEventsConfig) != M64ERR_SUCCESS || l_CoreEventsConfig == NULL)
514 {
515 DebugMessage(M64MSG_ERROR, "Failed to open CoreEvents config section.");
516 return 0; /* fail */
517 }
518
519 if (ConfigGetParameter(l_CoreEventsConfig, "Version", M64TYPE_FLOAT, &fConfigParamsVersion, sizeof(float)) != M64ERR_SUCCESS)
520 {
521 DebugMessage(M64MSG_WARNING, "No version number in 'CoreEvents' config section. Setting defaults.");
522 ConfigDeleteSection("CoreEvents");
523 ConfigOpenSection("CoreEvents", &l_CoreEventsConfig);
524 }
525 else if (((int) fConfigParamsVersion) != ((int) CONFIG_PARAM_VERSION))
526 {
527 DebugMessage(M64MSG_WARNING, "Incompatible version %.2f in 'CoreEvents' config section: current is %.2f. Setting defaults.", fConfigParamsVersion, (float) CONFIG_PARAM_VERSION);
528 ConfigDeleteSection("CoreEvents");
529 ConfigOpenSection("CoreEvents", &l_CoreEventsConfig);
530 }
531 else if ((CONFIG_PARAM_VERSION - fConfigParamsVersion) >= 0.0001f)
532 {
533 /* handle upgrades */
534 float fVersion = CONFIG_PARAM_VERSION;
535 ConfigSetParameter(l_CoreEventsConfig, "Version", M64TYPE_FLOAT, &fVersion);
536 DebugMessage(M64MSG_INFO, "Updating parameter set version in 'CoreEvents' config section to %.2f", fVersion);
537 }
538
539 ConfigSetDefaultFloat(l_CoreEventsConfig, "Version", CONFIG_PARAM_VERSION, "Mupen64Plus CoreEvents config parameter set version number. Please don't change this version number.");
540 /* Keyboard presses mapped to core functions */
541 ConfigSetDefaultInt(l_CoreEventsConfig, kbdStop, sdl_native2keysym(SDL_SCANCODE_ESCAPE), "SDL keysym for stopping the emulator");
542 ConfigSetDefaultInt(l_CoreEventsConfig, kbdFullscreen, sdl_native2keysym(SDL_NUM_SCANCODES), "SDL keysym for switching between fullscreen/windowed modes");
543 ConfigSetDefaultInt(l_CoreEventsConfig, kbdSave, sdl_native2keysym(SDL_SCANCODE_F5), "SDL keysym for saving the emulator state");
544 ConfigSetDefaultInt(l_CoreEventsConfig, kbdLoad, sdl_native2keysym(SDL_SCANCODE_F7), "SDL keysym for loading the emulator state");
545 ConfigSetDefaultInt(l_CoreEventsConfig, kbdIncrement, sdl_native2keysym(SDL_SCANCODE_UNKNOWN), "SDL keysym for advancing the save state slot");
546 ConfigSetDefaultInt(l_CoreEventsConfig, kbdReset, sdl_native2keysym(SDL_SCANCODE_F9), "SDL keysym for resetting the emulator");
547 ConfigSetDefaultInt(l_CoreEventsConfig, kbdSpeeddown, sdl_native2keysym(SDL_SCANCODE_F10), "SDL keysym for slowing down the emulator");
548 ConfigSetDefaultInt(l_CoreEventsConfig, kbdSpeedup, sdl_native2keysym(SDL_SCANCODE_F11), "SDL keysym for speeding up the emulator");
549 ConfigSetDefaultInt(l_CoreEventsConfig, kbdScreenshot, sdl_native2keysym(SDL_SCANCODE_F12), "SDL keysym for taking a screenshot");
550 ConfigSetDefaultInt(l_CoreEventsConfig, kbdPause, sdl_native2keysym(SDL_SCANCODE_P), "SDL keysym for pausing the emulator");
551 ConfigSetDefaultInt(l_CoreEventsConfig, kbdMute, sdl_native2keysym(SDL_SCANCODE_M), "SDL keysym for muting/unmuting the sound");
552 ConfigSetDefaultInt(l_CoreEventsConfig, kbdIncrease, sdl_native2keysym(SDL_SCANCODE_RIGHTBRACKET),"SDL keysym for increasing the volume");
553 ConfigSetDefaultInt(l_CoreEventsConfig, kbdDecrease, sdl_native2keysym(SDL_SCANCODE_LEFTBRACKET), "SDL keysym for decreasing the volume");
554 ConfigSetDefaultInt(l_CoreEventsConfig, kbdForward, sdl_native2keysym(SDL_SCANCODE_F), "SDL keysym for temporarily going really fast");
555 ConfigSetDefaultInt(l_CoreEventsConfig, kbdAdvance, sdl_native2keysym(SDL_SCANCODE_SLASH), "SDL keysym for advancing by one frame when paused");
556 ConfigSetDefaultInt(l_CoreEventsConfig, kbdGameshark, sdl_native2keysym(SDL_SCANCODE_G), "SDL keysym for pressing the game shark button");
557 /* Joystick events mapped to core functions */
558 ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyStop], "", "Joystick event string for stopping the emulator");
559 ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyFullscreen], "", "Joystick event string for switching between fullscreen/windowed modes");
560 ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joySave], "", "Joystick event string for saving the emulator state");
561 ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyLoad], "", "Joystick event string for loading the emulator state");
562 ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyIncrement], "", "Joystick event string for advancing the save state slot");
563 ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyReset], "", "Joystick event string for resetting the emulator");
564 ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joySpeedDown], "", "Joystick event string for slowing down the emulator");
565 ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joySpeedUp], "", "Joystick event string for speeding up the emulator");
566 ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyScreenshot], "", "Joystick event string for taking a screenshot");
567 ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyPause], "", "Joystick event string for pausing the emulator");
568 ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyMute], "", "Joystick event string for muting/unmuting the sound");
569 ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyIncrease], "", "Joystick event string for increasing the volume");
570 ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyDecrease], "", "Joystick event string for decreasing the volume");
571 ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyForward], "", "Joystick event string for fast-forward");
572 ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyAdvance], "", "Joystick event string for advancing by one frame when paused");
573 ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyGameshark], "", "Joystick event string for pressing the game shark button");
574
575 return 1;
576}
577
578static int get_saveslot_from_keysym(int keysym)
579{
580 switch (keysym) {
581 case SDL_SCANCODE_0:
582 return 0;
583 case SDL_SCANCODE_1:
584 return 1;
585 case SDL_SCANCODE_2:
586 return 2;
587 case SDL_SCANCODE_3:
588 return 3;
589 case SDL_SCANCODE_4:
590 return 4;
591 case SDL_SCANCODE_5:
592 return 5;
593 case SDL_SCANCODE_6:
594 return 6;
595 case SDL_SCANCODE_7:
596 return 7;
597 case SDL_SCANCODE_8:
598 return 8;
599 case SDL_SCANCODE_9:
600 return 9;
601 default:
602 return -1;
603 }
604}
605
606/*********************************************************************************************************
607* sdl keyup/keydown handlers
608*/
609
610void event_sdl_keydown(int keysym, int keymod)
611{
612 int slot;
613
614 /* check for the only 2 hard-coded key commands: Alt-enter for fullscreen and 0-9 for save state slot */
615 if (keysym == SDL_SCANCODE_RETURN && keymod & (KMOD_LALT | KMOD_RALT))
616 gfx.changeWindow();
617 else if ((slot = get_saveslot_from_keysym(keysym)) >= 0)
618 main_state_set_slot(slot);
619 /* check all of the configurable commands */
620 else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdStop)))
621 main_stop();
622 else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdFullscreen)))
623 gfx.changeWindow();
624 else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdSave)))
625 main_state_save(0, NULL); /* save in mupen64plus format using current slot */
626 else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdLoad)))
627 main_state_load(NULL); /* load using current slot */
628 else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdIncrement)))
629 main_state_inc_slot();
630 else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdReset)))
631 main_reset(0);
632 else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdSpeeddown)))
633 main_speeddown(5);
634 else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdSpeedup)))
635 main_speedup(5);
636 else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdScreenshot)))
637 main_take_next_screenshot(); /* screenshot will be taken at the end of frame rendering */
638 else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdPause)))
639 main_toggle_pause();
640 else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdMute)))
641 main_volume_mute();
642 else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdIncrease)))
643 main_volume_up();
644 else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdDecrease)))
645 main_volume_down();
646 else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdForward)))
647 main_set_fastforward(1);
648 else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdAdvance)))
649 main_advance_one();
650 else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdGameshark))) {
651 event_set_gameshark(1);
652 }
653 else
654 {
655 /* pass all other keypresses to the input plugin */
656 input.keyDown(keymod, keysym);
657 }
658
659}
660
661void event_sdl_keyup(int keysym, int keymod)
662{
663 if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdStop)))
664 {
665 return;
666 }
667 else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdForward)))
668 {
669 main_set_fastforward(0);
670 }
671 else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdGameshark)))
672 {
673 event_set_gameshark(0);
674 }
675 else input.keyUp(keymod, keysym);
676
677}
678
679int event_gameshark_active(void)
680{
681 return GamesharkActive;
682}
683
684void event_set_gameshark(int active)
685{
686 // if boolean value doesn't change then just return
687 if (!active == !GamesharkActive)
688 return;
689
690 // set the button state
691 GamesharkActive = (active ? 1 : 0);
692
693 // notify front-end application that gameshark button state has changed
694 StateChanged(M64CORE_INPUT_GAMESHARK, GamesharkActive);
695}
696
697