mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-05-19 10:34:53 +00:00
Removed X event loops from GCPad and Wiimote plugins, and implemented an asynchronous check for keyboard and mouse buttons. Also added an X event loop in core that handles events while the emulator is paused. Prevents unexpected behavior from events that occur while the emulator is paused. Now there is only one event loop running at a time (besides those hidden in SDL). I will revert this commit if other devs are unhappy with it. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5048 8ced0084-cf51-0410-be5f-012b33b47a6e
652 lines
18 KiB
C++
652 lines
18 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);
|
|
int argc = 0;
|
|
char **argv = NULL;
|
|
wxEntryStart(argc, argv);
|
|
if (!wxTheApp || !wxTheApp->CallOnInit())
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
#if defined(HAVE_WX) && HAVE_WX
|
|
wxEntryCleanup();
|
|
#endif
|
|
break;
|
|
default:
|
|
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
|
|
if (!m_ConfigFrame)
|
|
{
|
|
m_ConfigFrame = new GCPadConfigDialog(GetParentedWxWindow(_hParent));
|
|
m_ConfigFrame->ShowModal();
|
|
m_ConfigFrame->Destroy();
|
|
m_ConfigFrame = NULL;
|
|
}
|
|
#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 < 256 || MapKey > 0xf000)
|
|
{
|
|
char keys[32];
|
|
KeyCode keyCode;
|
|
XQueryKeymap(GCdisplay, keys);
|
|
keyCode = XKeysymToKeycode(GCdisplay, MapKey);
|
|
Ret = (keys[keyCode/8] & (1 << (keyCode%8))); // Keyboard (Linux)
|
|
#endif
|
|
}
|
|
else if (MapKey < 0x1100)
|
|
{
|
|
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()
|
|
{
|
|
#ifdef _WIN32
|
|
HWND RenderingWindow = (g_PADInitialize) ? g_PADInitialize->hWnd : NULL;
|
|
HWND Parent = GetParent(RenderingWindow);
|
|
HWND TopLevel = GetParent(Parent);
|
|
|
|
if (GetForegroundWindow() == TopLevel || GetForegroundWindow() == RenderingWindow)
|
|
return true;
|
|
else
|
|
return false;
|
|
#else
|
|
return true;
|
|
#endif
|
|
}
|