Added missing launcher
[mupen64plus-pandora.git] / source / mupen64plus-input-sdl / src / plugin.c
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  *   Mupen64plus-input-sdl - plugin.c                                      *
3  *   Mupen64Plus homepage: http://code.google.com/p/mupen64plus/           *
4  *   Copyright (C) 2008-2011 Richard Goedeken                              *
5  *   Copyright (C) 2008 Tillin9                                            *
6  *   Copyright (C) 2002 Blight                                             *
7  *                                                                         *
8  *   This program is free software; you can redistribute it and/or modify  *
9  *   it under the terms of the GNU General Public License as published by  *
10  *   the Free Software Foundation; either version 2 of the License, or     *
11  *   (at your option) any later version.                                   *
12  *                                                                         *
13  *   This program is distributed in the hope that it will be useful,       *
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
16  *   GNU General Public License for more details.                          *
17  *                                                                         *
18  *   You should have received a copy of the GNU General Public License     *
19  *   along with this program; if not, write to the                         *
20  *   Free Software Foundation, Inc.,                                       *
21  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
22  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include <SDL.h>
29
30 #define M64P_PLUGIN_PROTOTYPES 1
31 #include "m64p_types.h"
32 #include "m64p_plugin.h"
33 #include "m64p_common.h"
34 #include "m64p_config.h"
35
36 #include "plugin.h"
37 #include "config.h"
38 #include "version.h"
39 #include "osal_dynamiclib.h"
40
41 #ifdef __linux__
42 #include <unistd.h>
43 #include <dirent.h>
44 #include <fcntl.h>
45 #include <sys/types.h>
46 #include <linux/input.h>
47 #endif /* __linux__ */
48
49 #include <errno.h>
50
51 /* defines for the force feedback rumble support */
52 #ifdef __linux__
53 #define BITS_PER_LONG (sizeof(long) * 8)
54 #define OFF(x)  ((x)%BITS_PER_LONG)
55 #define BIT(x)  (1UL<<OFF(x))
56 #define LONG(x) ((x)/BITS_PER_LONG)
57 #define test_bit(bit, array)    ((array[LONG(bit)] >> OFF(bit)) & 1)
58 #endif //__linux__
59
60 /* definitions of pointers to Core config functions */
61 ptr_ConfigOpenSection      ConfigOpenSection = NULL;
62 ptr_ConfigDeleteSection    ConfigDeleteSection = NULL;
63 ptr_ConfigSaveSection      ConfigSaveSection = NULL;
64 ptr_ConfigListParameters   ConfigListParameters = NULL;
65 ptr_ConfigSaveFile         ConfigSaveFile = NULL;
66 ptr_ConfigSetParameter     ConfigSetParameter = NULL;
67 ptr_ConfigGetParameter     ConfigGetParameter = NULL;
68 ptr_ConfigGetParameterHelp ConfigGetParameterHelp = NULL;
69 ptr_ConfigSetDefaultInt    ConfigSetDefaultInt = NULL;
70 ptr_ConfigSetDefaultFloat  ConfigSetDefaultFloat = NULL;
71 ptr_ConfigSetDefaultBool   ConfigSetDefaultBool = NULL;
72 ptr_ConfigSetDefaultString ConfigSetDefaultString = NULL;
73 ptr_ConfigGetParamInt      ConfigGetParamInt = NULL;
74 ptr_ConfigGetParamFloat    ConfigGetParamFloat = NULL;
75 ptr_ConfigGetParamBool     ConfigGetParamBool = NULL;
76 ptr_ConfigGetParamString   ConfigGetParamString = NULL;
77
78 ptr_ConfigGetSharedDataFilepath ConfigGetSharedDataFilepath = NULL;
79 ptr_ConfigGetUserConfigPath     ConfigGetUserConfigPath = NULL;
80 ptr_ConfigGetUserDataPath       ConfigGetUserDataPath = NULL;
81 ptr_ConfigGetUserCachePath      ConfigGetUserCachePath = NULL;
82
83 /* global data definitions */
84 SController controller[4];   // 4 controllers
85
86 /* static data definitions */
87 static void (*l_DebugCallback)(void *, int, const char *) = NULL;
88 static void *l_DebugCallContext = NULL;
89 static int l_PluginInit = 0;
90
91 static unsigned short button_bits[] = {
92     0x0001,  // R_DPAD
93     0x0002,  // L_DPAD
94     0x0004,  // D_DPAD
95     0x0008,  // U_DPAD
96     0x0010,  // START_BUTTON
97     0x0020,  // Z_TRIG
98     0x0040,  // B_BUTTON
99     0x0080,  // A_BUTTON
100     0x0100,  // R_CBUTTON
101     0x0200,  // L_CBUTTON
102     0x0400,  // D_CBUTTON
103     0x0800,  // U_CBUTTON
104     0x1000,  // R_TRIG
105     0x2000,  // L_TRIG
106     0x4000,  // Mempak switch
107     0x8000,  // Rumblepak switch
108     0x0100,  // R_CBUTTON alternate
109     0x0200,  // L_CBUTTON alternate
110     0x0400,  // D_CBUTTON alternate
111     0x0800   // U_CBUTTON alternate
112 };
113
114 static int romopen = 0;         // is a rom opened
115
116 static unsigned char myKeyState[SDL_NUM_SCANCODES];
117
118 #ifdef __linux__
119 static struct ff_effect ffeffect[4];
120 static struct ff_effect ffstrong[4];
121 static struct ff_effect ffweak[4];
122 #endif //__linux__
123
124 /* Global functions */
125 void DebugMessage(int level, const char *message, ...)
126 {
127   char msgbuf[1024];
128   va_list args;
129
130   if (l_DebugCallback == NULL)
131       return;
132
133   va_start(args, message);
134   vsprintf(msgbuf, message, args);
135
136   (*l_DebugCallback)(l_DebugCallContext, level, msgbuf);
137
138   va_end(args);
139 }
140
141 static CONTROL temp_core_controlinfo[4];
142
143 /* Mupen64Plus plugin functions */
144 EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context,
145                                    void (*DebugCallback)(void *, int, const char *))
146 {
147     ptr_CoreGetAPIVersions CoreAPIVersionFunc;
148     
149     int i, ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion;
150
151     if (l_PluginInit)
152         return M64ERR_ALREADY_INIT;
153
154     /* first thing is to set the callback function for debug info */
155     l_DebugCallback = DebugCallback;
156     l_DebugCallContext = Context;
157
158     /* attach and call the CoreGetAPIVersions function, check Config API version for compatibility */
159     CoreAPIVersionFunc = (ptr_CoreGetAPIVersions) osal_dynlib_getproc(CoreLibHandle, "CoreGetAPIVersions");
160     if (CoreAPIVersionFunc == NULL)
161     {
162         DebugMessage(M64MSG_ERROR, "Core emulator broken; no CoreAPIVersionFunc() function found.");
163         return M64ERR_INCOMPATIBLE;
164     }
165     
166     (*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL);
167     if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000) || ConfigAPIVersion < CONFIG_API_VERSION)
168     {
169         DebugMessage(M64MSG_ERROR, "Emulator core Config API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)",
170                 VERSION_PRINTF_SPLIT(ConfigAPIVersion), VERSION_PRINTF_SPLIT(CONFIG_API_VERSION));
171         return M64ERR_INCOMPATIBLE;
172     }
173
174     /* Get the core config function pointers from the library handle */
175     ConfigOpenSection = (ptr_ConfigOpenSection) osal_dynlib_getproc(CoreLibHandle, "ConfigOpenSection");
176     ConfigDeleteSection = (ptr_ConfigDeleteSection) osal_dynlib_getproc(CoreLibHandle, "ConfigDeleteSection");
177     ConfigSaveFile = (ptr_ConfigSaveFile) osal_dynlib_getproc(CoreLibHandle, "ConfigSaveFile");
178     ConfigSaveSection = (ptr_ConfigSaveSection) osal_dynlib_getproc(CoreLibHandle, "ConfigSaveSection");
179     ConfigListParameters = (ptr_ConfigListParameters) osal_dynlib_getproc(CoreLibHandle, "ConfigListParameters");
180     ConfigSetParameter = (ptr_ConfigSetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigSetParameter");
181     ConfigGetParameter = (ptr_ConfigGetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParameter");
182     ConfigSetDefaultInt = (ptr_ConfigSetDefaultInt) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultInt");
183     ConfigSetDefaultFloat = (ptr_ConfigSetDefaultFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultFloat");
184     ConfigSetDefaultBool = (ptr_ConfigSetDefaultBool) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultBool");
185     ConfigSetDefaultString = (ptr_ConfigSetDefaultString) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultString");
186     ConfigGetParamInt = (ptr_ConfigGetParamInt) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamInt");
187     ConfigGetParamFloat = (ptr_ConfigGetParamFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamFloat");
188     ConfigGetParamBool = (ptr_ConfigGetParamBool) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamBool");
189     ConfigGetParamString = (ptr_ConfigGetParamString) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamString");
190
191     ConfigGetSharedDataFilepath = (ptr_ConfigGetSharedDataFilepath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetSharedDataFilepath");
192     ConfigGetUserConfigPath = (ptr_ConfigGetUserConfigPath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserConfigPath");
193     ConfigGetUserDataPath = (ptr_ConfigGetUserDataPath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserDataPath");
194     ConfigGetUserCachePath = (ptr_ConfigGetUserCachePath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserCachePath");
195
196     if (!ConfigOpenSection || !ConfigDeleteSection || !ConfigSaveFile || !ConfigSaveSection || !ConfigSetParameter || !ConfigGetParameter ||
197         !ConfigSetDefaultInt || !ConfigSetDefaultFloat || !ConfigSetDefaultBool || !ConfigSetDefaultString ||
198         !ConfigGetParamInt   || !ConfigGetParamFloat   || !ConfigGetParamBool   || !ConfigGetParamString ||
199         !ConfigGetSharedDataFilepath || !ConfigGetUserConfigPath || !ConfigGetUserDataPath || !ConfigGetUserCachePath)
200     {
201         DebugMessage(M64MSG_ERROR, "Couldn't connect to Core configuration functions");
202         return M64ERR_INCOMPATIBLE;
203     }
204
205     /* reset controllers */
206     memset(controller, 0, sizeof(SController) * 4);
207     for (i = 0; i < SDL_NUM_SCANCODES; i++)
208     {
209         myKeyState[i] = 0;
210     }
211     /* set CONTROL struct pointers to the temporary static array */
212     /* this small struct is used to tell the core whether each controller is plugged in, and what type of pak is connected */
213     /* we only need it so that we can call load_configuration below, to auto-config for a GUI front-end */
214     for (i = 0; i < 4; i++)
215         controller[i].control = temp_core_controlinfo + i;
216
217     /* read plugin config from core config database, auto-config if necessary and update core database */
218     load_configuration(1);
219
220     l_PluginInit = 1;
221     return M64ERR_SUCCESS;
222 }
223
224 EXPORT m64p_error CALL PluginShutdown(void)
225 {
226     if (!l_PluginInit)
227         return M64ERR_NOT_INIT;
228
229     /* reset some local variables */
230     l_DebugCallback = NULL;
231     l_DebugCallContext = NULL;
232
233     l_PluginInit = 0;
234     return M64ERR_SUCCESS;
235 }
236
237 EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)
238 {
239     /* set version info */
240     if (PluginType != NULL)
241         *PluginType = M64PLUGIN_INPUT;
242
243     if (PluginVersion != NULL)
244         *PluginVersion = PLUGIN_VERSION;
245
246     if (APIVersion != NULL)
247         *APIVersion = INPUT_PLUGIN_API_VERSION;
248     
249     if (PluginNamePtr != NULL)
250         *PluginNamePtr = PLUGIN_NAME;
251
252     if (Capabilities != NULL)
253     {
254         *Capabilities = 0;
255     }
256                     
257     return M64ERR_SUCCESS;
258 }
259
260 /* Helper function to handle the SDL keys */
261 static void
262 doSdlKeys(unsigned char* keystate)
263 {
264     int c, b, axis_val, axis_max_val;
265     static int grabmouse = 1, grabtoggled = 0;
266
267     axis_max_val = 80;
268 /*    if (keystate[SDL_SCANCODE_RCTRL])
269         axis_max_val -= 40;
270     if (keystate[SDL_SCANCODE_RSHIFT])
271         axis_max_val -= 20;*/
272
273     for( c = 0; c < 4; c++ )
274     {
275         for( b = 0; b < 16; b++ )
276         {
277             if( controller[c].button[b].key == SDL_SCANCODE_UNKNOWN || ((int) controller[c].button[b].key) < 0)
278                 continue;
279             if( keystate[controller[c].button[b].key] )
280                 controller[c].buttons.Value |= button_bits[b];
281         }
282         for( b = 0; b < 2; b++ )
283         {
284             // from the N64 func ref: The 3D Stick data is of type signed char and in
285             // the range between 80 and -80. (32768 / 409 = ~80.1)
286             if( b == 0 )
287                 axis_val = controller[c].buttons.X_AXIS;
288             else
289                 axis_val = -controller[c].buttons.Y_AXIS;
290
291             if( controller[c].axis[b].key_a != SDL_SCANCODE_UNKNOWN && ((int) controller[c].axis[b].key_a) > 0)
292                 if( keystate[controller[c].axis[b].key_a] )
293                     axis_val = -axis_max_val;
294             if( controller[c].axis[b].key_b != SDL_SCANCODE_UNKNOWN && ((int) controller[c].axis[b].key_b) > 0)
295                 if( keystate[controller[c].axis[b].key_b] )
296                     axis_val = axis_max_val;
297
298             if( b == 0 )
299                 controller[c].buttons.X_AXIS = axis_val;
300             else
301                 controller[c].buttons.Y_AXIS = -axis_val;
302         }
303         if (controller[c].mouse)
304         {
305         /*    if (keystate[SDL_SCANCODE_LCTRL] && keystate[SDL_SCANCODE_LALT])
306             {
307                 if (!grabtoggled)
308                 {
309                     grabtoggled = 1;
310                     grabmouse = !grabmouse;
311                     // grab/ungrab mouse
312 #if SDL_VERSION_ATLEAST(2,0,0)
313 #warning SDL mouse grabbing not yet supported with SDL 2.0
314 #else
315                     SDL_WM_GrabInput( grabmouse ? SDL_GRAB_ON : SDL_GRAB_OFF );
316 #endif
317                     SDL_ShowCursor( grabmouse ? 0 : 1 );
318                 }
319             }
320             else grabtoggled = 0;
321                 */
322         }
323     }
324 }
325
326 static unsigned char DataCRC( unsigned char *Data, int iLenght )
327 {
328     unsigned char Remainder = Data[0];
329
330     int iByte = 1;
331     unsigned char bBit = 0;
332
333     while( iByte <= iLenght )
334     {
335         int HighBit = ((Remainder & 0x80) != 0);
336         Remainder = Remainder << 1;
337
338         Remainder += ( iByte < iLenght && Data[iByte] & (0x80 >> bBit )) ? 1 : 0;
339
340         Remainder ^= (HighBit) ? 0x85 : 0;
341
342         bBit++;
343         iByte += bBit/8;
344         bBit %= 8;
345     }
346
347     return Remainder;
348 }
349
350 /******************************************************************
351   Function: ControllerCommand
352   Purpose:  To process the raw data that has just been sent to a
353             specific controller.
354   input:    - Controller Number (0 to 3) and -1 signalling end of
355               processing the pif ram.
356             - Pointer of data to be processed.
357   output:   none
358
359   note:     This function is only needed if the DLL is allowing raw
360             data, or the plugin is set to raw
361
362             the data that is being processed looks like this:
363             initilize controller: 01 03 00 FF FF FF
364             read controller:      01 04 01 FF FF FF FF
365 *******************************************************************/
366 EXPORT void CALL ControllerCommand(int Control, unsigned char *Command)
367 {
368     unsigned char *Data = &Command[5];
369
370     if (Control == -1)
371         return;
372
373     switch (Command[2])
374     {
375         case RD_GETSTATUS:
376 #ifdef _DEBUG
377             DebugMessage(M64MSG_INFO, "Get status");
378 #endif
379             break;
380         case RD_READKEYS:
381 #ifdef _DEBUG
382             DebugMessage(M64MSG_INFO, "Read keys");
383 #endif
384             break;
385         case RD_READPAK:
386 #ifdef _DEBUG
387             DebugMessage(M64MSG_INFO, "Read pak");
388 #endif
389             if (controller[Control].control->Plugin == PLUGIN_RAW)
390             {
391                 unsigned int dwAddress = (Command[3] << 8) + (Command[4] & 0xE0);
392
393                 if(( dwAddress >= 0x8000 ) && ( dwAddress < 0x9000 ) )
394                     memset( Data, 0x80, 32 );
395                 else
396                     memset( Data, 0x00, 32 );
397
398                 Data[32] = DataCRC( Data, 32 );
399             }
400             break;
401         case RD_WRITEPAK:
402 #ifdef _DEBUG
403             DebugMessage(M64MSG_INFO, "Write pak");
404 #endif
405             if (controller[Control].control->Plugin == PLUGIN_RAW)
406             {
407                 unsigned int dwAddress = (Command[3] << 8) + (Command[4] & 0xE0);
408               if (dwAddress == PAK_IO_RUMBLE && *Data)
409                     DebugMessage(M64MSG_VERBOSE, "Triggering rumble pack.");
410 #ifdef __linux__
411                 struct input_event play;
412                 if( dwAddress == PAK_IO_RUMBLE && controller[Control].event_joystick != 0)
413                 {
414                     if( *Data )
415                     {
416                         play.type = EV_FF;
417                         play.code = ffeffect[Control].id;
418                         play.value = 1;
419
420                         if (write(controller[Control].event_joystick, (const void*) &play, sizeof(play)) == -1)
421                             perror("Error starting rumble effect");
422
423                     }
424                     else
425                     {
426                         play.type = EV_FF;
427                         play.code = ffeffect[Control].id;
428                         play.value = 0;
429
430                         if (write(controller[Control].event_joystick, (const void*) &play, sizeof(play)) == -1)
431                             perror("Error stopping rumble effect");
432                     }
433                 }
434 #endif //__linux__
435                 Data[32] = DataCRC( Data, 32 );
436             }
437             break;
438         case RD_RESETCONTROLLER:
439 #ifdef _DEBUG
440             DebugMessage(M64MSG_INFO, "Reset controller");
441 #endif
442             break;
443         case RD_READEEPROM:
444 #ifdef _DEBUG
445             DebugMessage(M64MSG_INFO, "Read eeprom");
446 #endif
447             break;
448         case RD_WRITEEPROM:
449 #ifdef _DEBUG
450             DebugMessage(M64MSG_INFO, "Write eeprom");
451 #endif
452             break;
453         }
454 }
455
456 /******************************************************************
457   Function: GetKeys
458   Purpose:  To get the current state of the controllers buttons.
459   input:    - Controller Number (0 to 3)
460             - A pointer to a BUTTONS structure to be filled with
461             the controller state.
462   output:   none
463 *******************************************************************/
464 EXPORT void CALL GetKeys( int Control, BUTTONS *Keys )
465 {
466     static int mousex_residual = 0;
467     static int mousey_residual = 0;
468     int b, axis_val;
469     SDL_Event event;
470     unsigned char mstate;
471
472     // Handle keyboard input first
473     doSdlKeys(SDL_GetKeyboardState(NULL));
474     doSdlKeys(myKeyState);
475
476     // read joystick state
477     SDL_JoystickUpdate();
478
479     if( controller[Control].device >= 0 )
480     {
481         for( b = 0; b < NUM_BUTTONS; b++ )
482         {
483             if( controller[Control].button[b].button >= 0 )
484                 if( SDL_JoystickGetButton( controller[Control].joystick, controller[Control].button[b].button ) )
485                     controller[Control].buttons.Value |= button_bits[b];
486
487             if( controller[Control].button[b].axis >= 0 )
488             {
489                 int deadzone = controller[Control].button[b].axis_deadzone;
490                 axis_val = SDL_JoystickGetAxis( controller[Control].joystick, controller[Control].button[b].axis );
491                 if (deadzone < 0)
492                     deadzone = 6000; /* default */
493                 if( (controller[Control].button[b].axis_dir < 0) && (axis_val <= -deadzone) )
494                     controller[Control].buttons.Value |= button_bits[b];
495                 else if( (controller[Control].button[b].axis_dir > 0) && (axis_val >= deadzone) )
496                     controller[Control].buttons.Value |= button_bits[b];
497             }
498
499             if( controller[Control].button[b].hat >= 0 )
500             {
501                 if( controller[Control].button[b].hat_pos > 0 )
502                     if( SDL_JoystickGetHat( controller[Control].joystick, controller[Control].button[b].hat ) & controller[Control].button[b].hat_pos )
503                         controller[Control].buttons.Value |= button_bits[b];
504             }
505         }
506         for( b = 0; b < 2; b++ )
507         {
508             /* from the N64 func ref: The 3D Stick data is of type signed char and in the range between -80 and +80 */
509             int deadzone = controller[Control].axis_deadzone[b];
510             int range = controller[Control].axis_peak[b] - controller[Control].axis_deadzone[b];
511             /* skip this axis if the deadzone/peak values are invalid */
512             if (deadzone < 0 || range < 1)
513                 continue;
514
515             if( b == 0 )
516                 axis_val = controller[Control].buttons.X_AXIS;
517             else
518                 axis_val = -controller[Control].buttons.Y_AXIS;
519
520             if( controller[Control].axis[b].axis_a >= 0 )  /* up and left for N64 */
521             {
522                 int joy_val = SDL_JoystickGetAxis(controller[Control].joystick, controller[Control].axis[b].axis_a);
523                 int axis_dir = controller[Control].axis[b].axis_dir_a;
524                 if (joy_val * axis_dir > deadzone)
525                     axis_val = -((abs(joy_val) - deadzone) * 80 / range);
526                 if (axis_val < -80)
527                     axis_val = -80;
528             }
529             if( controller[Control].axis[b].axis_b >= 0 ) /* down and right for N64 */
530             {
531                 int joy_val = SDL_JoystickGetAxis(controller[Control].joystick, controller[Control].axis[b].axis_b);
532                 int axis_dir = controller[Control].axis[b].axis_dir_b;
533                 if (joy_val * axis_dir > deadzone)
534                     axis_val = ((abs(joy_val) - deadzone) * 80 / range);
535                 if (axis_val > 80)
536                     axis_val = 80;
537             }
538             if( controller[Control].axis[b].hat >= 0 )
539             {
540                 if( controller[Control].axis[b].hat_pos_a >= 0 )
541                     if( SDL_JoystickGetHat( controller[Control].joystick, controller[Control].axis[b].hat ) & controller[Control].axis[b].hat_pos_a )
542                         axis_val = -80;
543                 if( controller[Control].axis[b].hat_pos_b >= 0 )
544                     if( SDL_JoystickGetHat( controller[Control].joystick, controller[Control].axis[b].hat ) & controller[Control].axis[b].hat_pos_b )
545                         axis_val = 80;
546             }
547
548             if( controller[Control].axis[b].button_a >= 0 )
549                 if( SDL_JoystickGetButton( controller[Control].joystick, controller[Control].axis[b].button_a ) )
550                     axis_val = -80;
551             if( controller[Control].axis[b].button_b >= 0 )
552                 if( SDL_JoystickGetButton( controller[Control].joystick, controller[Control].axis[b].button_b ) )
553                     axis_val = 80;
554
555             if( b == 0 )
556                 controller[Control].buttons.X_AXIS = axis_val;
557             else
558                 controller[Control].buttons.Y_AXIS = -axis_val;
559         }
560     }
561
562     // process mouse events
563     mstate = SDL_GetMouseState( NULL, NULL );
564     for( b = 0; b < NUM_BUTTONS; b++ )
565     {
566         if( controller[Control].button[b].mouse < 1 )
567             continue;
568         if( mstate & SDL_BUTTON(controller[Control].button[b].mouse) )
569             controller[Control].buttons.Value |= button_bits[b];
570     }
571
572     if ((controller[Control].mouse)
573            || ((controller[Control].mouse_up) || (controller[Control].mouse_down) || (controller[Control].mouse_left) || (controller[Control].mouse_right) ))
574     {
575 #if SDL_VERSION_ATLEAST(2,0,0)
576 #warning SDL mouse grabbing not yet supported with SDL 2.0
577 #else
578         if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON)
579         {
580             SDL_PumpEvents();
581 #if SDL_VERSION_ATLEAST(1,3,0)
582             while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION) == 1)
583 #else
584             while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_EVENTMASK(SDL_MOUSEMOTION)) == 1)
585 #endif
586             {
587                 if (event.motion.xrel)
588                 {
589                     mousex_residual += (int) (event.motion.xrel * controller[Control].mouse_sens[0]);
590                 }
591                 if (event.motion.yrel)
592                 {
593                     mousey_residual += (int) (event.motion.yrel * controller[Control].mouse_sens[1]);
594                 }
595             }
596         }
597         else
598 #endif
599         {
600             mousex_residual = 0;
601             mousey_residual = 0;
602         }
603         axis_val = mousex_residual;
604         if (axis_val < -80)
605             axis_val = -80;
606         else if (axis_val > 80)
607             axis_val = 80;
608                 if (controller[Control].mouse)
609                         controller[Control].buttons.X_AXIS = axis_val;
610                 else {
611                         for( b = 0; b < NUM_BUTTONS; b++ ) {
612                                 if( controller[Control].button[b].mouse_left > 0 )
613                     if (controller[Control].mouse_left) controller[Control].buttons.Value |= (axis_val<-40)?button_bits[b]:0;
614                                 if( controller[Control].button[b].mouse_right > 0 )
615                     if (controller[Control].mouse_right) controller[Control].buttons.Value |= (axis_val>40)?button_bits[b]:0;
616                         }
617                 }
618         axis_val = mousey_residual;
619         if (axis_val < -80)
620             axis_val = -80;
621         else if (axis_val > 80)
622             axis_val = 80;
623                 if (controller[Control].mouse)
624                         controller[Control].buttons.Y_AXIS = -axis_val;
625                 else {
626                         for( b = 0; b < NUM_BUTTONS; b++ ) {
627                                 if( controller[Control].button[b].mouse_up > 0 )
628                     if (controller[Control].mouse_up) controller[Control].buttons.Value |= (axis_val<-40)?button_bits[b]:0;
629                                 if( controller[Control].button[b].mouse_down > 0 )
630                     if (controller[Control].mouse_down) controller[Control].buttons.Value |= (axis_val>40)?button_bits[b]:0;
631                         }
632                 }
633         /* the mouse x/y values decay exponentially */
634         mousex_residual = (mousex_residual * 224) / 256;
635         mousey_residual = (mousey_residual * 224) / 256;
636     }
637
638 #ifdef _DEBUG
639     DebugMessage(M64MSG_VERBOSE, "Controller #%d value: 0x%8.8X", Control, *(int *)&controller[Control].buttons );
640 #endif
641     *Keys = controller[Control].buttons;
642
643     /* handle mempack / rumblepak switching (only if rumble is active on joystick) */
644 #ifdef __linux__
645     if (controller[Control].event_joystick != 0)
646     {
647         struct input_event play;
648         static unsigned int SwitchPackTime[4] = {0, 0, 0, 0}, SwitchPackType[4] = {0, 0, 0, 0};
649         // when the user switches packs, we should mimick the act of removing 1 pack, and then inserting another 1 second later
650         if (controller[Control].buttons.Value & button_bits[14])
651         {
652             SwitchPackTime[Control] = SDL_GetTicks();         // time at which the 'switch pack' command was given
653             SwitchPackType[Control] = PLUGIN_MEMPAK;          // type of new pack to insert
654             controller[Control].control->Plugin = PLUGIN_NONE;// remove old pack
655             play.type = EV_FF;
656             play.code = ffweak[Control].id;
657             play.value = 1;
658             if (write(controller[Control].event_joystick, (const void*) &play, sizeof(play)) == -1)
659                 perror("Error starting rumble effect");
660         }
661         if (controller[Control].buttons.Value & button_bits[15])
662         {
663             SwitchPackTime[Control] = SDL_GetTicks();         // time at which the 'switch pack' command was given
664             SwitchPackType[Control] = PLUGIN_RAW;             // type of new pack to insert
665             controller[Control].control->Plugin = PLUGIN_NONE;// remove old pack
666             play.type = EV_FF;
667             play.code = ffstrong[Control].id;
668             play.value = 1;
669             if (write(controller[Control].event_joystick, (const void*) &play, sizeof(play)) == -1)
670                 perror("Error starting rumble effect");
671         }
672         // handle inserting new pack if the time has arrived
673         if (SwitchPackTime[Control] != 0 && (SDL_GetTicks() - SwitchPackTime[Control]) >= 1000)
674         {
675             controller[Control].control->Plugin = SwitchPackType[Control];
676             SwitchPackTime[Control] = 0;
677         }
678     }
679 #endif /* __linux__ */
680
681     controller[Control].buttons.Value = 0;
682 }
683
684 static void InitiateRumble(int cntrl)
685 {
686 #ifdef __linux__
687     DIR* dp;
688     struct dirent* ep;
689     unsigned long features[4];
690     char temp[128];
691     char temp2[128];
692     int iFound = 0;
693
694     controller[cntrl].event_joystick = 0;
695
696     sprintf(temp,"/sys/class/input/js%d/device", controller[cntrl].device);
697     dp = opendir(temp);
698
699     if(dp==NULL)
700         return;
701
702     while ((ep=readdir(dp)))
703         {
704         if (strncmp(ep->d_name, "event",5)==0)
705             {
706             sprintf(temp, "/dev/input/%s", ep->d_name);
707             iFound = 1;
708             break;
709             }
710         else if(strncmp(ep->d_name,"input:event", 11)==0)
711             {
712             sscanf(ep->d_name, "input:%s", temp2);
713             sprintf(temp, "/dev/input/%s", temp2);
714             iFound = 1;
715             break;
716             }
717         else if(strncmp(ep->d_name,"input:input", 11)==0)
718             {
719             strcat(temp, "/");
720             strcat(temp, ep->d_name);
721             closedir (dp);
722             dp = opendir(temp);
723             if(dp==NULL)
724                 return;
725             }
726        }
727
728     closedir(dp);
729
730     if (!iFound)
731     {
732         DebugMessage(M64MSG_WARNING, "Couldn't find input event for rumble support.");
733         return;
734     }
735
736     controller[cntrl].event_joystick = open(temp, O_RDWR);
737     if(controller[cntrl].event_joystick==-1)
738         {
739         DebugMessage(M64MSG_WARNING, "Couldn't open device file '%s' for rumble support.", temp);
740         controller[cntrl].event_joystick = 0;
741         return;
742         }
743
744     if(ioctl(controller[cntrl].event_joystick, EVIOCGBIT(EV_FF, sizeof(unsigned long) * 4), features)==-1)
745         {
746         DebugMessage(M64MSG_WARNING, "Linux kernel communication failed for force feedback (rumble).\n");
747         controller[cntrl].event_joystick = 0;
748         return;
749         }
750
751     if(!test_bit(FF_RUMBLE, features))
752         {
753         DebugMessage(M64MSG_WARNING, "No rumble supported on N64 joystick #%i", cntrl + 1);
754         controller[cntrl].event_joystick = 0;
755         return;
756         }
757
758     ffeffect[cntrl].type = FF_RUMBLE;
759     ffeffect[cntrl].id = -1;
760     ffeffect[cntrl].u.rumble.strong_magnitude = 0xFFFF;
761     ffeffect[cntrl].u.rumble.weak_magnitude = 0xFFFF;
762     ffeffect[cntrl].replay.length = 0x7fff;             // hack: xboxdrv is buggy and doesn't support infinite replay.
763                                                         // when xboxdrv is fixed (https://github.com/Grumbel/xboxdrv/issues/47),
764                                                         // please remove this
765
766     ioctl(controller[cntrl].event_joystick, EVIOCSFF, &ffeffect[cntrl]);
767
768     ffstrong[cntrl].type = FF_RUMBLE;
769     ffstrong[cntrl].id = -1;
770     ffstrong[cntrl].u.rumble.strong_magnitude = 0xFFFF;
771     ffstrong[cntrl].u.rumble.weak_magnitude = 0x0000;
772     ffstrong[cntrl].replay.length = 500;
773     ffstrong[cntrl].replay.delay = 0;
774
775     ioctl(controller[cntrl].event_joystick, EVIOCSFF, &ffstrong[cntrl]);
776
777     ffweak[cntrl].type = FF_RUMBLE;
778     ffweak[cntrl].id = -1;
779     ffweak[cntrl].u.rumble.strong_magnitude = 0x0000;
780     ffweak[cntrl].u.rumble.weak_magnitude = 0xFFFF;
781     ffweak[cntrl].replay.length = 500;
782     ffweak[cntrl].replay.delay = 0;
783
784     ioctl(controller[cntrl].event_joystick, EVIOCSFF, &ffweak[cntrl]);
785
786     DebugMessage(M64MSG_INFO, "Rumble activated on N64 joystick #%i", cntrl + 1);
787 #endif /* __linux__ */
788 }
789
790 /******************************************************************
791   Function: InitiateControllers
792   Purpose:  This function initialises how each of the controllers
793             should be handled.
794   input:    - The handle to the main window.
795             - A controller structure that needs to be filled for
796               the emulator to know how to handle each controller.
797   output:   none
798 *******************************************************************/
799 EXPORT void CALL InitiateControllers(CONTROL_INFO ControlInfo)
800 {
801     int i;
802
803     // reset controllers
804     memset( controller, 0, sizeof( SController ) * 4 );
805     for ( i = 0; i < SDL_NUM_SCANCODES; i++)
806     {
807         myKeyState[i] = 0;
808     }
809     // set our CONTROL struct pointers to the array that was passed in to this function from the core
810     // this small struct tells the core whether each controller is plugged in, and what type of pak is connected
811     for (i = 0; i < 4; i++)
812         controller[i].control = ControlInfo.Controls + i;
813
814     // read configuration
815     load_configuration(0);
816
817     for( i = 0; i < 4; i++ )
818     {
819         // test for rumble support for this joystick
820         InitiateRumble(i);
821         // if rumble not supported, switch to mempack
822         if (controller[i].control->Plugin == PLUGIN_RAW && controller[i].event_joystick == 0)
823             controller[i].control->Plugin = PLUGIN_MEMPAK;
824     }
825
826     DebugMessage(M64MSG_INFO, "%s version %i.%i.%i initialized.", PLUGIN_NAME, VERSION_PRINTF_SPLIT(PLUGIN_VERSION));
827 }
828
829 /******************************************************************
830   Function: ReadController
831   Purpose:  To process the raw data in the pif ram that is about to
832             be read.
833   input:    - Controller Number (0 to 3) and -1 signalling end of
834               processing the pif ram.
835             - Pointer of data to be processed.
836   output:   none
837   note:     This function is only needed if the DLL is allowing raw
838             data.
839 *******************************************************************/
840 EXPORT void CALL ReadController(int Control, unsigned char *Command)
841 {
842 #ifdef _DEBUG
843     if (Command != NULL)
844         DebugMessage(M64MSG_INFO, "Raw Read (cont=%d):  %02X %02X %02X %02X %02X %02X", Control,
845                      Command[0], Command[1], Command[2], Command[3], Command[4], Command[5]);
846 #endif
847 }
848
849 /******************************************************************
850   Function: RomClosed
851   Purpose:  This function is called when a rom is closed.
852   input:    none
853   output:   none
854 *******************************************************************/
855 EXPORT void CALL RomClosed(void)
856 {
857     int i;
858
859     // close joysticks
860     for( i = 0; i < 4; i++ )
861         if( controller[i].joystick )
862         {
863             SDL_JoystickClose( controller[i].joystick );
864             controller[i].joystick = NULL;
865         }
866
867     // quit SDL joystick subsystem
868     SDL_QuitSubSystem( SDL_INIT_JOYSTICK );
869
870     // release/ungrab mouse
871 #if SDL_VERSION_ATLEAST(2,0,0)
872 #warning SDL mouse grabbing not yet supported with SDL 2.0
873 #else
874     SDL_WM_GrabInput( SDL_GRAB_OFF );
875 #endif
876     SDL_ShowCursor( 1 );
877
878     romopen = 0;
879 }
880
881 /******************************************************************
882   Function: RomOpen
883   Purpose:  This function is called when a rom is open. (from the
884             emulation thread)
885   input:    none
886   output:   none
887 *******************************************************************/
888 EXPORT int CALL RomOpen(void)
889 {
890     int i;
891
892     // init SDL joystick subsystem
893     if( !SDL_WasInit( SDL_INIT_JOYSTICK ) )
894         if( SDL_InitSubSystem( SDL_INIT_JOYSTICK ) == -1 )
895         {
896             DebugMessage(M64MSG_ERROR, "Couldn't init SDL joystick subsystem: %s", SDL_GetError() );
897             return 0;
898         }
899
900     // open joysticks
901     for( i = 0; i < 4; i++ )
902         if( controller[i].device >= 0 )
903         {
904             controller[i].joystick = SDL_JoystickOpen( controller[i].device );
905             if( controller[i].joystick == NULL )
906                 DebugMessage(M64MSG_WARNING, "Couldn't open joystick for controller #%d: %s", i + 1, SDL_GetError() );
907         }
908         else
909             controller[i].joystick = NULL;
910
911     // grab mouse
912     if ((controller[0].mouse || controller[1].mouse || controller[2].mouse || controller[3].mouse) 
913           ||(controller[0].mouse_up || controller[0].mouse_down || controller[0].mouse_left || controller[0].mouse_right))
914     {
915 #if SDL_VERSION_ATLEAST(2,0,0)
916 #warning SDL mouse grabbing not yet supported with SDL 2.0
917 #else
918         SDL_ShowCursor( 0 );
919         if (SDL_WM_GrabInput( SDL_GRAB_ON ) != SDL_GRAB_ON)
920         {
921             DebugMessage(M64MSG_WARNING, "Couldn't grab input! Mouse support won't work!");
922         }
923 #endif
924     }
925
926     romopen = 1;
927     return 1;
928 }
929
930 /******************************************************************
931   Function: SDL_KeyDown
932   Purpose:  To pass the SDL_KeyDown message from the emulator to the
933             plugin.
934   input:    keymod and keysym of the SDL_KEYDOWN message.
935   output:   none
936 *******************************************************************/
937 EXPORT void CALL SDL_KeyDown(int keymod, int keysym)
938 {
939     myKeyState[keysym] = 1;
940 }
941
942 /******************************************************************
943   Function: SDL_KeyUp
944   Purpose:  To pass the SDL_KeyUp message from the emulator to the
945             plugin.
946   input:    keymod and keysym of the SDL_KEYUP message.
947   output:   none
948 *******************************************************************/
949 EXPORT void CALL SDL_KeyUp(int keymod, int keysym)
950 {
951     myKeyState[keysym] = 0;
952 }
953