diff --git a/BizHawk.MultiClient/output/dll/mupen64plus-input-bkm.dll b/BizHawk.MultiClient/output/dll/mupen64plus-input-bkm.dll
new file mode 100644
index 0000000000..f3e19c734c
Binary files /dev/null and b/BizHawk.MultiClient/output/dll/mupen64plus-input-bkm.dll differ
diff --git a/libmupen64plus/mupen64plus-input-bkm/mupen64plus-input-bkm/mupen64plus-input-bkm.vcxproj b/libmupen64plus/mupen64plus-input-bkm/mupen64plus-input-bkm/mupen64plus-input-bkm.vcxproj
new file mode 100644
index 0000000000..ba90303c19
--- /dev/null
+++ b/libmupen64plus/mupen64plus-input-bkm/mupen64plus-input-bkm/mupen64plus-input-bkm.vcxproj
@@ -0,0 +1,88 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+
+ {3D8BD211-6002-4698-B5C1-A0F3146B6ACF}
+ mupen64plusinputbkm
+
+
+
+ Application
+ true
+ v110
+ MultiByte
+
+
+ DynamicLibrary
+ false
+ v100
+ true
+ MultiByte
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+ Level3
+ Disabled
+
+
+ true
+
+
+
+
+ Level3
+ MaxSpeed
+
+
+ false
+ ..\..\mupen64plus-core\src\api;..\..\mupen64plus-win32-deps\SDL-1.2.14\include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)
+
+
+
+ true
+ true
+ true
+ ..\..\mupen64plus-win32-deps\SDL-1.2.14\lib\SDL.lib;%(AdditionalDependencies)
+ Windows
+
+
+ xcopy /y $(OutDir)$(TargetName)$(TargetExt) $(TargetDir)..\..\..\..\..\BizHawk.MultiClient\output\dll\
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libmupen64plus/mupen64plus-input-bkm/osal_dynamiclib.h b/libmupen64plus/mupen64plus-input-bkm/osal_dynamiclib.h
new file mode 100644
index 0000000000..daef1541c0
--- /dev/null
+++ b/libmupen64plus/mupen64plus-input-bkm/osal_dynamiclib.h
@@ -0,0 +1,30 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-core - osal/dynamiclib.h *
+ * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Copyright (C) 2009 Richard Goedeken *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#if !defined(OSAL_DYNAMICLIB_H)
+#define OSAL_DYNAMICLIB_H
+
+#include "m64p_types.h"
+
+void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName);
+
+#endif /* #define OSAL_DYNAMICLIB_H */
+
diff --git a/libmupen64plus/mupen64plus-input-bkm/osal_dynamiclib_unix.c b/libmupen64plus/mupen64plus-input-bkm/osal_dynamiclib_unix.c
new file mode 100644
index 0000000000..b3b7ba52dc
--- /dev/null
+++ b/libmupen64plus/mupen64plus-input-bkm/osal_dynamiclib_unix.c
@@ -0,0 +1,37 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-core - osal/dynamiclib_unix.c *
+ * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Copyright (C) 2009 Richard Goedeken *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include
+#include
+#include
+
+#include "m64p_types.h"
+#include "osal_dynamiclib.h"
+
+void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName)
+{
+ if (pccProcedureName == NULL)
+ return NULL;
+
+ return dlsym(LibHandle, pccProcedureName);
+}
+
+
diff --git a/libmupen64plus/mupen64plus-input-bkm/osal_dynamiclib_win32.c b/libmupen64plus/mupen64plus-input-bkm/osal_dynamiclib_win32.c
new file mode 100644
index 0000000000..4455cee52b
--- /dev/null
+++ b/libmupen64plus/mupen64plus-input-bkm/osal_dynamiclib_win32.c
@@ -0,0 +1,74 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-ui-console - osal_dynamiclib_win32.c *
+ * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Copyright (C) 2009 Richard Goedeken *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include
+#include
+#include
+
+#include "m64p_types.h"
+#include "osal_dynamiclib.h"
+
+m64p_error osal_dynlib_open(m64p_dynlib_handle *pLibHandle, const char *pccLibraryPath)
+{
+ if (pLibHandle == NULL || pccLibraryPath == NULL)
+ return M64ERR_INPUT_ASSERT;
+
+ *pLibHandle = LoadLibrary(pccLibraryPath);
+
+ if (*pLibHandle == NULL)
+ {
+ char *pchErrMsg;
+ DWORD dwErr = GetLastError();
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pchErrMsg, 0, NULL);
+ fprintf(stderr, "LoadLibrary('%s') error: %s\n", pccLibraryPath, pchErrMsg);
+ LocalFree(pchErrMsg);
+ return M64ERR_INPUT_NOT_FOUND;
+ }
+
+ return M64ERR_SUCCESS;
+}
+
+void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName)
+{
+ if (pccProcedureName == NULL)
+ return NULL;
+
+ return GetProcAddress(LibHandle, pccProcedureName);
+}
+
+m64p_error osal_dynlib_close(m64p_dynlib_handle LibHandle)
+{
+ int rval = FreeLibrary(LibHandle);
+
+ if (rval == 0)
+ {
+ char *pchErrMsg;
+ DWORD dwErr = GetLastError();
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pchErrMsg, 0, NULL);
+ fprintf(stderr, "FreeLibrary() error: %s\n", pchErrMsg);
+ LocalFree(pchErrMsg);
+ return M64ERR_INTERNAL;
+ }
+
+ return M64ERR_SUCCESS;
+}
diff --git a/libmupen64plus/mupen64plus-input-bkm/osal_preproc.h b/libmupen64plus/mupen64plus-input-bkm/osal_preproc.h
new file mode 100644
index 0000000000..37c7dc4a86
--- /dev/null
+++ b/libmupen64plus/mupen64plus-input-bkm/osal_preproc.h
@@ -0,0 +1,33 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus - osal_preproc.h *
+ * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Copyright (C) 2009 Richard Goedeken *
+ * Copyright (C) 2002 Hacktarux *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* this header file is for system-dependent #defines, #includes, and typedefs */
+
+#if !defined(OSAL_PREPROC_H)
+#define OSAL_PREPROC_H
+
+#if defined(WIN32)
+ #define strcasestr strstr
+ #define strcasecmp _stricmp
+#endif // WIN32
+
+#endif // OSAL_PREPROC_H
diff --git a/libmupen64plus/mupen64plus-input-bkm/plugin.c b/libmupen64plus/mupen64plus-input-bkm/plugin.c
new file mode 100644
index 0000000000..5cc29f46de
--- /dev/null
+++ b/libmupen64plus/mupen64plus-input-bkm/plugin.c
@@ -0,0 +1,457 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-input-sdl - plugin.c *
+ * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Copyright (C) 2008-2011 Richard Goedeken *
+ * Copyright (C) 2008 Tillin9 *
+ * Copyright (C) 2002 Blight *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include
+#include
+#include
+
+#define M64P_PLUGIN_PROTOTYPES 1
+#include "m64p_types.h"
+#include "m64p_plugin.h"
+#include "m64p_common.h"
+#include "m64p_config.h"
+
+#include "plugin.h"
+#include "config.h"
+#include "version.h"
+#include "osal_dynamiclib.h"
+
+#include
+
+/* definitions of pointers to Core config functions */
+ptr_ConfigOpenSection ConfigOpenSection = NULL;
+ptr_ConfigDeleteSection ConfigDeleteSection = NULL;
+ptr_ConfigSetParameter ConfigSetParameter = NULL;
+ptr_ConfigGetParameter ConfigGetParameter = NULL;
+ptr_ConfigGetParameterHelp ConfigGetParameterHelp = NULL;
+ptr_ConfigSetDefaultInt ConfigSetDefaultInt = NULL;
+ptr_ConfigSetDefaultFloat ConfigSetDefaultFloat = NULL;
+ptr_ConfigSetDefaultBool ConfigSetDefaultBool = NULL;
+ptr_ConfigSetDefaultString ConfigSetDefaultString = NULL;
+ptr_ConfigGetParamInt ConfigGetParamInt = NULL;
+ptr_ConfigGetParamFloat ConfigGetParamFloat = NULL;
+ptr_ConfigGetParamBool ConfigGetParamBool = NULL;
+ptr_ConfigGetParamString ConfigGetParamString = NULL;
+
+ptr_ConfigGetSharedDataFilepath ConfigGetSharedDataFilepath = NULL;
+ptr_ConfigGetUserConfigPath ConfigGetUserConfigPath = NULL;
+ptr_ConfigGetUserDataPath ConfigGetUserDataPath = NULL;
+ptr_ConfigGetUserCachePath ConfigGetUserCachePath = NULL;
+
+/* global data definitions */
+SController controller[4]; // 4 controllers
+
+/* static data definitions */
+static void (*l_DebugCallback)(void *, int, const char *) = NULL;
+static void *l_DebugCallContext = NULL;
+static int l_PluginInit = 0;
+
+static unsigned short button_bits[] = {
+ 0x0001, // R_DPAD
+ 0x0002, // L_DPAD
+ 0x0004, // D_DPAD
+ 0x0008, // U_DPAD
+ 0x0010, // START_BUTTON
+ 0x0020, // Z_TRIG
+ 0x0040, // B_BUTTON
+ 0x0080, // A_BUTTON
+ 0x0100, // R_CBUTTON
+ 0x0200, // L_CBUTTON
+ 0x0400, // D_CBUTTON
+ 0x0800, // U_CBUTTON
+ 0x1000, // R_TRIG
+ 0x2000, // L_TRIG
+ 0x4000, // Mempak switch
+ 0x8000 // Rumblepak switch
+};
+
+static int romopen = 0; // is a rom opened
+
+static unsigned char myKeyState[SDL_NUM_SCANCODES];
+
+#ifdef __linux__
+static struct ff_effect ffeffect[3];
+static struct ff_effect ffstrong[3];
+static struct ff_effect ffweak[3];
+#endif //__linux__
+
+/* Global functions */
+void DebugMessage(int level, const char *message, ...)
+{
+ char msgbuf[1024];
+ va_list args;
+
+ if (l_DebugCallback == NULL)
+ return;
+
+ va_start(args, message);
+ vsprintf(msgbuf, message, args);
+
+ (*l_DebugCallback)(l_DebugCallContext, level, msgbuf);
+
+ va_end(args);
+}
+
+static CONTROL temp_core_controlinfo[4];
+
+/* Mupen64Plus plugin functions */
+EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context,
+ void (*DebugCallback)(void *, int, const char *))
+{
+ ptr_CoreGetAPIVersions CoreAPIVersionFunc;
+
+ int i, ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion;
+
+ if (l_PluginInit)
+ return M64ERR_ALREADY_INIT;
+
+ /* first thing is to set the callback function for debug info */
+ l_DebugCallback = DebugCallback;
+ l_DebugCallContext = Context;
+
+ /* attach and call the CoreGetAPIVersions function, check Config API version for compatibility */
+ CoreAPIVersionFunc = (ptr_CoreGetAPIVersions) osal_dynlib_getproc(CoreLibHandle, "CoreGetAPIVersions");
+ if (CoreAPIVersionFunc == NULL)
+ {
+ DebugMessage(M64MSG_ERROR, "Core emulator broken; no CoreAPIVersionFunc() function found.");
+ return M64ERR_INCOMPATIBLE;
+ }
+
+ (*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL);
+ if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000))
+ {
+ DebugMessage(M64MSG_ERROR, "Emulator core Config API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)",
+ VERSION_PRINTF_SPLIT(ConfigAPIVersion), VERSION_PRINTF_SPLIT(CONFIG_API_VERSION));
+ return M64ERR_INCOMPATIBLE;
+ }
+
+ /* Get the core config function pointers from the library handle */
+ ConfigOpenSection = (ptr_ConfigOpenSection) osal_dynlib_getproc(CoreLibHandle, "ConfigOpenSection");
+ ConfigDeleteSection = (ptr_ConfigDeleteSection) osal_dynlib_getproc(CoreLibHandle, "ConfigDeleteSection");
+ ConfigSetParameter = (ptr_ConfigSetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigSetParameter");
+ ConfigGetParameter = (ptr_ConfigGetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParameter");
+ ConfigSetDefaultInt = (ptr_ConfigSetDefaultInt) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultInt");
+ ConfigSetDefaultFloat = (ptr_ConfigSetDefaultFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultFloat");
+ ConfigSetDefaultBool = (ptr_ConfigSetDefaultBool) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultBool");
+ ConfigSetDefaultString = (ptr_ConfigSetDefaultString) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultString");
+ ConfigGetParamInt = (ptr_ConfigGetParamInt) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamInt");
+ ConfigGetParamFloat = (ptr_ConfigGetParamFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamFloat");
+ ConfigGetParamBool = (ptr_ConfigGetParamBool) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamBool");
+ ConfigGetParamString = (ptr_ConfigGetParamString) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamString");
+
+ ConfigGetSharedDataFilepath = (ptr_ConfigGetSharedDataFilepath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetSharedDataFilepath");
+ ConfigGetUserConfigPath = (ptr_ConfigGetUserConfigPath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserConfigPath");
+ ConfigGetUserDataPath = (ptr_ConfigGetUserDataPath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserDataPath");
+ ConfigGetUserCachePath = (ptr_ConfigGetUserCachePath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserCachePath");
+
+ if (!ConfigOpenSection || !ConfigDeleteSection || !ConfigSetParameter || !ConfigGetParameter ||
+ !ConfigSetDefaultInt || !ConfigSetDefaultFloat || !ConfigSetDefaultBool || !ConfigSetDefaultString ||
+ !ConfigGetParamInt || !ConfigGetParamFloat || !ConfigGetParamBool || !ConfigGetParamString ||
+ !ConfigGetSharedDataFilepath || !ConfigGetUserConfigPath || !ConfigGetUserDataPath || !ConfigGetUserCachePath)
+ {
+ DebugMessage(M64MSG_ERROR, "Couldn't connect to Core configuration functions");
+ return M64ERR_INCOMPATIBLE;
+ }
+
+ /* reset controllers */
+ memset(controller, 0, sizeof(SController) * 4);
+ for (i = 0; i < SDL_NUM_SCANCODES; i++)
+ {
+ myKeyState[i] = 0;
+ }
+ /* set CONTROL struct pointers to the temporary static array */
+ /* this small struct is used to tell the core whether each controller is plugged in, and what type of pak is connected */
+ /* we only need it so that we can call load_configuration below, to auto-config for a GUI front-end */
+ for (i = 0; i < 4; i++)
+ controller[i].control = temp_core_controlinfo + i;
+
+ l_PluginInit = 1;
+ return M64ERR_SUCCESS;
+}
+
+EXPORT m64p_error CALL PluginShutdown(void)
+{
+ if (!l_PluginInit)
+ return M64ERR_NOT_INIT;
+
+ /* reset some local variables */
+ l_DebugCallback = NULL;
+ l_DebugCallContext = NULL;
+
+ l_PluginInit = 0;
+ return M64ERR_SUCCESS;
+}
+
+EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)
+{
+ /* set version info */
+ if (PluginType != NULL)
+ *PluginType = M64PLUGIN_INPUT;
+
+ if (PluginVersion != NULL)
+ *PluginVersion = PLUGIN_VERSION;
+
+ if (APIVersion != NULL)
+ *APIVersion = INPUT_PLUGIN_API_VERSION;
+
+ if (PluginNamePtr != NULL)
+ *PluginNamePtr = PLUGIN_NAME;
+
+ if (Capabilities != NULL)
+ {
+ *Capabilities = 0;
+ }
+
+ return M64ERR_SUCCESS;
+}
+
+static unsigned char DataCRC( unsigned char *Data, int iLenght )
+{
+ unsigned char Remainder = Data[0];
+
+ int iByte = 1;
+ unsigned char bBit = 0;
+
+ while( iByte <= iLenght )
+ {
+ int HighBit = ((Remainder & 0x80) != 0);
+ Remainder = Remainder << 1;
+
+ Remainder += ( iByte < iLenght && Data[iByte] & (0x80 >> bBit )) ? 1 : 0;
+
+ Remainder ^= (HighBit) ? 0x85 : 0;
+
+ bBit++;
+ iByte += bBit/8;
+ bBit %= 8;
+ }
+
+ return Remainder;
+}
+
+/******************************************************************
+ Function: ControllerCommand
+ Purpose: To process the raw data that has just been sent to a
+ specific controller.
+ input: - Controller Number (0 to 3) and -1 signalling end of
+ processing the pif ram.
+ - Pointer of data to be processed.
+ output: none
+
+ note: This function is only needed if the DLL is allowing raw
+ data, or the plugin is set to raw
+
+ the data that is being processed looks like this:
+ initilize controller: 01 03 00 FF FF FF
+ read controller: 01 04 01 FF FF FF FF
+*******************************************************************/
+EXPORT void CALL ControllerCommand(int Control, unsigned char *Command)
+{
+ unsigned char *Data = &Command[5];
+
+ if (Control == -1)
+ return;
+
+ switch (Command[2])
+ {
+ case RD_GETSTATUS:
+#ifdef _DEBUG
+ DebugMessage(M64MSG_INFO, "Get status");
+#endif
+ break;
+ case RD_READKEYS:
+#ifdef _DEBUG
+ DebugMessage(M64MSG_INFO, "Read keys");
+#endif
+ break;
+ case RD_READPAK:
+#ifdef _DEBUG
+ DebugMessage(M64MSG_INFO, "Read pak");
+#endif
+ if (controller[Control].control->Plugin == PLUGIN_RAW)
+ {
+ unsigned int dwAddress = (Command[3] << 8) + (Command[4] & 0xE0);
+
+ if(( dwAddress >= 0x8000 ) && ( dwAddress < 0x9000 ) )
+ memset( Data, 0x80, 32 );
+ else
+ memset( Data, 0x00, 32 );
+
+ Data[32] = DataCRC( Data, 32 );
+ }
+ break;
+ case RD_WRITEPAK:
+#ifdef _DEBUG
+ DebugMessage(M64MSG_INFO, "Write pak");
+#endif
+ if (controller[Control].control->Plugin == PLUGIN_RAW)
+ {
+ unsigned int dwAddress = (Command[3] << 8) + (Command[4] & 0xE0);
+ if (dwAddress == PAK_IO_RUMBLE && *Data)
+ DebugMessage(M64MSG_VERBOSE, "Triggering rumble pack.");
+#ifdef __linux__
+ struct input_event play;
+ if( dwAddress == PAK_IO_RUMBLE && controller[Control].event_joystick != 0)
+ {
+ if( *Data )
+ {
+ play.type = EV_FF;
+ play.code = ffeffect[Control].id;
+ play.value = 1;
+
+ if (write(controller[Control].event_joystick, (const void*) &play, sizeof(play)) == -1)
+ perror("Error starting rumble effect");
+
+ }
+ else
+ {
+ play.type = EV_FF;
+ play.code = ffeffect[Control].id;
+ play.value = 0;
+
+ if (write(controller[Control].event_joystick, (const void*) &play, sizeof(play)) == -1)
+ perror("Error stopping rumble effect");
+ }
+ }
+#endif //__linux__
+ Data[32] = DataCRC( Data, 32 );
+ }
+ break;
+ case RD_RESETCONTROLLER:
+#ifdef _DEBUG
+ DebugMessage(M64MSG_INFO, "Reset controller");
+#endif
+ break;
+ case RD_READEEPROM:
+#ifdef _DEBUG
+ DebugMessage(M64MSG_INFO, "Read eeprom");
+#endif
+ break;
+ case RD_WRITEEPROM:
+#ifdef _DEBUG
+ DebugMessage(M64MSG_INFO, "Write eeprom");
+#endif
+ break;
+ }
+}
+
+/******************************************************************
+ Function: GetKeys
+ Purpose: To get the current state of the controllers buttons.
+ input: - Controller Number (0 to 3)
+ - A pointer to a BUTTONS structure to be filled with
+ the controller state.
+ output: none
+*******************************************************************/
+EXPORT void CALL GetKeys( int Control, BUTTONS *Keys )
+{
+ // Use a call back function here, or look up a buffer
+}
+
+/******************************************************************
+ Function: InitiateControllers
+ Purpose: This function initialises how each of the controllers
+ should be handled.
+ input: - The handle to the main window.
+ - A controller structure that needs to be filled for
+ the emulator to know how to handle each controller.
+ output: none
+*******************************************************************/
+EXPORT void CALL InitiateControllers(CONTROL_INFO ControlInfo)
+{
+ int i;
+
+ for( i = 0; i < 4; i++ )
+ {
+ controller[i].control->Plugin = PLUGIN_MEMPAK;
+ }
+
+ DebugMessage(M64MSG_INFO, "%s version %i.%i.%i initialized.", PLUGIN_NAME, VERSION_PRINTF_SPLIT(PLUGIN_VERSION));
+}
+
+/******************************************************************
+ Function: ReadController
+ Purpose: To process the raw data in the pif ram that is about to
+ be read.
+ input: - Controller Number (0 to 3) and -1 signalling end of
+ processing the pif ram.
+ - Pointer of data to be processed.
+ output: none
+ note: This function is only needed if the DLL is allowing raw
+ data.
+*******************************************************************/
+EXPORT void CALL ReadController(int Control, unsigned char *Command)
+{
+#ifdef _DEBUG
+ if (Command != NULL)
+ DebugMessage(M64MSG_INFO, "Raw Read (cont=%d): %02X %02X %02X %02X %02X %02X", Control,
+ Command[0], Command[1], Command[2], Command[3], Command[4], Command[5]);
+#endif
+}
+
+/******************************************************************
+ Function: RomClosed
+ Purpose: This function is called when a rom is closed.
+ input: none
+ output: none
+*******************************************************************/
+EXPORT void CALL RomClosed(void)
+{
+ romopen = 0;
+}
+
+/******************************************************************
+ Function: RomOpen
+ Purpose: This function is called when a rom is open. (from the
+ emulation thread)
+ input: none
+ output: none
+*******************************************************************/
+EXPORT int CALL RomOpen(void)
+{
+ romopen = 1;
+ return 1;
+}
+
+/******************************************************************
+ Function: SDL_KeyDown
+ Purpose: To pass the SDL_KeyDown message from the emulator to the
+ plugin.
+ input: keymod and keysym of the SDL_KEYDOWN message.
+ output: none
+*******************************************************************/
+EXPORT void CALL SDL_KeyDown(int keymod, int keysym)
+{
+}
+
+/******************************************************************
+ Function: SDL_KeyUp
+ Purpose: To pass the SDL_KeyUp message from the emulator to the
+ plugin.
+ input: keymod and keysym of the SDL_KEYUP message.
+ output: none
+*******************************************************************/
+EXPORT void CALL SDL_KeyUp(int keymod, int keysym)
+{
+}
+
diff --git a/libmupen64plus/mupen64plus-input-bkm/plugin.h b/libmupen64plus/mupen64plus-input-bkm/plugin.h
new file mode 100644
index 0000000000..882d422cbb
--- /dev/null
+++ b/libmupen64plus/mupen64plus-input-bkm/plugin.h
@@ -0,0 +1,175 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-input-sdl - plugin.h *
+ * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Copyright (C) 2008-2009 Richard Goedeken *
+ * Copyright (C) 2008 Tillin9 *
+ * Copyright (C) 2002 Blight *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef __PLUGIN_H__
+#define __PLUGIN_H__
+
+#include
+#if ! SDL_VERSION_ATLEAST(1,3,0)
+
+#define SDL_GetKeyboardState SDL_GetKeyState
+#define SDL_SCANCODE_UNKNOWN SDLK_UNKNOWN
+#define SDL_NUM_SCANCODES SDLK_LAST
+#define SDL_SCANCODE_RCTRL SDLK_RCTRL
+#define SDL_SCANCODE_RSHIFT SDLK_RSHIFT
+#define SDL_SCANCODE_LCTRL SDLK_LCTRL
+#define SDL_SCANCODE_LALT SDLK_LALT
+#define SDL_Scancode SDLKey
+
+#endif
+
+#if SDL_VERSION_ATLEAST(2,0,0)
+
+static inline const char* _SDL_JoystickName(int device_index)
+{
+ SDL_Joystick *joystick;
+ const char *name;
+ static char JoyName[256];
+
+ joystick = SDL_JoystickOpen(device_index);
+ if (!joystick)
+ return NULL;
+
+ name = SDL_JoystickName(joystick);
+ if (name)
+ {
+ strncpy(JoyName, name, 255);
+ JoyName[255] = 0;
+ }
+ SDL_JoystickClose(joystick);
+
+ return JoyName;
+}
+
+#define SDL_JoystickName(device_index) _SDL_JoystickName(device_index)
+
+#endif
+
+#define M64P_PLUGIN_PROTOTYPES 1
+#include "m64p_plugin.h"
+#include "m64p_config.h"
+
+#define DEVICE_AUTO (-1)
+#define DEVICE_NOT_JOYSTICK (-2)
+
+// Some stuff from n-rage plugin
+#define RD_GETSTATUS 0x00 // get status
+#define RD_READKEYS 0x01 // read button values
+#define RD_READPAK 0x02 // read from controllerpack
+#define RD_WRITEPAK 0x03 // write to controllerpack
+#define RD_RESETCONTROLLER 0xff // reset controller
+#define RD_READEEPROM 0x04 // read eeprom
+#define RD_WRITEEPROM 0x05 // write eeprom
+
+#define PAK_IO_RUMBLE 0xC000 // the address where rumble-commands are sent to
+
+enum EButton
+{
+ R_DPAD = 0,
+ L_DPAD,
+ D_DPAD,
+ U_DPAD,
+ START_BUTTON,
+ Z_TRIG,
+ B_BUTTON,
+ A_BUTTON,
+ R_CBUTTON,
+ L_CBUTTON,
+ D_CBUTTON,
+ U_CBUTTON,
+ R_TRIG,
+ L_TRIG,
+ MEMPAK,
+ RUMBLEPAK,
+ X_AXIS,
+ Y_AXIS,
+ NUM_BUTTONS
+};
+
+typedef struct
+{
+ int button; // button index; -1 if notassigned
+ SDL_Scancode key; // sdl keysym; SDL_SCANCODE_UNKNOWN if not assigned
+ int axis, axis_dir; // aixs + direction (i.e. 0, 1 = X Axis +; 0, -1 = X Axis -); -1 if notassigned
+ int axis_deadzone; // -1 for default, or >= 0 for custom value
+ int hat, hat_pos; // hat + hat position; -1 if not assigned
+ int mouse; // mouse button
+} SButtonMap;
+
+typedef struct
+{
+ int button_a, button_b; // up/down or left/right; -1 if not assigned
+ SDL_Scancode key_a, key_b; // up/down or left/right; SDL_SCANCODE_UNKNOWN if not assigned
+ int axis_a, axis_b; // axis index; -1 if not assigned
+ int axis_dir_a, axis_dir_b; // direction (1 = X+, 0, -1 = X-)
+ int hat, hat_pos_a, hat_pos_b; // hat + hat position up/down and left/right; -1 if not assigned
+} SAxisMap;
+
+typedef struct
+{
+ CONTROL *control; // pointer to CONTROL struct in Core library
+ BUTTONS buttons;
+
+ // mappings
+ SButtonMap button[16]; // 14 buttons; in the order of EButton + mempak/rumblepak switches
+ SAxisMap axis[2]; // 2 axis
+ int device; // joystick device; -1 = keyboard; -2 = none
+ int mouse; // mouse enabled: 0 = no; 1 = yes
+ SDL_Joystick *joystick; // SDL joystick device
+ int event_joystick; // the /dev/input/eventX device for force feeback
+ int axis_deadzone[2]; // minimum absolute value before analog movement is recognized
+ int axis_peak[2]; // highest analog value returned by SDL, used for scaling
+ float mouse_sens[2]; // mouse sensitivity
+} SController;
+
+/* global data definitions */
+extern SController controller[4]; // 4 controllers
+
+/* global function definitions */
+extern void DebugMessage(int level, const char *message, ...);
+
+/* declarations of pointers to Core config functions */
+extern ptr_ConfigListSections ConfigListSections;
+extern ptr_ConfigOpenSection ConfigOpenSection;
+extern ptr_ConfigDeleteSection ConfigDeleteSection;
+extern ptr_ConfigListParameters ConfigListParameters;
+extern ptr_ConfigSaveFile ConfigSaveFile;
+extern ptr_ConfigSetParameter ConfigSetParameter;
+extern ptr_ConfigGetParameter ConfigGetParameter;
+extern ptr_ConfigGetParameterHelp ConfigGetParameterHelp;
+extern ptr_ConfigSetDefaultInt ConfigSetDefaultInt;
+extern ptr_ConfigSetDefaultFloat ConfigSetDefaultFloat;
+extern ptr_ConfigSetDefaultBool ConfigSetDefaultBool;
+extern ptr_ConfigSetDefaultString ConfigSetDefaultString;
+extern ptr_ConfigGetParamInt ConfigGetParamInt;
+extern ptr_ConfigGetParamFloat ConfigGetParamFloat;
+extern ptr_ConfigGetParamBool ConfigGetParamBool;
+extern ptr_ConfigGetParamString ConfigGetParamString;
+
+extern ptr_ConfigGetSharedDataFilepath ConfigGetSharedDataFilepath;
+extern ptr_ConfigGetUserConfigPath ConfigGetUserConfigPath;
+extern ptr_ConfigGetUserDataPath ConfigGetUserDataPath;
+extern ptr_ConfigGetUserCachePath ConfigGetUserCachePath;
+
+#endif // __PLUGIN_H__
+
diff --git a/libmupen64plus/mupen64plus-input-bkm/version.h b/libmupen64plus/mupen64plus-input-bkm/version.h
new file mode 100644
index 0000000000..36dd9ce6ff
--- /dev/null
+++ b/libmupen64plus/mupen64plus-input-bkm/version.h
@@ -0,0 +1,37 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-input-sdl - version.h *
+ * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Copyright (C) 2009-2012 Richard Goedeken *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* This header file is for versioning information
+ *
+ */
+
+#if !defined(VERSION_H)
+#define VERSION_H
+
+#define PLUGIN_NAME "Mupen64Plus Bizhawk Input Plugin"
+#define PLUGIN_VERSION 0x016305
+#define INPUT_PLUGIN_API_VERSION 0x020000
+#define CONFIG_API_VERSION 0x020000
+
+#define VERSION_PRINTF_SPLIT(x) (((x) >> 16) & 0xffff), (((x) >> 8) & 0xff), ((x) & 0xff)
+
+#endif /* #define VERSION_H */
+
diff --git a/libmupen64plus/mupen64plus-ui-console/projects/msvc11/mupen64plus-ui-console.sln b/libmupen64plus/mupen64plus-ui-console/projects/msvc11/mupen64plus-ui-console.sln
index 305bedd73f..e550e4c3ec 100644
--- a/libmupen64plus/mupen64plus-ui-console/projects/msvc11/mupen64plus-ui-console.sln
+++ b/libmupen64plus/mupen64plus-ui-console/projects/msvc11/mupen64plus-ui-console.sln
@@ -16,6 +16,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mupen64plus-video-glide64mk
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mupen64plus-audio-bkm", "..\..\..\mupen64plus-audio-bkm\mupen64plus-audio-bkm\mupen64plus-audio-bkm.vcxproj", "{B6F20769-1385-4C0F-91A9-26F47AD1E78F}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mupen64plus-input-bkm", "..\..\..\mupen64plus-input-bkm\mupen64plus-input-bkm\mupen64plus-input-bkm.vcxproj", "{3D8BD211-6002-4698-B5C1-A0F3146B6ACF}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -54,6 +56,10 @@ Global
{B6F20769-1385-4C0F-91A9-26F47AD1E78F}.Debug|Win32.Build.0 = Debug|Win32
{B6F20769-1385-4C0F-91A9-26F47AD1E78F}.Release|Win32.ActiveCfg = Release|Win32
{B6F20769-1385-4C0F-91A9-26F47AD1E78F}.Release|Win32.Build.0 = Release|Win32
+ {3D8BD211-6002-4698-B5C1-A0F3146B6ACF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3D8BD211-6002-4698-B5C1-A0F3146B6ACF}.Debug|Win32.Build.0 = Debug|Win32
+ {3D8BD211-6002-4698-B5C1-A0F3146B6ACF}.Release|Win32.ActiveCfg = Release|Win32
+ {3D8BD211-6002-4698-B5C1-A0F3146B6ACF}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE