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