ALL: Huge upstream synch + PerRom DelaySI & CountPerOp parameters
[mupen64plus-pandora.git] / source / mupen64plus-core / src / main / eventloop.c
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  *   Mupen64plus - eventloop.c                                             *
3  *   Mupen64Plus homepage: http://code.google.com/p/mupen64plus/           *
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 <stdlib.h>
24 #include <SDL.h>
25 #if ! SDL_VERSION_ATLEAST(1,3,0)
26
27 #define SDL_SCANCODE_ESCAPE SDLK_ESCAPE
28 #define SDL_NUM_SCANCODES SDLK_LAST
29 #define SDL_SCANCODE_F5 SDLK_F5
30 #define SDL_SCANCODE_F7 SDLK_F7
31 #define SDL_SCANCODE_F9 SDLK_F9
32 #define SDL_SCANCODE_F10 SDLK_F10
33 #define SDL_SCANCODE_F11 SDLK_F11
34 #define SDL_SCANCODE_F12 SDLK_F12
35 #define SDL_SCANCODE_P SDLK_p
36 #define SDL_SCANCODE_M SDLK_m
37 #define SDL_SCANCODE_RIGHTBRACKET SDLK_RIGHTBRACKET
38 #define SDL_SCANCODE_LEFTBRACKET SDLK_LEFTBRACKET
39 #define SDL_SCANCODE_F SDLK_f
40 #define SDL_SCANCODE_SLASH SDLK_SLASH
41 #define SDL_SCANCODE_G SDLK_g
42 #define SDL_SCANCODE_RETURN SDLK_RETURN
43 #define SDL_SCANCODE_0 SDLK_0
44 #define SDL_SCANCODE_1 SDLK_1
45 #define SDL_SCANCODE_2 SDLK_2
46 #define SDL_SCANCODE_3 SDLK_3
47 #define SDL_SCANCODE_4 SDLK_4
48 #define SDL_SCANCODE_5 SDLK_5
49 #define SDL_SCANCODE_6 SDLK_6
50 #define SDL_SCANCODE_7 SDLK_7
51 #define SDL_SCANCODE_8 SDLK_8
52 #define SDL_SCANCODE_9 SDLK_9
53
54 #define SDL_SetEventFilter(func, data) SDL_SetEventFilter(func)
55 #define event_sdl_filter(userdata, event) event_sdl_filter(const event)
56
57 #endif
58
59 #define M64P_CORE_PROTOTYPES 1
60 #include "main.h"
61 #include "eventloop.h"
62 #include "util.h"
63 #include "api/callbacks.h"
64 #include "api/config.h"
65 #include "api/m64p_config.h"
66 #include "plugin/plugin.h"
67 #include "r4300/interupt.h"
68 #include "r4300/reset.h"
69
70 /* version number for CoreEvents config section */
71 #define CONFIG_PARAM_VERSION 1.00
72
73 static m64p_handle l_CoreEventsConfig = NULL;
74
75 /*********************************************************************************************************
76 * static variables and definitions for eventloop.c
77 */
78
79 #define kbdFullscreen "Kbd Mapping Fullscreen"
80 #define kbdStop "Kbd Mapping Stop"
81 #define kbdPause "Kbd Mapping Pause"
82 #define kbdSave "Kbd Mapping Save State"
83 #define kbdLoad "Kbd Mapping Load State"
84 #define kbdIncrement "Kbd Mapping Increment Slot"
85 #define kbdReset "Kbd Mapping Reset"
86 #define kbdSpeeddown "Kbd Mapping Speed Down"
87 #define kbdSpeedup "Kbd Mapping Speed Up"
88 #define kbdScreenshot "Kbd Mapping Screenshot"
89 #define kbdMute "Kbd Mapping Mute"
90 #define kbdIncrease "Kbd Mapping Increase Volume"
91 #define kbdDecrease "Kbd Mapping Decrease Volume"
92 #define kbdForward "Kbd Mapping Fast Forward"
93 #define kbdAdvance "Kbd Mapping Frame Advance"
94 #define kbdGameshark "Kbd Mapping Gameshark"
95
96 typedef enum {joyFullscreen,
97               joyStop,
98               joyPause,
99               joySave,
100               joyLoad,
101               joyIncrement,
102               joyScreenshot,
103               joyMute,
104               joyIncrease,
105               joyDecrease,
106               joyForward,
107               joyGameshark
108 } eJoyCommand;
109
110 static const char *JoyCmdName[] = { "Joy Mapping Fullscreen",
111                                     "Joy Mapping Stop",
112                                     "Joy Mapping Pause",
113                                     "Joy Mapping Save State",
114                                     "Joy Mapping Load State",
115                                     "Joy Mapping Increment Slot",
116                                     "Joy Mapping Screenshot",
117                                     "Joy Mapping Mute",
118                                     "Joy Mapping Increase Volume",
119                                     "Joy Mapping Decrease Volume",
120                                     "Joy Mapping Fast Forward",
121                                     "Joy Mapping Gameshark"};
122
123 static const int NumJoyCommands = sizeof(JoyCmdName) / sizeof(const char *);
124
125 static int JoyCmdActive[16];  /* if extra joystick commands are added above, make sure there is enough room in this array */
126
127 static int GamesharkActive = 0;
128
129 /*********************************************************************************************************
130 * static functions for eventloop.c
131 */
132
133 /** MatchJoyCommand
134  *    This function processes an SDL event and updates the JoyCmdActive array if the
135  *    event matches with the given command.
136  *
137  *    If the event activates a joystick command which was not previously active, then
138  *    a 1 is returned.  If the event de-activates an command, a -1 is returned.  Otherwise
139  *    (if the event does not match the command or active status didn't change), a 0 is returned.
140  */
141 static int MatchJoyCommand(const SDL_Event *event, eJoyCommand cmd)
142 {
143     const char *event_str = ConfigGetParamString(l_CoreEventsConfig, JoyCmdName[cmd]);
144     int dev_number, input_number, input_value;
145     char axis_direction;
146
147     /* Empty string or non-joystick command */
148     if (event_str == NULL || strlen(event_str) < 4 || event_str[0] != 'J')
149         return 0;
150
151     /* Evaluate event based on type of joystick input expected by the given command */
152     switch (event_str[2])
153     {
154         /* Axis */
155         case 'A':
156             if (event->type != SDL_JOYAXISMOTION)
157                 return 0;
158             if (sscanf(event_str, "J%dA%d%c", &dev_number, &input_number, &axis_direction) != 3)
159                 return 0;
160             if (dev_number != event->jaxis.which || input_number != event->jaxis.axis)
161                 return 0;
162             if (axis_direction == '+')
163             {
164                 if (event->jaxis.value >= 15000 && JoyCmdActive[cmd] == 0)
165                 {
166                     JoyCmdActive[cmd] = 1;
167                     return 1;
168                 }
169                 else if (event->jaxis.value <= 8000 && JoyCmdActive[cmd] == 1)
170                 {
171                     JoyCmdActive[cmd] = 0;
172                     return -1;
173                 }
174                 return 0;
175             }
176             else if (axis_direction == '-')
177             {
178                 if (event->jaxis.value <= -15000 && JoyCmdActive[cmd] == 0)
179                 {
180                     JoyCmdActive[cmd] = 1;
181                     return 1;
182                 }
183                 else if (event->jaxis.value >= -8000 && JoyCmdActive[cmd] == 1)
184                 {
185                     JoyCmdActive[cmd] = 0;
186                     return -1;
187                 }
188                 return 0;
189             }
190             else return 0; /* invalid axis direction in configuration parameter */
191             break;
192         /* Hat */
193         case 'H':
194             if (event->type != SDL_JOYHATMOTION)
195                 return 0;
196             if (sscanf(event_str, "J%dH%dV%d", &dev_number, &input_number, &input_value) != 3)
197                 return 0;
198             if (dev_number != event->jhat.which || input_number != event->jhat.hat)
199                 return 0;
200             if ((event->jhat.value & input_value) == input_value && JoyCmdActive[cmd] == 0)
201             {
202                 JoyCmdActive[cmd] = 1;
203                 return 1;
204             }
205             else if ((event->jhat.value & input_value) != input_value  && JoyCmdActive[cmd] == 1)
206             {
207                 JoyCmdActive[cmd] = 0;
208                 return -1;
209             }
210             return 0;
211             break;
212         /* Button. */
213         case 'B':
214             if (event->type != SDL_JOYBUTTONDOWN && event->type != SDL_JOYBUTTONUP)
215                 return 0;
216             if (sscanf(event_str, "J%dB%d", &dev_number, &input_number) != 2)
217                 return 0;
218             if (dev_number != event->jbutton.which || input_number != event->jbutton.button)
219                 return 0;
220             if (event->type == SDL_JOYBUTTONDOWN && JoyCmdActive[cmd] == 0)
221             {
222                 JoyCmdActive[cmd] = 1;
223                 return 1;
224             }
225             else if (event->type == SDL_JOYBUTTONUP && JoyCmdActive[cmd] == 1)
226             {
227                 JoyCmdActive[cmd] = 0;
228                 return -1;
229             }
230             return 0;
231             break;
232         default:
233             /* bad configuration parameter */
234             return 0;
235     }
236
237     /* impossible to reach this point */
238     return 0;
239 }
240
241 /*********************************************************************************************************
242 * sdl event filter
243 */
244 static int SDLCALL event_sdl_filter(void *userdata, SDL_Event *event)
245 {
246     int cmd, action;
247
248     switch(event->type)
249     {
250         // user clicked on window close button
251         case SDL_QUIT:
252             main_stop();
253             break;
254
255         case SDL_KEYDOWN:
256 #if SDL_VERSION_ATLEAST(1,3,0)
257             if (event->key.repeat)
258                 return 0;
259
260             event_sdl_keydown(event->key.keysym.scancode, event->key.keysym.mod);
261 #else
262             event_sdl_keydown(event->key.keysym.sym, event->key.keysym.mod);
263 #endif
264             return 0;
265         case SDL_KEYUP:
266 #if SDL_VERSION_ATLEAST(1,3,0)
267             event_sdl_keyup(event->key.keysym.scancode, event->key.keysym.mod);
268 #else
269             event_sdl_keyup(event->key.keysym.sym, event->key.keysym.mod);
270 #endif
271             return 0;
272
273 #if SDL_VERSION_ATLEAST(2,0,0)
274         case SDL_WINDOWEVENT:
275             switch (event->window.event) {
276                 case SDL_WINDOWEVENT_RESIZED:
277                     // call the video plugin.  if the video plugin supports resizing, it will resize its viewport and call
278                     // VidExt_ResizeWindow to update the window manager handling our opengl output window
279                     gfx.resizeVideoOutput(event->window.data1, event->window.data2);
280                     return 0;  // consumed the event
281                     break;
282             }
283             break;
284 #else
285         case SDL_VIDEORESIZE:
286             // call the video plugin.  if the video plugin supports resizing, it will resize its viewport and call
287             // VidExt_ResizeWindow to update the window manager handling our opengl output window
288             gfx.resizeVideoOutput(event->resize.w, event->resize.h);
289             return 0;  // consumed the event
290             break;
291 #endif
292
293         // if joystick action is detected, check if it's mapped to a special function
294         case SDL_JOYAXISMOTION:
295         case SDL_JOYBUTTONDOWN:
296         case SDL_JOYBUTTONUP:
297         case SDL_JOYHATMOTION:
298             for (cmd = 0; cmd < NumJoyCommands; cmd++)
299             {
300                 action = MatchJoyCommand(event, (eJoyCommand) cmd);
301                 if (action == 1) /* command was just activated (button down, etc) */
302                 {
303                     if (cmd == joyFullscreen)
304                         gfx.changeWindow();
305                     else if (cmd == joyStop)
306                         main_stop();
307                     else if (cmd == joyPause)
308                         main_toggle_pause();
309                     else if (cmd == joySave)
310                         main_state_save(1, NULL); /* save in mupen64plus format using current slot */
311                     else if (cmd == joyLoad)
312                         main_state_load(NULL); /* load using current slot */
313                     else if (cmd == joyIncrement)
314                         main_state_inc_slot();
315                     else if (cmd == joyScreenshot)
316                         main_take_next_screenshot();
317                     else if (cmd == joyMute)
318                         main_volume_mute();
319                     else if (cmd == joyDecrease)
320                         main_volume_down();
321                     else if (cmd == joyIncrease)
322                         main_volume_up();
323                     else if (cmd == joyForward)
324                         main_set_fastforward(1);
325                     else if (cmd == joyGameshark)
326                         event_set_gameshark(1);
327                 }
328                 else if (action == -1) /* command was just de-activated (button up, etc) */
329                 {
330                     if (cmd == joyForward)
331                         main_set_fastforward(0);
332                     else if (cmd == joyGameshark)
333                         event_set_gameshark(0);
334                 }
335             }
336
337             return 0;
338             break;
339     }
340
341     return 1;
342 }
343
344 /*********************************************************************************************************
345 * global functions
346 */
347
348 void event_initialize(void)
349 {
350     const char *event_str = NULL;
351     int i;
352
353     /* set initial state of all joystick commands to 'off' */
354     for (i = 0; i < NumJoyCommands; i++)
355         JoyCmdActive[i] = 0;
356
357     /* activate any joysticks which are referenced in the joystick event command strings */
358     for (i = 0; i < NumJoyCommands; i++)
359     {
360         event_str = ConfigGetParamString(l_CoreEventsConfig, JoyCmdName[i]);
361         if (event_str != NULL && strlen(event_str) >= 4 && event_str[0] == 'J' && event_str[1] >= '0' && event_str[1] <= '9')
362         {
363             int device = event_str[1] - '0';
364             if (!SDL_WasInit(SDL_INIT_JOYSTICK))
365                 SDL_InitSubSystem(SDL_INIT_JOYSTICK);
366 #if SDL_VERSION_ATLEAST(2,0,0)
367             SDL_JoystickOpen(device);
368 #else
369             if (!SDL_JoystickOpened(device))
370                 SDL_JoystickOpen(device);
371 #endif
372         }
373     }
374
375     /* set up SDL event filter and disable key repeat */
376 #if !SDL_VERSION_ATLEAST(2,0,0)
377     SDL_EnableKeyRepeat(0, 0);
378 #endif
379     SDL_SetEventFilter(event_sdl_filter, NULL);
380 }
381
382 int event_set_core_defaults(void)
383 {
384     float fConfigParamsVersion;
385     int bSaveConfig = 0;
386
387     if (ConfigOpenSection("CoreEvents", &l_CoreEventsConfig) != M64ERR_SUCCESS || l_CoreEventsConfig == NULL)
388     {
389         DebugMessage(M64MSG_ERROR, "Failed to open CoreEvents config section.");
390         return 0; /* fail */
391     }
392
393     if (ConfigGetParameter(l_CoreEventsConfig, "Version", M64TYPE_FLOAT, &fConfigParamsVersion, sizeof(float)) != M64ERR_SUCCESS)
394     {
395         DebugMessage(M64MSG_WARNING, "No version number in 'CoreEvents' config section. Setting defaults.");
396         ConfigDeleteSection("CoreEvents");
397         ConfigOpenSection("CoreEvents", &l_CoreEventsConfig);
398         bSaveConfig = 1;
399     }
400     else if (((int) fConfigParamsVersion) != ((int) CONFIG_PARAM_VERSION))
401     {
402         DebugMessage(M64MSG_WARNING, "Incompatible version %.2f in 'CoreEvents' config section: current is %.2f. Setting defaults.", fConfigParamsVersion, (float) CONFIG_PARAM_VERSION);
403         ConfigDeleteSection("CoreEvents");
404         ConfigOpenSection("CoreEvents", &l_CoreEventsConfig);
405         bSaveConfig = 1;
406     }
407     else if ((CONFIG_PARAM_VERSION - fConfigParamsVersion) >= 0.0001f)
408     {
409         /* handle upgrades */
410         float fVersion = CONFIG_PARAM_VERSION;
411         ConfigSetParameter(l_CoreEventsConfig, "Version", M64TYPE_FLOAT, &fVersion);
412         DebugMessage(M64MSG_INFO, "Updating parameter set version in 'CoreEvents' config section to %.2f", fVersion);
413         bSaveConfig = 1;
414     }
415
416     ConfigSetDefaultFloat(l_CoreEventsConfig, "Version", CONFIG_PARAM_VERSION,  "Mupen64Plus CoreEvents config parameter set version number.  Please don't change this version number.");
417     /* Keyboard presses mapped to core functions */
418     ConfigSetDefaultInt(l_CoreEventsConfig, kbdStop, SDL_SCANCODE_ESCAPE,          "SDL keysym for stopping the emulator");
419     ConfigSetDefaultInt(l_CoreEventsConfig, kbdFullscreen, SDL_NUM_SCANCODES,      "SDL keysym for switching between fullscreen/windowed modes");
420     ConfigSetDefaultInt(l_CoreEventsConfig, kbdSave, SDL_SCANCODE_F5,              "SDL keysym for saving the emulator state");
421     ConfigSetDefaultInt(l_CoreEventsConfig, kbdLoad, SDL_SCANCODE_F7,              "SDL keysym for loading the emulator state");
422     ConfigSetDefaultInt(l_CoreEventsConfig, kbdIncrement, 0,                       "SDL keysym for advancing the save state slot");
423     ConfigSetDefaultInt(l_CoreEventsConfig, kbdReset, SDL_SCANCODE_F9,             "SDL keysym for resetting the emulator");
424     ConfigSetDefaultInt(l_CoreEventsConfig, kbdSpeeddown, SDL_SCANCODE_F10,        "SDL keysym for slowing down the emulator");
425     ConfigSetDefaultInt(l_CoreEventsConfig, kbdSpeedup, SDL_SCANCODE_F11,          "SDL keysym for speeding up the emulator");
426     ConfigSetDefaultInt(l_CoreEventsConfig, kbdScreenshot, SDL_SCANCODE_F12,       "SDL keysym for taking a screenshot");
427     ConfigSetDefaultInt(l_CoreEventsConfig, kbdPause, SDL_SCANCODE_P,              "SDL keysym for pausing the emulator");
428     ConfigSetDefaultInt(l_CoreEventsConfig, kbdMute, SDL_SCANCODE_M,               "SDL keysym for muting/unmuting the sound");
429     ConfigSetDefaultInt(l_CoreEventsConfig, kbdIncrease, SDL_SCANCODE_RIGHTBRACKET,"SDL keysym for increasing the volume");
430     ConfigSetDefaultInt(l_CoreEventsConfig, kbdDecrease, SDL_SCANCODE_LEFTBRACKET, "SDL keysym for decreasing the volume");
431     ConfigSetDefaultInt(l_CoreEventsConfig, kbdForward, SDL_SCANCODE_F,            "SDL keysym for temporarily going really fast");
432     ConfigSetDefaultInt(l_CoreEventsConfig, kbdAdvance, SDL_SCANCODE_SLASH,        "SDL keysym for advancing by one frame when paused");
433     ConfigSetDefaultInt(l_CoreEventsConfig, kbdGameshark, SDL_SCANCODE_G,          "SDL keysym for pressing the game shark button");
434     /* Joystick events mapped to core functions */
435     ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyStop], "",       "Joystick event string for stopping the emulator");
436     ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyFullscreen], "", "Joystick event string for switching between fullscreen/windowed modes");
437     ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joySave], "",       "Joystick event string for saving the emulator state");
438     ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyLoad], "",       "Joystick event string for loading the emulator state");
439     ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyIncrement], "",  "Joystick event string for advancing the save state slot");
440     ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyScreenshot], "", "Joystick event string for taking a screenshot");
441     ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyPause], "",      "Joystick event string for pausing the emulator");
442     ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyMute], "",       "Joystick event string for muting/unmuting the sound");
443     ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyIncrease], "",   "Joystick event string for increasing the volume");
444     ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyDecrease], "",   "Joystick event string for decreasing the volume");
445     ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyForward], "",    "Joystick event string for fast-forward");
446     ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyGameshark], "",  "Joystick event string for pressing the game shark button");
447
448     if (bSaveConfig)
449         ConfigSaveSection("CoreEvents");
450
451     return 1;
452 }
453
454 static int get_saveslot_from_keysym(int keysym)
455 {
456     switch (keysym) {
457     case SDL_SCANCODE_0:
458         return 0;
459     case SDL_SCANCODE_1:
460         return 1;
461     case SDL_SCANCODE_2:
462         return 2;
463     case SDL_SCANCODE_3:
464         return 3;
465     case SDL_SCANCODE_4:
466         return 4;
467     case SDL_SCANCODE_5:
468         return 5;
469     case SDL_SCANCODE_6:
470         return 6;
471     case SDL_SCANCODE_7:
472         return 7;
473     case SDL_SCANCODE_8:
474         return 8;
475     case SDL_SCANCODE_9:
476         return 9;
477     default:
478         return -1;
479     }
480 }
481
482 /*********************************************************************************************************
483 * sdl keyup/keydown handlers
484 */
485
486 void event_sdl_keydown(int keysym, int keymod)
487 {
488     int slot;
489
490     /* check for the only 2 hard-coded key commands: Alt-enter for fullscreen and 0-9 for save state slot */
491     if (keysym == SDL_SCANCODE_RETURN && keymod & (KMOD_LALT | KMOD_RALT))
492         gfx.changeWindow();
493     else if ((slot = get_saveslot_from_keysym(keysym)) >= 0)
494         main_state_set_slot(slot);
495     /* check all of the configurable commands */
496     else if (keysym == ConfigGetParamInt(l_CoreEventsConfig, kbdStop))
497         main_stop();
498     else if (keysym == ConfigGetParamInt(l_CoreEventsConfig, kbdFullscreen))
499         gfx.changeWindow();
500     else if (keysym == ConfigGetParamInt(l_CoreEventsConfig, kbdSave))
501         main_state_save(0, NULL); /* save in mupen64plus format using current slot */
502     else if (keysym == ConfigGetParamInt(l_CoreEventsConfig, kbdLoad))
503         main_state_load(NULL); /* load using current slot */
504     else if (keysym == ConfigGetParamInt(l_CoreEventsConfig, kbdIncrement))
505         main_state_inc_slot();
506     else if (keysym == ConfigGetParamInt(l_CoreEventsConfig, kbdReset))
507         reset_soft();
508     else if (keysym == ConfigGetParamInt(l_CoreEventsConfig, kbdSpeeddown))
509         main_speeddown(5);
510     else if (keysym == ConfigGetParamInt(l_CoreEventsConfig, kbdSpeedup))
511         main_speedup(5);
512     else if (keysym == ConfigGetParamInt(l_CoreEventsConfig, kbdScreenshot))
513         main_take_next_screenshot();    /* screenshot will be taken at the end of frame rendering */
514     else if (keysym == ConfigGetParamInt(l_CoreEventsConfig, kbdPause))
515         main_toggle_pause();
516     else if (keysym == ConfigGetParamInt(l_CoreEventsConfig, kbdMute))
517         main_volume_mute();
518     else if (keysym == ConfigGetParamInt(l_CoreEventsConfig, kbdIncrease))
519         main_volume_up();
520     else if (keysym == ConfigGetParamInt(l_CoreEventsConfig, kbdDecrease))
521         main_volume_down();
522     else if (keysym == ConfigGetParamInt(l_CoreEventsConfig, kbdForward))
523         main_set_fastforward(1);
524     else if (keysym == ConfigGetParamInt(l_CoreEventsConfig, kbdAdvance))
525         main_advance_one();
526     else if (keysym == ConfigGetParamInt(l_CoreEventsConfig, kbdGameshark))
527         event_set_gameshark(1);
528     else
529     {
530         /* pass all other keypresses to the input plugin */
531         input.keyDown(keymod, keysym);
532     }
533
534 }
535
536 void event_sdl_keyup(int keysym, int keymod)
537 {
538     if (keysym == ConfigGetParamInt(l_CoreEventsConfig, kbdStop))
539     {
540         return;
541     }
542     else if (keysym == ConfigGetParamInt(l_CoreEventsConfig, kbdForward))
543     {
544         main_set_fastforward(0);
545     }
546     else if (keysym == ConfigGetParamInt(l_CoreEventsConfig, kbdGameshark))
547     {
548         event_set_gameshark(0);
549     }
550     else input.keyUp(keymod, keysym);
551
552 }
553
554 int event_gameshark_active(void)
555 {
556     return GamesharkActive;
557 }
558
559 void event_set_gameshark(int active)
560 {
561     // if boolean value doesn't change then just return
562     if (!active == !GamesharkActive)
563         return;
564
565     // set the button state
566     GamesharkActive = (active ? 1 : 0);
567
568     // notify front-end application that gameshark button state has changed
569     StateChanged(M64CORE_INPUT_GAMESHARK, GamesharkActive);
570 }
571