CORE: Ajusted CountPerOp for KI
[mupen64plus-pandora.git] / source / mupen64plus-input-sdl / src / plugin.c
CommitLineData
48d52ab5 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 */
61ptr_ConfigOpenSection ConfigOpenSection = NULL;
62ptr_ConfigDeleteSection ConfigDeleteSection = NULL;
63ptr_ConfigSaveSection ConfigSaveSection = NULL;
64ptr_ConfigListParameters ConfigListParameters = NULL;
65ptr_ConfigSaveFile ConfigSaveFile = NULL;
66ptr_ConfigSetParameter ConfigSetParameter = NULL;
67ptr_ConfigGetParameter ConfigGetParameter = NULL;
68ptr_ConfigGetParameterHelp ConfigGetParameterHelp = NULL;
69ptr_ConfigSetDefaultInt ConfigSetDefaultInt = NULL;
70ptr_ConfigSetDefaultFloat ConfigSetDefaultFloat = NULL;
71ptr_ConfigSetDefaultBool ConfigSetDefaultBool = NULL;
72ptr_ConfigSetDefaultString ConfigSetDefaultString = NULL;
73ptr_ConfigGetParamInt ConfigGetParamInt = NULL;
74ptr_ConfigGetParamFloat ConfigGetParamFloat = NULL;
75ptr_ConfigGetParamBool ConfigGetParamBool = NULL;
76ptr_ConfigGetParamString ConfigGetParamString = NULL;
77
78ptr_ConfigGetSharedDataFilepath ConfigGetSharedDataFilepath = NULL;
79ptr_ConfigGetUserConfigPath ConfigGetUserConfigPath = NULL;
80ptr_ConfigGetUserDataPath ConfigGetUserDataPath = NULL;
81ptr_ConfigGetUserCachePath ConfigGetUserCachePath = NULL;
82
83/* global data definitions */
84SController controller[4]; // 4 controllers
85
86/* static data definitions */
87static void (*l_DebugCallback)(void *, int, const char *) = NULL;
88static void *l_DebugCallContext = NULL;
89static int l_PluginInit = 0;
90
91static 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
110static int romopen = 0; // is a rom opened
111
112static unsigned char myKeyState[SDL_NUM_SCANCODES];
113
114#ifdef __linux__
115static struct ff_effect ffeffect[4];
116static struct ff_effect ffstrong[4];
117static struct ff_effect ffweak[4];
118#endif //__linux__
119
120/* Global functions */
121void 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
137static CONTROL temp_core_controlinfo[4];
138
139/* Mupen64Plus plugin functions */
140EXPORT 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
220EXPORT 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
233EXPORT 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 */
257static void
258doSdlKeys(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
321static 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*******************************************************************/
361EXPORT 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*******************************************************************/
459EXPORT 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
660static 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*******************************************************************/
775EXPORT 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*******************************************************************/
816EXPORT 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*******************************************************************/
831EXPORT 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*******************************************************************/
864EXPORT 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*******************************************************************/
912EXPORT 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*******************************************************************/
924EXPORT void CALL SDL_KeyUp(int keymod, int keysym)
925{
926 myKeyState[keysym] = 0;
927}
928