652 lines
17 KiB
C++
652 lines
17 KiB
C++
|
// Project description
|
||
|
// -------------------
|
||
|
// Name: nJoy
|
||
|
// Description: A Dolphin Compatible Input Plugin
|
||
|
//
|
||
|
// Author: Falcon4ever (nJoy@falcon4ever.com)
|
||
|
// Site: www.multigesture.net
|
||
|
// Copyright (C) 2003 Dolphin Project.
|
||
|
//
|
||
|
|
||
|
|
||
|
// Copyright (C) 2003 Dolphin Project.
|
||
|
|
||
|
// 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, version 2.0.
|
||
|
|
||
|
// 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 2.0 for more details.
|
||
|
|
||
|
// A copy of the GPL 2.0 should have been included with the program.
|
||
|
// If not, see http://www.gnu.org/licenses/
|
||
|
|
||
|
// Official SVN repository and contact information can be found at
|
||
|
// http://code.google.com/p/dolphin-emu/
|
||
|
|
||
|
|
||
|
#include "GCPad.h"
|
||
|
#include "Config.h"
|
||
|
#include "LogManager.h"
|
||
|
#if defined(HAVE_WX) && HAVE_WX
|
||
|
#include "ConfigBox.h"
|
||
|
#endif
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
#include "XInput.h"
|
||
|
#endif
|
||
|
|
||
|
// Declare config window so that we can write debugging info to it from functions in this file
|
||
|
#if defined(HAVE_WX) && HAVE_WX
|
||
|
GCPadConfigDialog* m_ConfigFrame = NULL;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
// Variables
|
||
|
// ---------
|
||
|
bool g_SearchDeviceDone = false;
|
||
|
CONTROLLER_MAPPING_GC GCMapping[4];
|
||
|
std::vector<InputCommon::CONTROLLER_INFO> joyinfo;
|
||
|
int NumPads = 0, NumGoodPads = 0, g_ID = 0;
|
||
|
#ifdef _WIN32
|
||
|
HWND m_hWnd = NULL; // Handle to window
|
||
|
#endif
|
||
|
#if defined(HAVE_X11) && HAVE_X11
|
||
|
Display* GCdisplay;
|
||
|
#endif
|
||
|
SPADInitialize *g_PADInitialize = NULL;
|
||
|
PLUGIN_GLOBALS* globals = NULL;
|
||
|
|
||
|
|
||
|
// Standard crap to make wxWidgets happy
|
||
|
#ifdef _WIN32
|
||
|
HINSTANCE g_hInstance;
|
||
|
|
||
|
#if defined(HAVE_WX) && HAVE_WX
|
||
|
class wxDLLApp : public wxApp
|
||
|
{
|
||
|
bool OnInit()
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
};
|
||
|
IMPLEMENT_APP_NO_MAIN(wxDLLApp)
|
||
|
WXDLLIMPEXP_BASE void wxSetInstance(HINSTANCE hInst);
|
||
|
#endif
|
||
|
|
||
|
BOOL APIENTRY DllMain(HINSTANCE hinstDLL, // DLL module handle
|
||
|
DWORD dwReason, // reason called
|
||
|
LPVOID lpvReserved) // reserved
|
||
|
{
|
||
|
switch (dwReason)
|
||
|
{
|
||
|
case DLL_PROCESS_ATTACH:
|
||
|
{
|
||
|
#if defined(HAVE_WX) && HAVE_WX
|
||
|
wxSetInstance((HINSTANCE)hinstDLL);
|
||
|
wxInitialize();
|
||
|
#endif
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case DLL_PROCESS_DETACH:
|
||
|
#if defined(HAVE_WX) && HAVE_WX
|
||
|
wxUninitialize();
|
||
|
#endif
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
g_hInstance = hinstDLL;
|
||
|
return TRUE;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if defined(HAVE_WX) && HAVE_WX
|
||
|
wxWindow* GetParentedWxWindow(HWND Parent)
|
||
|
{
|
||
|
#ifdef _WIN32
|
||
|
wxSetInstance((HINSTANCE)g_hInstance);
|
||
|
#endif
|
||
|
wxWindow *win = new wxWindow();
|
||
|
#ifdef _WIN32
|
||
|
win->SetHWND((WXHWND)Parent);
|
||
|
win->AdoptAttributesFromHWND();
|
||
|
#endif
|
||
|
return win;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
// Input Plugin Functions (from spec's)
|
||
|
// ------------------------------------
|
||
|
|
||
|
// Get properties of plugin
|
||
|
// ------------------------
|
||
|
void GetDllInfo(PLUGIN_INFO* _PluginInfo)
|
||
|
{
|
||
|
_PluginInfo->Version = 0x0100;
|
||
|
_PluginInfo->Type = PLUGIN_TYPE_PAD;
|
||
|
|
||
|
#ifdef DEBUGFAST
|
||
|
sprintf(_PluginInfo->Name, "Dolphin GCPad Plugin (DebugFast)");
|
||
|
#else
|
||
|
#ifdef _DEBUG
|
||
|
sprintf(_PluginInfo->Name, "Dolphin GCPad Plugin (Debug)");
|
||
|
#else
|
||
|
sprintf(_PluginInfo->Name, "Dolphin GCPad Plugin");
|
||
|
#endif
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void SetDllGlobals(PLUGIN_GLOBALS* _pPluginGlobals)
|
||
|
{
|
||
|
globals = _pPluginGlobals;
|
||
|
LogManager::SetInstance((LogManager *)globals->logManager);
|
||
|
}
|
||
|
|
||
|
|
||
|
// Call config dialog
|
||
|
// ------------------
|
||
|
void DllConfig(HWND _hParent)
|
||
|
{
|
||
|
if (!g_SearchDeviceDone)
|
||
|
{
|
||
|
g_Config.Load(); // load settings
|
||
|
// Init Joystick + Haptic (force feedback) subsystem on SDL 1.3
|
||
|
// Populate joyinfo for all attached devices
|
||
|
Search_Devices(joyinfo, NumPads, NumGoodPads);
|
||
|
g_SearchDeviceDone = true;
|
||
|
}
|
||
|
|
||
|
#if defined(HAVE_WX) && HAVE_WX
|
||
|
wxWindow *frame = GetParentedWxWindow(_hParent);
|
||
|
m_ConfigFrame = new GCPadConfigDialog(frame);
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
frame->Disable();
|
||
|
m_ConfigFrame->ShowModal();
|
||
|
frame->Enable();
|
||
|
#else
|
||
|
m_ConfigFrame->ShowModal();
|
||
|
#endif
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
frame->SetFocus();
|
||
|
frame->SetHWND(NULL);
|
||
|
#endif
|
||
|
|
||
|
m_ConfigFrame->Destroy();
|
||
|
m_ConfigFrame = NULL;
|
||
|
frame->Destroy();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void DllDebugger(HWND _hParent, bool Show)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
// Init PAD (start emulation)
|
||
|
// --------------------------
|
||
|
void Initialize(void *init)
|
||
|
{
|
||
|
INFO_LOG(PAD, "Initialize: %i", SDL_WasInit(0));
|
||
|
g_PADInitialize = (SPADInitialize*)init;
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
m_hWnd = (HWND)g_PADInitialize->hWnd;
|
||
|
#endif
|
||
|
#if defined(HAVE_X11) && HAVE_X11
|
||
|
GCdisplay = (Display*)g_PADInitialize->hWnd;
|
||
|
#endif
|
||
|
|
||
|
if (!g_SearchDeviceDone)
|
||
|
{
|
||
|
g_Config.Load(); // load settings
|
||
|
// Populate joyinfo for all attached devices
|
||
|
Search_Devices(joyinfo, NumPads, NumGoodPads);
|
||
|
g_SearchDeviceDone = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Shutdown PAD (stop emulation)
|
||
|
// -----------------------------
|
||
|
void Shutdown()
|
||
|
{
|
||
|
INFO_LOG(PAD, "Shutdown: %i", SDL_WasInit(0));
|
||
|
|
||
|
Close_Devices();
|
||
|
|
||
|
// Finally close SDL
|
||
|
if (SDL_WasInit(0))
|
||
|
{
|
||
|
SDL_Quit();
|
||
|
}
|
||
|
|
||
|
// Remove the pointer to the initialize data
|
||
|
g_PADInitialize = NULL;
|
||
|
g_SearchDeviceDone = false;
|
||
|
}
|
||
|
|
||
|
// Save state
|
||
|
// --------------
|
||
|
void DoState(unsigned char **ptr, int mode)
|
||
|
{
|
||
|
#ifdef RERECORDING
|
||
|
Recording::DoState(ptr, mode);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void EmuStateChange(PLUGIN_EMUSTATE newState)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
// Set buttons status from keyboard input. Currently this is done from wxWidgets in the main application.
|
||
|
// --------------
|
||
|
void PAD_Input(u16 _Key, u8 _UpDown)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
// Set PAD status
|
||
|
// --------------
|
||
|
// Called from: SI_DeviceGCController.cpp
|
||
|
// Function: Gives the current pad status to the Core
|
||
|
void PAD_GetStatus(u8 _numPAD, SPADStatus* _pPADStatus)
|
||
|
{
|
||
|
// Check if all is okay
|
||
|
if (_pPADStatus == NULL) return;
|
||
|
|
||
|
// Clear pad
|
||
|
memset(_pPADStatus, 0, sizeof(SPADStatus));
|
||
|
const int base = 0x80;
|
||
|
_pPADStatus->stickX = base;
|
||
|
_pPADStatus->stickY = base;
|
||
|
_pPADStatus->substickX = base;
|
||
|
_pPADStatus->substickY = base;
|
||
|
_pPADStatus->button |= PAD_USE_ORIGIN;
|
||
|
_pPADStatus->err = PAD_ERR_NONE;
|
||
|
|
||
|
// Check that Dolphin is in focus, otherwise don't update the pad status
|
||
|
if (!IsFocus()) return;
|
||
|
|
||
|
g_ID = _numPAD;
|
||
|
|
||
|
if (NumGoodPads && NumPads > GCMapping[_numPAD].ID)
|
||
|
UpdatePadState(GCMapping[_numPAD]);
|
||
|
|
||
|
if (IsKey(EGC_A))
|
||
|
{
|
||
|
_pPADStatus->button |= PAD_BUTTON_A;
|
||
|
_pPADStatus->analogA = DEF_BUTTON_FULL;
|
||
|
}
|
||
|
if (IsKey(EGC_B))
|
||
|
{
|
||
|
_pPADStatus->button |= PAD_BUTTON_B;
|
||
|
_pPADStatus->analogB = DEF_BUTTON_FULL;
|
||
|
}
|
||
|
if (IsKey(EGC_X)) _pPADStatus->button |= PAD_BUTTON_X;
|
||
|
if (IsKey(EGC_Y)) _pPADStatus->button |= PAD_BUTTON_Y;
|
||
|
if (IsKey(EGC_Z)) _pPADStatus->button |= PAD_TRIGGER_Z;
|
||
|
if (IsKey(EGC_START)) _pPADStatus->button |= PAD_BUTTON_START;
|
||
|
if (IsKey(EGC_DPAD_UP)) _pPADStatus->button |= PAD_BUTTON_UP;
|
||
|
if (IsKey(EGC_DPAD_DOWN)) _pPADStatus->button |= PAD_BUTTON_DOWN;
|
||
|
if (IsKey(EGC_DPAD_LEFT)) _pPADStatus->button |= PAD_BUTTON_LEFT;
|
||
|
if (IsKey(EGC_DPAD_RIGHT)) _pPADStatus->button |= PAD_BUTTON_RIGHT;
|
||
|
|
||
|
if (GCMapping[_numPAD].Stick.Main == FROM_KEYBOARD)
|
||
|
{
|
||
|
int iMagnitude = DEF_STICK_FULL;
|
||
|
bool bUp = false;
|
||
|
bool bDown = false;
|
||
|
bool bLeft = false;
|
||
|
bool bRight = false;
|
||
|
if (IsKey(EGC_STICK_SEMI)) iMagnitude = GCMapping[_numPAD].Pressure.Main;
|
||
|
if (IsKey(EGC_STICK_UP)) bUp = true;
|
||
|
else if (IsKey(EGC_STICK_DOWN)) bDown = true;
|
||
|
if (IsKey(EGC_STICK_LEFT)) bLeft = true;
|
||
|
else if (IsKey(EGC_STICK_RIGHT)) bRight = true;
|
||
|
EmulateAnalogStick(_pPADStatus->stickX, _pPADStatus->stickY, bUp, bDown, bLeft, bRight, iMagnitude);
|
||
|
}
|
||
|
else if (GCMapping[_numPAD].Stick.Main == FROM_ANALOG1)
|
||
|
{
|
||
|
_pPADStatus->stickX = GCMapping[_numPAD].AxisState.Lx;
|
||
|
// Y-axis is inverted
|
||
|
_pPADStatus->stickY = 0xFF - (u8)GCMapping[_numPAD].AxisState.Ly;
|
||
|
}
|
||
|
else if (GCMapping[_numPAD].Stick.Main == FROM_ANALOG2)
|
||
|
{
|
||
|
_pPADStatus->stickX = GCMapping[_numPAD].AxisState.Rx;
|
||
|
// Y-axis is inverted
|
||
|
_pPADStatus->stickY = 0xFF - (u8)GCMapping[_numPAD].AxisState.Ry;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_pPADStatus->stickX = GCMapping[_numPAD].AxisState.Tl;
|
||
|
_pPADStatus->stickY = GCMapping[_numPAD].AxisState.Tr;
|
||
|
}
|
||
|
|
||
|
if (GCMapping[_numPAD].Stick.Sub == FROM_KEYBOARD)
|
||
|
{
|
||
|
int iMagnitude = DEF_STICK_FULL;
|
||
|
bool bUp = false;
|
||
|
bool bDown = false;
|
||
|
bool bLeft = false;
|
||
|
bool bRight = false;
|
||
|
if (IsKey(EGC_CSTICK_SEMI)) iMagnitude = GCMapping[_numPAD].Pressure.Sub;
|
||
|
if (IsKey(EGC_CSTICK_UP)) bUp = true;
|
||
|
else if (IsKey(EGC_CSTICK_DOWN)) bDown = true;
|
||
|
if (IsKey(EGC_CSTICK_LEFT)) bLeft = true;
|
||
|
else if (IsKey(EGC_CSTICK_RIGHT)) bRight = true;
|
||
|
EmulateAnalogStick(_pPADStatus->substickX, _pPADStatus->substickY, bUp, bDown, bLeft, bRight, iMagnitude);
|
||
|
}
|
||
|
else if (GCMapping[_numPAD].Stick.Sub == FROM_ANALOG1)
|
||
|
{
|
||
|
_pPADStatus->substickX = GCMapping[_numPAD].AxisState.Lx;
|
||
|
// Y-axis is inverted
|
||
|
_pPADStatus->substickY = 0xFF - (u8)GCMapping[_numPAD].AxisState.Ly;
|
||
|
}
|
||
|
else if (GCMapping[_numPAD].Stick.Sub == FROM_ANALOG2)
|
||
|
{
|
||
|
_pPADStatus->substickX = GCMapping[_numPAD].AxisState.Rx;
|
||
|
// Y-axis is inverted
|
||
|
_pPADStatus->substickY = 0xFF - (u8)GCMapping[_numPAD].AxisState.Ry;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_pPADStatus->substickX = GCMapping[_numPAD].AxisState.Tl;
|
||
|
_pPADStatus->substickY = GCMapping[_numPAD].AxisState.Tr;
|
||
|
}
|
||
|
|
||
|
if (GCMapping[_numPAD].Stick.Shoulder == FROM_KEYBOARD)
|
||
|
{
|
||
|
if (IsKey(EGC_TGR_L))
|
||
|
{
|
||
|
_pPADStatus->triggerLeft = DEF_TRIGGER_FULL;
|
||
|
_pPADStatus->button |= PAD_TRIGGER_L;
|
||
|
}
|
||
|
else if (IsKey(EGC_TGR_SEMI_L))
|
||
|
{
|
||
|
_pPADStatus->triggerLeft = GCMapping[_numPAD].Pressure.Shoulder;
|
||
|
if (_pPADStatus->triggerLeft > DEF_TRIGGER_THRESHOLD)
|
||
|
_pPADStatus->button |= PAD_TRIGGER_L;
|
||
|
}
|
||
|
|
||
|
if (IsKey(EGC_TGR_R))
|
||
|
{
|
||
|
_pPADStatus->triggerRight = DEF_TRIGGER_FULL;
|
||
|
_pPADStatus->button |= PAD_TRIGGER_R;
|
||
|
}
|
||
|
else if (IsKey(EGC_TGR_SEMI_R))
|
||
|
{
|
||
|
_pPADStatus->triggerRight = GCMapping[_numPAD].Pressure.Shoulder;
|
||
|
if (_pPADStatus->triggerRight > DEF_TRIGGER_THRESHOLD)
|
||
|
_pPADStatus->button |= PAD_TRIGGER_R;
|
||
|
}
|
||
|
}
|
||
|
else if (GCMapping[_numPAD].Stick.Shoulder == FROM_ANALOG1)
|
||
|
{
|
||
|
_pPADStatus->triggerLeft = GCMapping[_numPAD].AxisState.Lx;
|
||
|
_pPADStatus->triggerRight = GCMapping[_numPAD].AxisState.Ly;
|
||
|
EmulateAnalogTrigger(_pPADStatus->triggerLeft, _pPADStatus->triggerRight);
|
||
|
if (_pPADStatus->triggerLeft > DEF_TRIGGER_THRESHOLD)
|
||
|
_pPADStatus->button |= PAD_TRIGGER_L;
|
||
|
if (_pPADStatus->triggerRight > DEF_TRIGGER_THRESHOLD)
|
||
|
_pPADStatus->button |= PAD_TRIGGER_R;
|
||
|
}
|
||
|
else if (GCMapping[_numPAD].Stick.Shoulder == FROM_ANALOG2)
|
||
|
{
|
||
|
_pPADStatus->triggerLeft = GCMapping[_numPAD].AxisState.Rx;
|
||
|
_pPADStatus->triggerRight = GCMapping[_numPAD].AxisState.Ry;
|
||
|
EmulateAnalogTrigger(_pPADStatus->triggerLeft, _pPADStatus->triggerRight);
|
||
|
if (_pPADStatus->triggerLeft > DEF_TRIGGER_THRESHOLD)
|
||
|
_pPADStatus->button |= PAD_TRIGGER_L;
|
||
|
if (_pPADStatus->triggerRight > DEF_TRIGGER_THRESHOLD)
|
||
|
_pPADStatus->button |= PAD_TRIGGER_R;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_pPADStatus->triggerLeft = GCMapping[_numPAD].AxisState.Tl;
|
||
|
_pPADStatus->triggerRight = GCMapping[_numPAD].AxisState.Tr;
|
||
|
EmulateAnalogTrigger(_pPADStatus->triggerLeft, _pPADStatus->triggerRight);
|
||
|
if (_pPADStatus->triggerLeft > DEF_TRIGGER_THRESHOLD)
|
||
|
_pPADStatus->button |= PAD_TRIGGER_L;
|
||
|
if (_pPADStatus->triggerRight > DEF_TRIGGER_THRESHOLD)
|
||
|
_pPADStatus->button |= PAD_TRIGGER_R;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
//******************************************************************************
|
||
|
// Supporting functions
|
||
|
//******************************************************************************
|
||
|
|
||
|
// for same displacement should be sqrt(2)/2 (in theory)
|
||
|
// 3/4 = 0.75 is a little faster than sqrt(2)/2 = 0.7071...
|
||
|
// In SMS, 17/20 = 0.85 is perfect; in WW, 7/10 = 0.70 is closer.
|
||
|
#define DIAGONAL_SCALE 0.70710678
|
||
|
void EmulateAnalogStick(unsigned char &stickX, unsigned char &stickY, bool buttonUp, bool buttonDown, bool buttonLeft, bool buttonRight, int magnitude)
|
||
|
{
|
||
|
int mainX = 0;
|
||
|
int mainY = 0;
|
||
|
if (buttonUp)
|
||
|
mainY = magnitude;
|
||
|
else if (buttonDown)
|
||
|
mainY = -magnitude;
|
||
|
if (buttonLeft)
|
||
|
mainX = -magnitude;
|
||
|
else if (buttonRight)
|
||
|
mainX = magnitude;
|
||
|
|
||
|
if ((mainX == 0) || (mainY == 0))
|
||
|
{
|
||
|
stickX += mainX;
|
||
|
stickY += mainY;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
stickX += mainX * DIAGONAL_SCALE;
|
||
|
stickY += mainY * DIAGONAL_SCALE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void EmulateAnalogTrigger(unsigned char &trL, unsigned char &trR)
|
||
|
{
|
||
|
if (GCMapping[g_ID].TriggerType == InputCommon::CTL_TRIGGER_SDL)
|
||
|
{
|
||
|
int triggerL = abs((int)trL - 0x80) * 2;
|
||
|
int triggerR = abs((int)trR - 0x80) * 2;
|
||
|
trL = (triggerL > 0xFF) ? 0xFF : triggerL;
|
||
|
trR = (triggerR > 0xFF) ? 0xFF : triggerR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Close_Devices()
|
||
|
{
|
||
|
PAD_RumbleClose();
|
||
|
|
||
|
if (SDL_WasInit(0))
|
||
|
{
|
||
|
for (int i = 0; i < NumPads; i++)
|
||
|
{
|
||
|
if (joyinfo.at(i).joy)
|
||
|
{
|
||
|
if(SDL_JoystickOpened(i))
|
||
|
{
|
||
|
INFO_LOG(WIIMOTE, "Shut down Joypad: %i", i);
|
||
|
SDL_JoystickClose(joyinfo.at(i).joy);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < 4; i++)
|
||
|
GCMapping[i].joy = NULL;
|
||
|
|
||
|
// Clear the physical device info
|
||
|
joyinfo.clear();
|
||
|
NumPads = 0;
|
||
|
NumGoodPads = 0;
|
||
|
}
|
||
|
|
||
|
// Search for SDL devices
|
||
|
// ----------------
|
||
|
bool Search_Devices(std::vector<InputCommon::CONTROLLER_INFO> &_joyinfo, int &_NumPads, int &_NumGoodPads)
|
||
|
{
|
||
|
// Close opened devices first
|
||
|
Close_Devices();
|
||
|
|
||
|
bool success = InputCommon::SearchDevices(_joyinfo, _NumPads, _NumGoodPads);
|
||
|
|
||
|
if (_NumGoodPads == 0)
|
||
|
return false;
|
||
|
|
||
|
for (int i = 0; i < 4; i++)
|
||
|
{
|
||
|
if (_NumPads > GCMapping[i].ID)
|
||
|
if(joyinfo.at(GCMapping[i].ID).Good)
|
||
|
{
|
||
|
GCMapping[i].joy = joyinfo.at(GCMapping[i].ID).joy;
|
||
|
#ifdef _WIN32
|
||
|
XINPUT_STATE xstate;
|
||
|
DWORD xresult = XInputGetState(GCMapping[i].ID, &xstate);
|
||
|
if (xresult == ERROR_SUCCESS)
|
||
|
GCMapping[i].TriggerType = InputCommon::CTL_TRIGGER_XINPUT;
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return success;
|
||
|
}
|
||
|
|
||
|
void GetAxisState(CONTROLLER_MAPPING_GC &_GCMapping)
|
||
|
{
|
||
|
// Update the gamepad status
|
||
|
SDL_JoystickUpdate();
|
||
|
|
||
|
// Update axis states. It doesn't hurt much if we happen to ask for nonexisting axises here.
|
||
|
_GCMapping.AxisState.Lx = SDL_JoystickGetAxis(_GCMapping.joy, _GCMapping.AxisMapping.Lx);
|
||
|
_GCMapping.AxisState.Ly = SDL_JoystickGetAxis(_GCMapping.joy, _GCMapping.AxisMapping.Ly);
|
||
|
_GCMapping.AxisState.Rx = SDL_JoystickGetAxis(_GCMapping.joy, _GCMapping.AxisMapping.Rx);
|
||
|
_GCMapping.AxisState.Ry = SDL_JoystickGetAxis(_GCMapping.joy, _GCMapping.AxisMapping.Ry);
|
||
|
|
||
|
// Update the analog trigger axis values
|
||
|
#ifdef _WIN32
|
||
|
if (_GCMapping.TriggerType == InputCommon::CTL_TRIGGER_SDL)
|
||
|
{
|
||
|
#endif
|
||
|
// If we are using SDL analog triggers the buttons have to be mapped as 1000 or up, otherwise they are not used
|
||
|
// We must also check that we are not asking for a negative axis number because SDL_JoystickGetAxis() has
|
||
|
// no good way of handling that
|
||
|
if ((_GCMapping.AxisMapping.Tl - 1000) >= 0)
|
||
|
_GCMapping.AxisState.Tl = SDL_JoystickGetAxis(_GCMapping.joy, _GCMapping.AxisMapping.Tl - 1000);
|
||
|
if ((_GCMapping.AxisMapping.Tr - 1000) >= 0)
|
||
|
_GCMapping.AxisState.Tr = SDL_JoystickGetAxis(_GCMapping.joy, _GCMapping.AxisMapping.Tr - 1000);
|
||
|
#ifdef _WIN32
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_GCMapping.AxisState.Tl = XInput::GetXI(_GCMapping.ID, _GCMapping.AxisMapping.Tl - 1000);
|
||
|
_GCMapping.AxisState.Tr = XInput::GetXI(_GCMapping.ID, _GCMapping.AxisMapping.Tr - 1000);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void UpdatePadState(CONTROLLER_MAPPING_GC &_GCiMapping)
|
||
|
{
|
||
|
// Return if we have no pads
|
||
|
if (NumGoodPads == 0) return;
|
||
|
|
||
|
GetAxisState(_GCiMapping);
|
||
|
|
||
|
int &Lx = _GCiMapping.AxisState.Lx;
|
||
|
int &Ly = _GCiMapping.AxisState.Ly;
|
||
|
int &Rx = _GCiMapping.AxisState.Rx;
|
||
|
int &Ry = _GCiMapping.AxisState.Ry;
|
||
|
int &Tl = _GCiMapping.AxisState.Tl;
|
||
|
int &Tr = _GCiMapping.AxisState.Tr;
|
||
|
|
||
|
// Check the circle to square option
|
||
|
if(_GCiMapping.bSquare2Circle)
|
||
|
{
|
||
|
InputCommon::Square2Circle(Lx, Ly, _GCiMapping.Diagonal, false);
|
||
|
InputCommon::Square2Circle(Rx, Ry, _GCiMapping.Diagonal, false);
|
||
|
}
|
||
|
|
||
|
// Dead zone adjustment
|
||
|
float DeadZoneLeft = (float)_GCiMapping.DeadZoneL / 100.0f;
|
||
|
float DeadZoneRight = (float)_GCiMapping.DeadZoneR / 100.0f;
|
||
|
if (InputCommon::IsDeadZone(DeadZoneLeft, Lx, Ly))
|
||
|
{
|
||
|
Lx = 0;
|
||
|
Ly = 0;
|
||
|
}
|
||
|
if (InputCommon::IsDeadZone(DeadZoneRight, Rx, Ry))
|
||
|
{
|
||
|
Rx = 0;
|
||
|
Ry = 0;
|
||
|
}
|
||
|
|
||
|
// Downsize the values from 0x8000 to 0x80
|
||
|
Lx = InputCommon::Pad_Convert(Lx);
|
||
|
Ly = InputCommon::Pad_Convert(Ly);
|
||
|
Rx = InputCommon::Pad_Convert(Rx);
|
||
|
Ry = InputCommon::Pad_Convert(Ry);
|
||
|
// The XInput range is already 0 to 0x80
|
||
|
if (_GCiMapping.TriggerType == InputCommon::CTL_TRIGGER_SDL)
|
||
|
{
|
||
|
Tl = InputCommon::Pad_Convert(Tl);
|
||
|
Tr = InputCommon::Pad_Convert(Tr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Multi System Input Status Check
|
||
|
bool IsKey(int Key)
|
||
|
{
|
||
|
int Ret = NULL;
|
||
|
int MapKey = GCMapping[g_ID].Button[Key];
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
if (MapKey < 256)
|
||
|
{
|
||
|
Ret = GetAsyncKeyState(MapKey); // Keyboard (Windows)
|
||
|
}
|
||
|
else if (MapKey < 0x1100)
|
||
|
#elif defined HAVE_X11 && HAVE_X11
|
||
|
if (MapKey < 256 || MapKey > 0xf000)
|
||
|
{
|
||
|
char keys[32];
|
||
|
KeyCode keyCode;
|
||
|
XQueryKeymap(GCdisplay, keys);
|
||
|
keyCode = XKeysymToKeycode(GCdisplay, MapKey);
|
||
|
Ret = (keys[keyCode/8] & (1 << (keyCode%8))); // Keyboard (Linux)
|
||
|
}
|
||
|
else if (MapKey < 0x1100)
|
||
|
#else
|
||
|
if (MapKey < 0x1100)
|
||
|
#endif
|
||
|
{
|
||
|
Ret = SDL_JoystickGetButton(GCMapping[g_ID].joy, MapKey - 0x1000); // Pad button
|
||
|
}
|
||
|
else // Pad hat
|
||
|
{
|
||
|
u8 HatCode, HatKey;
|
||
|
HatCode = SDL_JoystickGetHat(GCMapping[g_ID].joy, (MapKey - 0x1100) / 0x0010);
|
||
|
HatKey = (MapKey - 0x1100) % 0x0010;
|
||
|
|
||
|
if (HatCode & HatKey)
|
||
|
Ret = HatKey;
|
||
|
}
|
||
|
|
||
|
return (Ret) ? true : false;
|
||
|
}
|
||
|
|
||
|
// Check if Dolphin is in focus
|
||
|
// ----------------
|
||
|
bool IsFocus()
|
||
|
{
|
||
|
return g_PADInitialize->pRendererHasFocus();
|
||
|
}
|