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 *
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. *
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. *
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 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
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"
39 #include "osal_dynamiclib.h"
45 #include <sys/types.h>
46 #include <linux/input.h>
47 #endif /* __linux__ */
51 /* defines for the force feedback rumble support */
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)
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;
78 ptr_ConfigGetSharedDataFilepath ConfigGetSharedDataFilepath = NULL;
79 ptr_ConfigGetUserConfigPath ConfigGetUserConfigPath = NULL;
80 ptr_ConfigGetUserDataPath ConfigGetUserDataPath = NULL;
81 ptr_ConfigGetUserCachePath ConfigGetUserCachePath = NULL;
83 /* global data definitions */
84 SController controller[4]; // 4 controllers
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;
91 static unsigned short button_bits[] = {
96 0x0010, // START_BUTTON
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
114 static int romopen = 0; // is a rom opened
116 static unsigned char myKeyState[SDL_NUM_SCANCODES];
119 static struct ff_effect ffeffect[4];
120 static struct ff_effect ffstrong[4];
121 static struct ff_effect ffweak[4];
124 /* Global functions */
125 void DebugMessage(int level, const char *message, ...)
130 if (l_DebugCallback == NULL)
133 va_start(args, message);
134 vsprintf(msgbuf, message, args);
136 (*l_DebugCallback)(l_DebugCallContext, level, msgbuf);
141 static CONTROL temp_core_controlinfo[4];
143 /* Mupen64Plus plugin functions */
144 EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context,
145 void (*DebugCallback)(void *, int, const char *))
147 ptr_CoreGetAPIVersions CoreAPIVersionFunc;
149 int i, ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion;
152 return M64ERR_ALREADY_INIT;
154 /* first thing is to set the callback function for debug info */
155 l_DebugCallback = DebugCallback;
156 l_DebugCallContext = Context;
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)
162 DebugMessage(M64MSG_ERROR, "Core emulator broken; no CoreAPIVersionFunc() function found.");
163 return M64ERR_INCOMPATIBLE;
166 (*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL);
167 if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000) || ConfigAPIVersion < CONFIG_API_VERSION)
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;
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");
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");
196 if (!ConfigOpenSection || !ConfigDeleteSection || !ConfigSaveFile || !ConfigSaveSection || !ConfigSetParameter || !ConfigGetParameter ||
197 !ConfigSetDefaultInt || !ConfigSetDefaultFloat || !ConfigSetDefaultBool || !ConfigSetDefaultString ||
198 !ConfigGetParamInt || !ConfigGetParamFloat || !ConfigGetParamBool || !ConfigGetParamString ||
199 !ConfigGetSharedDataFilepath || !ConfigGetUserConfigPath || !ConfigGetUserDataPath || !ConfigGetUserCachePath)
201 DebugMessage(M64MSG_ERROR, "Couldn't connect to Core configuration functions");
202 return M64ERR_INCOMPATIBLE;
205 /* reset controllers */
206 memset(controller, 0, sizeof(SController) * 4);
207 for (i = 0; i < SDL_NUM_SCANCODES; i++)
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;
217 /* read plugin config from core config database, auto-config if necessary and update core database */
218 load_configuration(1);
221 return M64ERR_SUCCESS;
224 EXPORT m64p_error CALL PluginShutdown(void)
227 return M64ERR_NOT_INIT;
229 /* reset some local variables */
230 l_DebugCallback = NULL;
231 l_DebugCallContext = NULL;
234 return M64ERR_SUCCESS;
237 EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)
239 /* set version info */
240 if (PluginType != NULL)
241 *PluginType = M64PLUGIN_INPUT;
243 if (PluginVersion != NULL)
244 *PluginVersion = PLUGIN_VERSION;
246 if (APIVersion != NULL)
247 *APIVersion = INPUT_PLUGIN_API_VERSION;
249 if (PluginNamePtr != NULL)
250 *PluginNamePtr = PLUGIN_NAME;
252 if (Capabilities != NULL)
257 return M64ERR_SUCCESS;
260 /* Helper function to handle the SDL keys */
262 doSdlKeys(unsigned char* keystate)
264 int c, b, axis_val, axis_max_val;
265 static int grabmouse = 1, grabtoggled = 0;
268 /* if (keystate[SDL_SCANCODE_RCTRL])
270 if (keystate[SDL_SCANCODE_RSHIFT])
271 axis_max_val -= 20;*/
273 for( c = 0; c < 4; c++ )
275 for( b = 0; b < 16; b++ )
277 if( controller[c].button[b].key == SDL_SCANCODE_UNKNOWN || ((int) controller[c].button[b].key) < 0)
279 if( keystate[controller[c].button[b].key] )
280 controller[c].buttons.Value |= button_bits[b];
282 for( b = 0; b < 2; b++ )
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)
287 axis_val = controller[c].buttons.X_AXIS;
289 axis_val = -controller[c].buttons.Y_AXIS;
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;
299 controller[c].buttons.X_AXIS = axis_val;
301 controller[c].buttons.Y_AXIS = -axis_val;
303 if (controller[c].mouse)
305 /* if (keystate[SDL_SCANCODE_LCTRL] && keystate[SDL_SCANCODE_LALT])
310 grabmouse = !grabmouse;
312 #if SDL_VERSION_ATLEAST(2,0,0)
313 #warning SDL mouse grabbing not yet supported with SDL 2.0
315 SDL_WM_GrabInput( grabmouse ? SDL_GRAB_ON : SDL_GRAB_OFF );
317 SDL_ShowCursor( grabmouse ? 0 : 1 );
320 else grabtoggled = 0;
326 static unsigned char DataCRC( unsigned char *Data, int iLenght )
328 unsigned char Remainder = Data[0];
331 unsigned char bBit = 0;
333 while( iByte <= iLenght )
335 int HighBit = ((Remainder & 0x80) != 0);
336 Remainder = Remainder << 1;
338 Remainder += ( iByte < iLenght && Data[iByte] & (0x80 >> bBit )) ? 1 : 0;
340 Remainder ^= (HighBit) ? 0x85 : 0;
350 /******************************************************************
351 Function: ControllerCommand
352 Purpose: To process the raw data that has just been sent to a
354 input: - Controller Number (0 to 3) and -1 signalling end of
355 processing the pif ram.
356 - Pointer of data to be processed.
359 note: This function is only needed if the DLL is allowing raw
360 data, or the plugin is set to raw
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)
368 unsigned char *Data = &Command[5];
377 DebugMessage(M64MSG_INFO, "Get status");
382 DebugMessage(M64MSG_INFO, "Read keys");
387 DebugMessage(M64MSG_INFO, "Read pak");
389 if (controller[Control].control->Plugin == PLUGIN_RAW)
391 unsigned int dwAddress = (Command[3] << 8) + (Command[4] & 0xE0);
393 if(( dwAddress >= 0x8000 ) && ( dwAddress < 0x9000 ) )
394 memset( Data, 0x80, 32 );
396 memset( Data, 0x00, 32 );
398 Data[32] = DataCRC( Data, 32 );
403 DebugMessage(M64MSG_INFO, "Write pak");
405 if (controller[Control].control->Plugin == PLUGIN_RAW)
407 unsigned int dwAddress = (Command[3] << 8) + (Command[4] & 0xE0);
408 if (dwAddress == PAK_IO_RUMBLE && *Data)
409 DebugMessage(M64MSG_VERBOSE, "Triggering rumble pack.");
411 struct input_event play;
412 if( dwAddress == PAK_IO_RUMBLE && controller[Control].event_joystick != 0)
417 play.code = ffeffect[Control].id;
420 if (write(controller[Control].event_joystick, (const void*) &play, sizeof(play)) == -1)
421 perror("Error starting rumble effect");
427 play.code = ffeffect[Control].id;
430 if (write(controller[Control].event_joystick, (const void*) &play, sizeof(play)) == -1)
431 perror("Error stopping rumble effect");
435 Data[32] = DataCRC( Data, 32 );
438 case RD_RESETCONTROLLER:
440 DebugMessage(M64MSG_INFO, "Reset controller");
445 DebugMessage(M64MSG_INFO, "Read eeprom");
450 DebugMessage(M64MSG_INFO, "Write eeprom");
456 /******************************************************************
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.
463 *******************************************************************/
464 EXPORT void CALL GetKeys( int Control, BUTTONS *Keys )
466 static int mousex_residual = 0;
467 static int mousey_residual = 0;
470 unsigned char mstate;
472 // Handle keyboard input first
473 doSdlKeys(SDL_GetKeyboardState(NULL));
474 doSdlKeys(myKeyState);
476 // read joystick state
477 SDL_JoystickUpdate();
479 if( controller[Control].device >= 0 )
481 for( b = 0; b < NUM_BUTTONS; b++ )
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];
487 if( controller[Control].button[b].axis >= 0 )
489 int deadzone = controller[Control].button[b].axis_deadzone;
490 axis_val = SDL_JoystickGetAxis( controller[Control].joystick, controller[Control].button[b].axis );
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];
499 if( controller[Control].button[b].hat >= 0 )
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];
506 for( b = 0; b < 2; b++ )
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)
516 axis_val = controller[Control].buttons.X_AXIS;
518 axis_val = -controller[Control].buttons.Y_AXIS;
520 if( controller[Control].axis[b].axis_a >= 0 ) /* up and left for N64 */
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);
529 if( controller[Control].axis[b].axis_b >= 0 ) /* down and right for N64 */
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);
538 if( controller[Control].axis[b].hat >= 0 )
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 )
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 )
548 if( controller[Control].axis[b].button_a >= 0 )
549 if( SDL_JoystickGetButton( controller[Control].joystick, controller[Control].axis[b].button_a ) )
551 if( controller[Control].axis[b].button_b >= 0 )
552 if( SDL_JoystickGetButton( controller[Control].joystick, controller[Control].axis[b].button_b ) )
556 controller[Control].buttons.X_AXIS = axis_val;
558 controller[Control].buttons.Y_AXIS = -axis_val;
562 // process mouse events
563 mstate = SDL_GetMouseState( NULL, NULL );
564 for( b = 0; b < NUM_BUTTONS; b++ )
566 if( controller[Control].button[b].mouse < 1 )
568 if( mstate & SDL_BUTTON(controller[Control].button[b].mouse) )
569 controller[Control].buttons.Value |= button_bits[b];
572 if ((controller[Control].mouse)
573 || ((controller[Control].mouse_up) || (controller[Control].mouse_down) || (controller[Control].mouse_left) || (controller[Control].mouse_right) ))
575 #if SDL_VERSION_ATLEAST(2,0,0)
576 #warning SDL mouse grabbing not yet supported with SDL 2.0
578 if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON)
581 #if SDL_VERSION_ATLEAST(1,3,0)
582 while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION) == 1)
584 while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_EVENTMASK(SDL_MOUSEMOTION)) == 1)
587 if (event.motion.xrel)
589 mousex_residual += (int) (event.motion.xrel * controller[Control].mouse_sens[0]);
591 if (event.motion.yrel)
593 mousey_residual += (int) (event.motion.yrel * controller[Control].mouse_sens[1]);
603 axis_val = mousex_residual;
606 else if (axis_val > 80)
608 if (controller[Control].mouse)
609 controller[Control].buttons.X_AXIS = axis_val;
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;
618 axis_val = mousey_residual;
621 else if (axis_val > 80)
623 if (controller[Control].mouse)
624 controller[Control].buttons.Y_AXIS = -axis_val;
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;
633 /* the mouse x/y values decay exponentially */
634 mousex_residual = (mousex_residual * 224) / 256;
635 mousey_residual = (mousey_residual * 224) / 256;
639 DebugMessage(M64MSG_VERBOSE, "Controller #%d value: 0x%8.8X", Control, *(int *)&controller[Control].buttons );
641 *Keys = controller[Control].buttons;
643 /* handle mempack / rumblepak switching (only if rumble is active on joystick) */
645 if (controller[Control].event_joystick != 0)
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])
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
656 play.code = ffweak[Control].id;
658 if (write(controller[Control].event_joystick, (const void*) &play, sizeof(play)) == -1)
659 perror("Error starting rumble effect");
661 if (controller[Control].buttons.Value & button_bits[15])
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
667 play.code = ffstrong[Control].id;
669 if (write(controller[Control].event_joystick, (const void*) &play, sizeof(play)) == -1)
670 perror("Error starting rumble effect");
672 // handle inserting new pack if the time has arrived
673 if (SwitchPackTime[Control] != 0 && (SDL_GetTicks() - SwitchPackTime[Control]) >= 1000)
675 controller[Control].control->Plugin = SwitchPackType[Control];
676 SwitchPackTime[Control] = 0;
679 #endif /* __linux__ */
681 controller[Control].buttons.Value = 0;
684 static void InitiateRumble(int cntrl)
689 unsigned long features[4];
694 controller[cntrl].event_joystick = 0;
696 sprintf(temp,"/sys/class/input/js%d/device", controller[cntrl].device);
702 while ((ep=readdir(dp)))
704 if (strncmp(ep->d_name, "event",5)==0)
706 sprintf(temp, "/dev/input/%s", ep->d_name);
710 else if(strncmp(ep->d_name,"input:event", 11)==0)
712 sscanf(ep->d_name, "input:%s", temp2);
713 sprintf(temp, "/dev/input/%s", temp2);
717 else if(strncmp(ep->d_name,"input:input", 11)==0)
720 strcat(temp, ep->d_name);
732 DebugMessage(M64MSG_WARNING, "Couldn't find input event for rumble support.");
736 controller[cntrl].event_joystick = open(temp, O_RDWR);
737 if(controller[cntrl].event_joystick==-1)
739 DebugMessage(M64MSG_WARNING, "Couldn't open device file '%s' for rumble support.", temp);
740 controller[cntrl].event_joystick = 0;
744 if(ioctl(controller[cntrl].event_joystick, EVIOCGBIT(EV_FF, sizeof(unsigned long) * 4), features)==-1)
746 DebugMessage(M64MSG_WARNING, "Linux kernel communication failed for force feedback (rumble).\n");
747 controller[cntrl].event_joystick = 0;
751 if(!test_bit(FF_RUMBLE, features))
753 DebugMessage(M64MSG_WARNING, "No rumble supported on N64 joystick #%i", cntrl + 1);
754 controller[cntrl].event_joystick = 0;
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
766 ioctl(controller[cntrl].event_joystick, EVIOCSFF, &ffeffect[cntrl]);
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;
775 ioctl(controller[cntrl].event_joystick, EVIOCSFF, &ffstrong[cntrl]);
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;
784 ioctl(controller[cntrl].event_joystick, EVIOCSFF, &ffweak[cntrl]);
786 DebugMessage(M64MSG_INFO, "Rumble activated on N64 joystick #%i", cntrl + 1);
787 #endif /* __linux__ */
790 /******************************************************************
791 Function: InitiateControllers
792 Purpose: This function initialises how each of the controllers
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.
798 *******************************************************************/
799 EXPORT void CALL InitiateControllers(CONTROL_INFO ControlInfo)
804 memset( controller, 0, sizeof( SController ) * 4 );
805 for ( i = 0; i < SDL_NUM_SCANCODES; i++)
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;
814 // read configuration
815 load_configuration(0);
817 for( i = 0; i < 4; i++ )
819 // test for rumble support for this joystick
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;
826 DebugMessage(M64MSG_INFO, "%s version %i.%i.%i initialized.", PLUGIN_NAME, VERSION_PRINTF_SPLIT(PLUGIN_VERSION));
829 /******************************************************************
830 Function: ReadController
831 Purpose: To process the raw data in the pif ram that is about to
833 input: - Controller Number (0 to 3) and -1 signalling end of
834 processing the pif ram.
835 - Pointer of data to be processed.
837 note: This function is only needed if the DLL is allowing raw
839 *******************************************************************/
840 EXPORT void CALL ReadController(int Control, unsigned char *Command)
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]);
849 /******************************************************************
851 Purpose: This function is called when a rom is closed.
854 *******************************************************************/
855 EXPORT void CALL RomClosed(void)
860 for( i = 0; i < 4; i++ )
861 if( controller[i].joystick )
863 SDL_JoystickClose( controller[i].joystick );
864 controller[i].joystick = NULL;
867 // quit SDL joystick subsystem
868 SDL_QuitSubSystem( SDL_INIT_JOYSTICK );
870 // release/ungrab mouse
871 #if SDL_VERSION_ATLEAST(2,0,0)
872 #warning SDL mouse grabbing not yet supported with SDL 2.0
874 SDL_WM_GrabInput( SDL_GRAB_OFF );
881 /******************************************************************
883 Purpose: This function is called when a rom is open. (from the
887 *******************************************************************/
888 EXPORT int CALL RomOpen(void)
892 // init SDL joystick subsystem
893 if( !SDL_WasInit( SDL_INIT_JOYSTICK ) )
894 if( SDL_InitSubSystem( SDL_INIT_JOYSTICK ) == -1 )
896 DebugMessage(M64MSG_ERROR, "Couldn't init SDL joystick subsystem: %s", SDL_GetError() );
901 for( i = 0; i < 4; i++ )
902 if( controller[i].device >= 0 )
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() );
909 controller[i].joystick = NULL;
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))
915 #if SDL_VERSION_ATLEAST(2,0,0)
916 #warning SDL mouse grabbing not yet supported with SDL 2.0
919 if (SDL_WM_GrabInput( SDL_GRAB_ON ) != SDL_GRAB_ON)
921 DebugMessage(M64MSG_WARNING, "Couldn't grab input! Mouse support won't work!");
930 /******************************************************************
931 Function: SDL_KeyDown
932 Purpose: To pass the SDL_KeyDown message from the emulator to the
934 input: keymod and keysym of the SDL_KEYDOWN message.
936 *******************************************************************/
937 EXPORT void CALL SDL_KeyDown(int keymod, int keysym)
939 myKeyState[keysym] = 1;
942 /******************************************************************
944 Purpose: To pass the SDL_KeyUp message from the emulator to the
946 input: keymod and keysym of the SDL_KEYUP message.
948 *******************************************************************/
949 EXPORT void CALL SDL_KeyUp(int keymod, int keysym)
951 myKeyState[keysym] = 0;