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
110 static int romopen = 0; // is a rom opened
112 static unsigned char myKeyState[SDL_NUM_SCANCODES];
115 static struct ff_effect ffeffect[4];
116 static struct ff_effect ffstrong[4];
117 static struct ff_effect ffweak[4];
120 /* Global functions */
121 void DebugMessage(int level, const char *message, ...)
126 if (l_DebugCallback == NULL)
129 va_start(args, message);
130 vsprintf(msgbuf, message, args);
132 (*l_DebugCallback)(l_DebugCallContext, level, msgbuf);
137 static CONTROL temp_core_controlinfo[4];
139 /* Mupen64Plus plugin functions */
140 EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context,
141 void (*DebugCallback)(void *, int, const char *))
143 ptr_CoreGetAPIVersions CoreAPIVersionFunc;
145 int i, ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion;
148 return M64ERR_ALREADY_INIT;
150 /* first thing is to set the callback function for debug info */
151 l_DebugCallback = DebugCallback;
152 l_DebugCallContext = Context;
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)
158 DebugMessage(M64MSG_ERROR, "Core emulator broken; no CoreAPIVersionFunc() function found.");
159 return M64ERR_INCOMPATIBLE;
162 (*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL);
163 if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000) || ConfigAPIVersion < CONFIG_API_VERSION)
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;
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");
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");
192 if (!ConfigOpenSection || !ConfigDeleteSection || !ConfigSaveFile || !ConfigSaveSection || !ConfigSetParameter || !ConfigGetParameter ||
193 !ConfigSetDefaultInt || !ConfigSetDefaultFloat || !ConfigSetDefaultBool || !ConfigSetDefaultString ||
194 !ConfigGetParamInt || !ConfigGetParamFloat || !ConfigGetParamBool || !ConfigGetParamString ||
195 !ConfigGetSharedDataFilepath || !ConfigGetUserConfigPath || !ConfigGetUserDataPath || !ConfigGetUserCachePath)
197 DebugMessage(M64MSG_ERROR, "Couldn't connect to Core configuration functions");
198 return M64ERR_INCOMPATIBLE;
201 /* reset controllers */
202 memset(controller, 0, sizeof(SController) * 4);
203 for (i = 0; i < SDL_NUM_SCANCODES; i++)
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;
213 /* read plugin config from core config database, auto-config if necessary and update core database */
214 load_configuration(1);
217 return M64ERR_SUCCESS;
220 EXPORT m64p_error CALL PluginShutdown(void)
223 return M64ERR_NOT_INIT;
225 /* reset some local variables */
226 l_DebugCallback = NULL;
227 l_DebugCallContext = NULL;
230 return M64ERR_SUCCESS;
233 EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)
235 /* set version info */
236 if (PluginType != NULL)
237 *PluginType = M64PLUGIN_INPUT;
239 if (PluginVersion != NULL)
240 *PluginVersion = PLUGIN_VERSION;
242 if (APIVersion != NULL)
243 *APIVersion = INPUT_PLUGIN_API_VERSION;
245 if (PluginNamePtr != NULL)
246 *PluginNamePtr = PLUGIN_NAME;
248 if (Capabilities != NULL)
253 return M64ERR_SUCCESS;
256 /* Helper function to handle the SDL keys */
258 doSdlKeys(unsigned char* keystate)
260 int c, b, axis_val, axis_max_val;
261 static int grabmouse = 1, grabtoggled = 0;
264 if (keystate[SDL_SCANCODE_RCTRL])
266 if (keystate[SDL_SCANCODE_RSHIFT])
269 for( c = 0; c < 4; c++ )
271 for( b = 0; b < 16; b++ )
273 if( controller[c].button[b].key == SDL_SCANCODE_UNKNOWN || ((int) controller[c].button[b].key) < 0)
275 if( keystate[controller[c].button[b].key] )
276 controller[c].buttons.Value |= button_bits[b];
278 for( b = 0; b < 2; b++ )
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)
283 axis_val = controller[c].buttons.X_AXIS;
285 axis_val = -controller[c].buttons.Y_AXIS;
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;
295 controller[c].buttons.X_AXIS = axis_val;
297 controller[c].buttons.Y_AXIS = -axis_val;
299 if (controller[c].mouse)
301 if (keystate[SDL_SCANCODE_LCTRL] && keystate[SDL_SCANCODE_LALT])
306 grabmouse = !grabmouse;
308 #if SDL_VERSION_ATLEAST(2,0,0)
309 #warning SDL mouse grabbing not yet supported with SDL 2.0
311 SDL_WM_GrabInput( grabmouse ? SDL_GRAB_ON : SDL_GRAB_OFF );
313 SDL_ShowCursor( grabmouse ? 0 : 1 );
316 else grabtoggled = 0;
321 static unsigned char DataCRC( unsigned char *Data, int iLenght )
323 unsigned char Remainder = Data[0];
326 unsigned char bBit = 0;
328 while( iByte <= iLenght )
330 int HighBit = ((Remainder & 0x80) != 0);
331 Remainder = Remainder << 1;
333 Remainder += ( iByte < iLenght && Data[iByte] & (0x80 >> bBit )) ? 1 : 0;
335 Remainder ^= (HighBit) ? 0x85 : 0;
345 /******************************************************************
346 Function: ControllerCommand
347 Purpose: To process the raw data that has just been sent to a
349 input: - Controller Number (0 to 3) and -1 signalling end of
350 processing the pif ram.
351 - Pointer of data to be processed.
354 note: This function is only needed if the DLL is allowing raw
355 data, or the plugin is set to raw
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)
363 unsigned char *Data = &Command[5];
372 DebugMessage(M64MSG_INFO, "Get status");
377 DebugMessage(M64MSG_INFO, "Read keys");
382 DebugMessage(M64MSG_INFO, "Read pak");
384 if (controller[Control].control->Plugin == PLUGIN_RAW)
386 unsigned int dwAddress = (Command[3] << 8) + (Command[4] & 0xE0);
388 if(( dwAddress >= 0x8000 ) && ( dwAddress < 0x9000 ) )
389 memset( Data, 0x80, 32 );
391 memset( Data, 0x00, 32 );
393 Data[32] = DataCRC( Data, 32 );
398 DebugMessage(M64MSG_INFO, "Write pak");
400 if (controller[Control].control->Plugin == PLUGIN_RAW)
402 unsigned int dwAddress = (Command[3] << 8) + (Command[4] & 0xE0);
403 if (dwAddress == PAK_IO_RUMBLE && *Data)
404 DebugMessage(M64MSG_VERBOSE, "Triggering rumble pack.");
406 struct input_event play;
407 if( dwAddress == PAK_IO_RUMBLE && controller[Control].event_joystick != 0)
412 play.code = ffeffect[Control].id;
415 if (write(controller[Control].event_joystick, (const void*) &play, sizeof(play)) == -1)
416 perror("Error starting rumble effect");
422 play.code = ffeffect[Control].id;
425 if (write(controller[Control].event_joystick, (const void*) &play, sizeof(play)) == -1)
426 perror("Error stopping rumble effect");
430 Data[32] = DataCRC( Data, 32 );
433 case RD_RESETCONTROLLER:
435 DebugMessage(M64MSG_INFO, "Reset controller");
440 DebugMessage(M64MSG_INFO, "Read eeprom");
445 DebugMessage(M64MSG_INFO, "Write eeprom");
451 /******************************************************************
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.
458 *******************************************************************/
459 EXPORT void CALL GetKeys( int Control, BUTTONS *Keys )
461 static int mousex_residual = 0;
462 static int mousey_residual = 0;
465 unsigned char mstate;
467 // Handle keyboard input first
468 doSdlKeys(SDL_GetKeyboardState(NULL));
469 doSdlKeys(myKeyState);
471 // read joystick state
472 SDL_JoystickUpdate();
474 if( controller[Control].device >= 0 )
476 for( b = 0; b < 16; b++ )
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];
482 if( controller[Control].button[b].axis >= 0 )
484 int deadzone = controller[Control].button[b].axis_deadzone;
485 axis_val = SDL_JoystickGetAxis( controller[Control].joystick, controller[Control].button[b].axis );
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];
494 if( controller[Control].button[b].hat >= 0 )
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];
501 for( b = 0; b < 2; b++ )
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)
511 axis_val = controller[Control].buttons.X_AXIS;
513 axis_val = -controller[Control].buttons.Y_AXIS;
515 if( controller[Control].axis[b].axis_a >= 0 ) /* up and left for N64 */
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);
524 if( controller[Control].axis[b].axis_b >= 0 ) /* down and right for N64 */
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);
533 if( controller[Control].axis[b].hat >= 0 )
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 )
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 )
543 if( controller[Control].axis[b].button_a >= 0 )
544 if( SDL_JoystickGetButton( controller[Control].joystick, controller[Control].axis[b].button_a ) )
546 if( controller[Control].axis[b].button_b >= 0 )
547 if( SDL_JoystickGetButton( controller[Control].joystick, controller[Control].axis[b].button_b ) )
551 controller[Control].buttons.X_AXIS = axis_val;
553 controller[Control].buttons.Y_AXIS = -axis_val;
557 // process mouse events
558 mstate = SDL_GetMouseState( NULL, NULL );
559 for( b = 0; b < 16; b++ )
561 if( controller[Control].button[b].mouse < 1 )
563 if( mstate & SDL_BUTTON(controller[Control].button[b].mouse) )
564 controller[Control].buttons.Value |= button_bits[b];
567 if (controller[Control].mouse)
569 #if SDL_VERSION_ATLEAST(2,0,0)
570 #warning SDL mouse grabbing not yet supported with SDL 2.0
572 if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON)
575 #if SDL_VERSION_ATLEAST(1,3,0)
576 while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION) == 1)
578 while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_EVENTMASK(SDL_MOUSEMOTION)) == 1)
581 if (event.motion.xrel)
583 mousex_residual += (int) (event.motion.xrel * controller[Control].mouse_sens[0]);
585 if (event.motion.yrel)
587 mousey_residual += (int) (event.motion.yrel * controller[Control].mouse_sens[1]);
597 axis_val = mousex_residual;
600 else if (axis_val > 80)
602 controller[Control].buttons.X_AXIS = axis_val;
603 axis_val = mousey_residual;
606 else if (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;
615 DebugMessage(M64MSG_VERBOSE, "Controller #%d value: 0x%8.8X", Control, *(int *)&controller[Control].buttons );
617 *Keys = controller[Control].buttons;
619 /* handle mempack / rumblepak switching (only if rumble is active on joystick) */
621 if (controller[Control].event_joystick != 0)
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])
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
632 play.code = ffweak[Control].id;
634 if (write(controller[Control].event_joystick, (const void*) &play, sizeof(play)) == -1)
635 perror("Error starting rumble effect");
637 if (controller[Control].buttons.Value & button_bits[15])
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
643 play.code = ffstrong[Control].id;
645 if (write(controller[Control].event_joystick, (const void*) &play, sizeof(play)) == -1)
646 perror("Error starting rumble effect");
648 // handle inserting new pack if the time has arrived
649 if (SwitchPackTime[Control] != 0 && (SDL_GetTicks() - SwitchPackTime[Control]) >= 1000)
651 controller[Control].control->Plugin = SwitchPackType[Control];
652 SwitchPackTime[Control] = 0;
655 #endif /* __linux__ */
657 controller[Control].buttons.Value = 0;
660 static void InitiateRumble(int cntrl)
665 unsigned long features[4];
670 controller[cntrl].event_joystick = 0;
672 sprintf(temp,"/sys/class/input/js%d/device", controller[cntrl].device);
678 while ((ep=readdir(dp)))
680 if (strncmp(ep->d_name, "event",5)==0)
682 sprintf(temp, "/dev/input/%s", ep->d_name);
686 else if(strncmp(ep->d_name,"input:event", 11)==0)
688 sscanf(ep->d_name, "input:%s", temp2);
689 sprintf(temp, "/dev/input/%s", temp2);
693 else if(strncmp(ep->d_name,"input:input", 11)==0)
696 strcat(temp, ep->d_name);
708 DebugMessage(M64MSG_WARNING, "Couldn't find input event for rumble support.");
712 controller[cntrl].event_joystick = open(temp, O_RDWR);
713 if(controller[cntrl].event_joystick==-1)
715 DebugMessage(M64MSG_WARNING, "Couldn't open device file '%s' for rumble support.", temp);
716 controller[cntrl].event_joystick = 0;
720 if(ioctl(controller[cntrl].event_joystick, EVIOCGBIT(EV_FF, sizeof(unsigned long) * 4), features)==-1)
722 DebugMessage(M64MSG_WARNING, "Linux kernel communication failed for force feedback (rumble).\n");
723 controller[cntrl].event_joystick = 0;
727 if(!test_bit(FF_RUMBLE, features))
729 DebugMessage(M64MSG_WARNING, "No rumble supported on N64 joystick #%i", cntrl + 1);
730 controller[cntrl].event_joystick = 0;
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
742 ioctl(controller[cntrl].event_joystick, EVIOCSFF, &ffeffect[cntrl]);
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;
751 ioctl(controller[cntrl].event_joystick, EVIOCSFF, &ffstrong[cntrl]);
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;
760 ioctl(controller[cntrl].event_joystick, EVIOCSFF, &ffweak[cntrl]);
762 DebugMessage(M64MSG_INFO, "Rumble activated on N64 joystick #%i", cntrl + 1);
763 #endif /* __linux__ */
766 /******************************************************************
767 Function: InitiateControllers
768 Purpose: This function initialises how each of the controllers
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.
774 *******************************************************************/
775 EXPORT void CALL InitiateControllers(CONTROL_INFO ControlInfo)
780 memset( controller, 0, sizeof( SController ) * 4 );
781 for ( i = 0; i < SDL_NUM_SCANCODES; i++)
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;
790 // read configuration
791 load_configuration(0);
793 for( i = 0; i < 4; i++ )
795 // test for rumble support for this joystick
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;
802 DebugMessage(M64MSG_INFO, "%s version %i.%i.%i initialized.", PLUGIN_NAME, VERSION_PRINTF_SPLIT(PLUGIN_VERSION));
805 /******************************************************************
806 Function: ReadController
807 Purpose: To process the raw data in the pif ram that is about to
809 input: - Controller Number (0 to 3) and -1 signalling end of
810 processing the pif ram.
811 - Pointer of data to be processed.
813 note: This function is only needed if the DLL is allowing raw
815 *******************************************************************/
816 EXPORT void CALL ReadController(int Control, unsigned char *Command)
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]);
825 /******************************************************************
827 Purpose: This function is called when a rom is closed.
830 *******************************************************************/
831 EXPORT void CALL RomClosed(void)
836 for( i = 0; i < 4; i++ )
837 if( controller[i].joystick )
839 SDL_JoystickClose( controller[i].joystick );
840 controller[i].joystick = NULL;
843 // quit SDL joystick subsystem
844 SDL_QuitSubSystem( SDL_INIT_JOYSTICK );
846 // release/ungrab mouse
847 #if SDL_VERSION_ATLEAST(2,0,0)
848 #warning SDL mouse grabbing not yet supported with SDL 2.0
850 SDL_WM_GrabInput( SDL_GRAB_OFF );
857 /******************************************************************
859 Purpose: This function is called when a rom is open. (from the
863 *******************************************************************/
864 EXPORT int CALL RomOpen(void)
868 // init SDL joystick subsystem
869 if( !SDL_WasInit( SDL_INIT_JOYSTICK ) )
870 if( SDL_InitSubSystem( SDL_INIT_JOYSTICK ) == -1 )
872 DebugMessage(M64MSG_ERROR, "Couldn't init SDL joystick subsystem: %s", SDL_GetError() );
877 for( i = 0; i < 4; i++ )
878 if( controller[i].device >= 0 )
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() );
885 controller[i].joystick = NULL;
888 if (controller[0].mouse || controller[1].mouse || controller[2].mouse || controller[3].mouse)
890 #if SDL_VERSION_ATLEAST(2,0,0)
891 #warning SDL mouse grabbing not yet supported with SDL 2.0
894 if (SDL_WM_GrabInput( SDL_GRAB_ON ) != SDL_GRAB_ON)
896 DebugMessage(M64MSG_WARNING, "Couldn't grab input! Mouse support won't work!");
905 /******************************************************************
906 Function: SDL_KeyDown
907 Purpose: To pass the SDL_KeyDown message from the emulator to the
909 input: keymod and keysym of the SDL_KEYDOWN message.
911 *******************************************************************/
912 EXPORT void CALL SDL_KeyDown(int keymod, int keysym)
914 myKeyState[keysym] = 1;
917 /******************************************************************
919 Purpose: To pass the SDL_KeyUp message from the emulator to the
921 input: keymod and keysym of the SDL_KEYUP message.
923 *******************************************************************/
924 EXPORT void CALL SDL_KeyUp(int keymod, int keysym)
926 myKeyState[keysym] = 0;