forked from dolphin-emu/dolphin
		
	git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3656 8ced0084-cf51-0410-be5f-012b33b47a6e
		
			
				
	
	
		
			993 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			993 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// Copyright (C) 2003-2008 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
 | 
						|
#include <stdio.h>
 | 
						|
#include <math.h>
 | 
						|
 | 
						|
#include "Common.h"
 | 
						|
#include "pluginspecs_pad.h"
 | 
						|
#include "PadSimple.h"
 | 
						|
#include "IniFile.h"
 | 
						|
#include "StringUtil.h"
 | 
						|
#include "FileUtil.h"
 | 
						|
#include "ChunkFile.h"
 | 
						|
 | 
						|
#if defined(HAVE_WX) && HAVE_WX
 | 
						|
	#include "GUI/ConfigDlg.h"
 | 
						|
	PADConfigDialogSimple* m_ConfigFrame = NULL;
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef _WIN32
 | 
						|
	#include "XInput.h"
 | 
						|
	#include "../../../Core/InputCommon/Src/DirectInputBase.h" // Core
 | 
						|
 | 
						|
	DInput dinput;
 | 
						|
	//#elif defined(USE_SDL) && USE_SDL
 | 
						|
	//#include <SDL.h>
 | 
						|
 | 
						|
#elif defined(HAVE_X11) && HAVE_X11
 | 
						|
 | 
						|
	#include <X11/Xlib.h>
 | 
						|
	#include <X11/Xutil.h>
 | 
						|
	#include <X11/keysym.h>
 | 
						|
	#include <X11/XKBlib.h>
 | 
						|
 | 
						|
	Display* GXdsp;
 | 
						|
	bool KeyStatus[NUMCONTROLS];
 | 
						|
#elif defined(HAVE_COCOA) && HAVE_COCOA
 | 
						|
	#include <Cocoa/Cocoa.h>
 | 
						|
	bool KeyStatus[NUMCONTROLS];
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
//////////////////////////////////////////////////////////////////////////
 | 
						|
// Declarations
 | 
						|
SPads pad[4];
 | 
						|
SPADInitialize g_PADInitialize;
 | 
						|
 | 
						|
//////////////////////////////////////////////////////////////////////////
 | 
						|
// 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 Recording
 | 
						|
 | 
						|
// Enable these to record or play back
 | 
						|
//#define RECORD_REPLAY
 | 
						|
//#define RECORD_STORE
 | 
						|
 | 
						|
// Pre defined maxium storage limit
 | 
						|
#define RECORD_SIZE (1024 * 128)
 | 
						|
PLUGIN_GLOBALS* globals = NULL;
 | 
						|
SPADStatus recordBuffer[RECORD_SIZE];
 | 
						|
int count = 0;
 | 
						|
bool g_EmulatorRunning = false;
 | 
						|
 | 
						|
//******************************************************************************
 | 
						|
// Supporting functions
 | 
						|
//******************************************************************************
 | 
						|
 | 
						|
void RecordInput(const SPADStatus& _rPADStatus)
 | 
						|
{
 | 
						|
	if (count >= RECORD_SIZE) return;
 | 
						|
	recordBuffer[count++] = _rPADStatus;
 | 
						|
 | 
						|
	// Logging
 | 
						|
	//u8 TmpData[sizeof(SPADStatus)];
 | 
						|
	//memcpy(TmpData, &recordBuffer[count - 1], sizeof(SPADStatus));
 | 
						|
	//Console::Print("RecordInput(%i): %s\n", count, ArrayToString(TmpData, sizeof(SPADStatus), 0, 30).c_str());
 | 
						|
 | 
						|
	// Auto save every ten seconds
 | 
						|
	if (count % (60 * 10) == 0) SaveRecord();
 | 
						|
}
 | 
						|
 | 
						|
const SPADStatus& PlayRecord()
 | 
						|
{
 | 
						|
	// Logging
 | 
						|
	//Console::Print("PlayRecord(%i)\n", count);
 | 
						|
 | 
						|
	if (count >= RECORD_SIZE)
 | 
						|
	{
 | 
						|
		// Todo: Make the recording size unlimited?
 | 
						|
		//PanicAlert("The recording reached its end");
 | 
						|
		return(recordBuffer[0]);
 | 
						|
	}
 | 
						|
	return(recordBuffer[count++]);
 | 
						|
}
 | 
						|
 | 
						|
void LoadRecord()
 | 
						|
{
 | 
						|
	FILE* pStream = fopen("pad-record.bin", "rb");
 | 
						|
 | 
						|
	if (pStream != NULL)
 | 
						|
	{
 | 
						|
		fread(recordBuffer, 1, RECORD_SIZE * sizeof(SPADStatus), pStream);
 | 
						|
		fclose(pStream);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		PanicAlert("SimplePad: Could not open pad-record.bin");
 | 
						|
	}
 | 
						|
 | 
						|
	//Console::Print("LoadRecord()");
 | 
						|
}
 | 
						|
 | 
						|
void SaveRecord()
 | 
						|
{
 | 
						|
	// Open the file in a way that clears all old data
 | 
						|
	FILE* pStream = fopen("pad-record.bin", "wb");
 | 
						|
 | 
						|
	if (pStream != NULL)
 | 
						|
	{
 | 
						|
		fwrite(recordBuffer, 1, RECORD_SIZE * sizeof(SPADStatus), pStream);
 | 
						|
		fclose(pStream);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		PanicAlert("SimplePad: Could not save pad-record.bin");
 | 
						|
	}
 | 
						|
	//PanicAlert("SaveRecord()");
 | 
						|
	//Console::Print("SaveRecord()");
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Check if Dolphin is in focus
 | 
						|
bool IsFocus()
 | 
						|
{
 | 
						|
#ifdef _WIN32
 | 
						|
	HWND Parent = GetParent(g_PADInitialize.hWnd);
 | 
						|
	HWND TopLevel = GetParent(Parent);
 | 
						|
	// Support both rendering to main window and not
 | 
						|
	if (GetForegroundWindow() == TopLevel || GetForegroundWindow() == g_PADInitialize.hWnd)
 | 
						|
		return true;
 | 
						|
	else
 | 
						|
		return false;
 | 
						|
#else
 | 
						|
	return true;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
// Implement circular deadzone
 | 
						|
const float kDeadZone = 0.1f;
 | 
						|
void ScaleStickValues(unsigned char* outx,
 | 
						|
					  unsigned char* outy,
 | 
						|
					  short inx, short iny)
 | 
						|
{
 | 
						|
	float x = ((float)inx + 0.5f) / 32767.5f;
 | 
						|
	float y = ((float)iny + 0.5f) / 32767.5f;
 | 
						|
 | 
						|
	if ((x == 0.0f) && (y == 0.0f)) // to be safe
 | 
						|
	{
 | 
						|
		*outx = 0;
 | 
						|
		*outy = 0;
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	float magnitude = sqrtf(x * x + y * y);
 | 
						|
	float nx = x / magnitude;
 | 
						|
	float ny = y / magnitude;
 | 
						|
 | 
						|
	if (magnitude < kDeadZone){magnitude = kDeadZone;}
 | 
						|
 | 
						|
	magnitude  = (magnitude - kDeadZone) / (1.0f - kDeadZone);
 | 
						|
	magnitude *= magnitude; // another power may be more appropriate
 | 
						|
	nx *= magnitude;
 | 
						|
	ny *= magnitude;
 | 
						|
	int ix = (int)(nx * 100);
 | 
						|
	int iy = (int)(ny * 100);
 | 
						|
	*outx = 0x80 + ix;
 | 
						|
	*outy = 0x80 + iy;
 | 
						|
}
 | 
						|
 | 
						|
//******************************************************************************
 | 
						|
// Input
 | 
						|
//******************************************************************************
 | 
						|
 | 
						|
#ifdef _WIN32
 | 
						|
void DInput_Read(int _numPAD, SPADStatus* _pPADStatus)
 | 
						|
{
 | 
						|
	dinput.Read();
 | 
						|
 | 
						|
	int stickvalue =    (dinput.diks[pad[_numPAD].keyForControl[CTL_HALFPRESS]] & 0xFF) ? 40 : 100;
 | 
						|
	int triggervalue = (dinput.diks[pad[_numPAD].keyForControl[CTL_HALFPRESS]] & 0xFF) ? 100 : 255;
 | 
						|
 | 
						|
	// get the new keys
 | 
						|
	if (dinput.diks[pad[_numPAD].keyForControl[CTL_MAINLEFT]] & 0xFF){_pPADStatus->stickX -= stickvalue;}
 | 
						|
	if (dinput.diks[pad[_numPAD].keyForControl[CTL_MAINRIGHT]] & 0xFF){_pPADStatus->stickX += stickvalue;}
 | 
						|
	if (dinput.diks[pad[_numPAD].keyForControl[CTL_MAINDOWN]] & 0xFF){_pPADStatus->stickY -= stickvalue;}
 | 
						|
	if (dinput.diks[pad[_numPAD].keyForControl[CTL_MAINUP]]   & 0xFF){_pPADStatus->stickY += stickvalue;}
 | 
						|
	if (dinput.diks[pad[_numPAD].keyForControl[CTL_SUBLEFT]]  & 0xFF){_pPADStatus->substickX -= stickvalue;}
 | 
						|
	if (dinput.diks[pad[_numPAD].keyForControl[CTL_SUBRIGHT]] & 0xFF){_pPADStatus->substickX += stickvalue;}
 | 
						|
	if (dinput.diks[pad[_numPAD].keyForControl[CTL_SUBDOWN]]  & 0xFF){_pPADStatus->substickY -= stickvalue;}
 | 
						|
	if (dinput.diks[pad[_numPAD].keyForControl[CTL_SUBUP]]    & 0xFF){_pPADStatus->substickY += stickvalue;}
 | 
						|
 | 
						|
	if (dinput.diks[pad[_numPAD].keyForControl[CTL_L]] & 0xFF)
 | 
						|
	{
 | 
						|
		if (triggervalue > 230)
 | 
						|
			_pPADStatus->button |= PAD_TRIGGER_L;
 | 
						|
		_pPADStatus->triggerLeft = triggervalue;
 | 
						|
	}
 | 
						|
 | 
						|
	if (dinput.diks[pad[_numPAD].keyForControl[CTL_R]] & 0xFF)
 | 
						|
	{
 | 
						|
		if (triggervalue > 230)
 | 
						|
			_pPADStatus->button |= PAD_TRIGGER_R;
 | 
						|
		_pPADStatus->triggerRight = triggervalue;
 | 
						|
	}
 | 
						|
 | 
						|
	if (dinput.diks[pad[_numPAD].keyForControl[CTL_A]] & 0xFF)
 | 
						|
	{
 | 
						|
		_pPADStatus->button |= PAD_BUTTON_A;
 | 
						|
		_pPADStatus->analogA = 255;
 | 
						|
	}
 | 
						|
 | 
						|
	if (dinput.diks[pad[_numPAD].keyForControl[CTL_B]] & 0xFF)
 | 
						|
	{
 | 
						|
		_pPADStatus->button |= PAD_BUTTON_B;
 | 
						|
		_pPADStatus->analogB = 255;
 | 
						|
	}
 | 
						|
 | 
						|
	if (dinput.diks[pad[_numPAD].keyForControl[CTL_X]] & 0xFF){_pPADStatus->button |= PAD_BUTTON_X;}
 | 
						|
	if (dinput.diks[pad[_numPAD].keyForControl[CTL_Y]] & 0xFF){_pPADStatus->button |= PAD_BUTTON_Y;}
 | 
						|
	if (dinput.diks[pad[_numPAD].keyForControl[CTL_Z]] & 0xFF){_pPADStatus->button |= PAD_TRIGGER_Z;}
 | 
						|
	if (dinput.diks[pad[_numPAD].keyForControl[CTL_DPADUP]]   & 0xFF){_pPADStatus->button |= PAD_BUTTON_UP;}
 | 
						|
	if (dinput.diks[pad[_numPAD].keyForControl[CTL_DPADDOWN]] & 0xFF){_pPADStatus->button |= PAD_BUTTON_DOWN;}
 | 
						|
	if (dinput.diks[pad[_numPAD].keyForControl[CTL_DPADLEFT]] & 0xFF){_pPADStatus->button |= PAD_BUTTON_LEFT;}
 | 
						|
	if (dinput.diks[pad[_numPAD].keyForControl[CTL_DPADRIGHT]]& 0xFF){_pPADStatus->button |= PAD_BUTTON_RIGHT;}
 | 
						|
	if (dinput.diks[pad[_numPAD].keyForControl[CTL_START]]    & 0xFF){_pPADStatus->button |= PAD_BUTTON_START;}
 | 
						|
 | 
						|
	_pPADStatus->MicButton = (dinput.diks[pad[_numPAD].keyForControl[CTL_MIC]] & 0xFF) ? true : false;
 | 
						|
}
 | 
						|
 | 
						|
bool XInput_Read(int XPadPlayer, SPADStatus* _pPADStatus)
 | 
						|
{
 | 
						|
	const int base = 0x80;
 | 
						|
	XINPUT_STATE xstate;
 | 
						|
	DWORD xresult = XInputGetState(XPadPlayer, &xstate);
 | 
						|
 | 
						|
	// Let's .. yes, let's use XINPUT!
 | 
						|
	if (xresult == ERROR_SUCCESS)
 | 
						|
	{
 | 
						|
		const XINPUT_GAMEPAD& xpad = xstate.Gamepad;
 | 
						|
 | 
						|
		if ((_pPADStatus->stickX == base) && (_pPADStatus->stickY == base))
 | 
						|
		{
 | 
						|
			ScaleStickValues(
 | 
						|
					&_pPADStatus->stickX,
 | 
						|
					&_pPADStatus->stickY,
 | 
						|
					xpad.sThumbLX,
 | 
						|
					xpad.sThumbLY);
 | 
						|
		}
 | 
						|
 | 
						|
		if ((_pPADStatus->substickX == base) && (_pPADStatus->substickY == base))
 | 
						|
		{
 | 
						|
			ScaleStickValues(
 | 
						|
					&_pPADStatus->substickX,
 | 
						|
					&_pPADStatus->substickY,
 | 
						|
					xpad.sThumbRX,
 | 
						|
					xpad.sThumbRY);
 | 
						|
		}
 | 
						|
 | 
						|
		_pPADStatus->triggerLeft  = xpad.bLeftTrigger;
 | 
						|
		_pPADStatus->triggerRight = xpad.bRightTrigger;
 | 
						|
 | 
						|
		if (xpad.bLeftTrigger > 200)					{_pPADStatus->button |= PAD_TRIGGER_L;}
 | 
						|
		if (xpad.bRightTrigger > 200)					{_pPADStatus->button |= PAD_TRIGGER_R;}
 | 
						|
		if (xpad.wButtons & XINPUT_GAMEPAD_A)			{_pPADStatus->button |= PAD_BUTTON_A;}
 | 
						|
		if (xpad.wButtons & XINPUT_GAMEPAD_X)			{_pPADStatus->button |= PAD_BUTTON_B;}
 | 
						|
		if (xpad.wButtons & XINPUT_GAMEPAD_B)			{_pPADStatus->button |= PAD_BUTTON_X;}
 | 
						|
		if (xpad.wButtons & XINPUT_GAMEPAD_Y)			{_pPADStatus->button |= PAD_BUTTON_Y;}
 | 
						|
		if (xpad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER){_pPADStatus->button |= PAD_TRIGGER_Z;}
 | 
						|
		if (xpad.wButtons & XINPUT_GAMEPAD_START)		{_pPADStatus->button |= PAD_BUTTON_START;}
 | 
						|
		if (xpad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT)	{_pPADStatus->button |= PAD_BUTTON_LEFT;}
 | 
						|
		if (xpad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT)	{_pPADStatus->button |= PAD_BUTTON_RIGHT;}
 | 
						|
		if (xpad.wButtons & XINPUT_GAMEPAD_DPAD_UP)		{_pPADStatus->button |= PAD_BUTTON_UP;}
 | 
						|
		if (xpad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN)	{_pPADStatus->button |= PAD_BUTTON_DOWN;}
 | 
						|
 | 
						|
		//_pPADStatus->MicButton = (xpad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) ? true : false;
 | 
						|
 | 
						|
		return true;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(HAVE_X11) && HAVE_X11
 | 
						|
// The graphics plugin in the PCSX2 design leaves a lot of the window processing to the pad plugin, weirdly enough.
 | 
						|
void X11_Read(int _numPAD, SPADStatus* _pPADStatus)
 | 
						|
{
 | 
						|
    // Do all the stuff we need to do once per frame here
 | 
						|
    if (_numPAD != 0) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
    // This code is from Zerofrog's pcsx2 pad plugin
 | 
						|
    XEvent E;
 | 
						|
    //int keyPress=0, keyRelease=0;
 | 
						|
    KeySym key;
 | 
						|
    
 | 
						|
    // keyboard input
 | 
						|
    int num_events;
 | 
						|
    for (num_events = XPending(GXdsp);num_events > 0;num_events--) {
 | 
						|
        XNextEvent(GXdsp, &E);
 | 
						|
        switch (E.type) {
 | 
						|
        case KeyPress:
 | 
						|
            //_KeyPress(pad, XLookupKeysym((XKeyEvent *)&E, 0)); break;
 | 
						|
 | 
						|
            key = XLookupKeysym((XKeyEvent*)&E, 0);
 | 
						|
            
 | 
						|
            if((key >= XK_F1 && key <= XK_F9) ||
 | 
						|
               key == XK_Shift_L || key == XK_Shift_R ||
 | 
						|
               key == XK_Control_L || key == XK_Control_R) {
 | 
						|
                XPutBackEvent(GXdsp, &E);
 | 
						|
                break;
 | 
						|
            }
 | 
						|
 | 
						|
            int i;
 | 
						|
            for (i = 0; i < NUMCONTROLS; i++) {
 | 
						|
                if (key == pad[_numPAD].keyForControl[i]) {
 | 
						|
                    KeyStatus[i] = true;
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            
 | 
						|
            
 | 
						|
            break;
 | 
						|
            
 | 
						|
        case KeyRelease:
 | 
						|
 | 
						|
            key = XLookupKeysym((XKeyEvent*)&E, 0);
 | 
						|
            
 | 
						|
            if((key >= XK_F1 && key <= XK_F9) ||
 | 
						|
               key == XK_Shift_L || key == XK_Shift_R ||
 | 
						|
               key == XK_Control_L || key == XK_Control_R) {
 | 
						|
                XPutBackEvent(GXdsp, &E);
 | 
						|
                break;
 | 
						|
            }
 | 
						|
          
 | 
						|
            //_KeyRelease(pad, XLookupKeysym((XKeyEvent *)&E, 0));
 | 
						|
            for (i = 0; i < NUMCONTROLS; i++) {
 | 
						|
                if (key == pad[_numPAD].keyForControl[i]) {
 | 
						|
                    KeyStatus[i] = false;
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            }
 | 
						|
  
 | 
						|
            break;
 | 
						|
            
 | 
						|
        default:
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    int stickvalue =   (KeyStatus[CTL_HALFPRESS]) ? 40 : 100;
 | 
						|
    int triggervalue = (KeyStatus[CTL_HALFPRESS]) ? 100 : 255;
 | 
						|
 | 
						|
    if (KeyStatus[CTL_MAINLEFT]){_pPADStatus->stickX -= stickvalue;}
 | 
						|
    if (KeyStatus[CTL_MAINUP]){_pPADStatus->stickY += stickvalue;}
 | 
						|
    if (KeyStatus[CTL_MAINRIGHT]){_pPADStatus->stickX += stickvalue;}
 | 
						|
    if (KeyStatus[CTL_MAINDOWN]){_pPADStatus->stickY -= stickvalue;}
 | 
						|
 | 
						|
    if (KeyStatus[CTL_SUBLEFT]){_pPADStatus->substickX -= stickvalue;}
 | 
						|
    if (KeyStatus[CTL_SUBUP]){_pPADStatus->substickY += stickvalue;}
 | 
						|
    if (KeyStatus[CTL_SUBRIGHT]){_pPADStatus->substickX += stickvalue;}
 | 
						|
    if (KeyStatus[CTL_SUBDOWN]){_pPADStatus->substickY -= stickvalue;}
 | 
						|
 | 
						|
    if (KeyStatus[CTL_DPADLEFT]){_pPADStatus->button |= PAD_BUTTON_LEFT;}
 | 
						|
    if (KeyStatus[CTL_DPADUP]){_pPADStatus->button |= PAD_BUTTON_UP;}
 | 
						|
    if (KeyStatus[CTL_DPADRIGHT]){_pPADStatus->button |= PAD_BUTTON_RIGHT;}
 | 
						|
    if (KeyStatus[CTL_DPADDOWN]){_pPADStatus->button |= PAD_BUTTON_DOWN;}
 | 
						|
 | 
						|
    if (KeyStatus[CTL_A]) {
 | 
						|
        _pPADStatus->button |= PAD_BUTTON_A;
 | 
						|
        _pPADStatus->analogA = 255;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (KeyStatus[CTL_B]) {
 | 
						|
        _pPADStatus->button |= PAD_BUTTON_B;
 | 
						|
        _pPADStatus->analogB = 255;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (KeyStatus[CTL_X]){_pPADStatus->button |= PAD_BUTTON_X;}
 | 
						|
    if (KeyStatus[CTL_Y]){_pPADStatus->button |= PAD_BUTTON_Y;}
 | 
						|
    if (KeyStatus[CTL_Z]){_pPADStatus->button |= PAD_TRIGGER_Z;}
 | 
						|
 | 
						|
    if (KeyStatus[CTL_L]) {
 | 
						|
        _pPADStatus->button |= PAD_TRIGGER_L;
 | 
						|
        _pPADStatus->triggerLeft = triggervalue;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (KeyStatus[CTL_R]) {
 | 
						|
        _pPADStatus->button |= PAD_TRIGGER_R;
 | 
						|
        _pPADStatus->triggerRight = triggervalue;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (KeyStatus[CTL_START]){_pPADStatus->button |= PAD_BUTTON_START;}
 | 
						|
    if (KeyStatus[CTL_MIC])
 | 
						|
    	_pPADStatus->MicButton = true;
 | 
						|
    else
 | 
						|
    	_pPADStatus->MicButton = false;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(HAVE_COCOA) && HAVE_COCOA
 | 
						|
void cocoa_Read(int _numPAD, SPADStatus* _pPADStatus)
 | 
						|
{
 | 
						|
    // Do all the stuff we need to do once per frame here
 | 
						|
    if (_numPAD != 0) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
	//get event from main thread
 | 
						|
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 | 
						|
        NSConnection *conn;
 | 
						|
        NSDistantObject *proxy;
 | 
						|
 | 
						|
	conn = [NSConnection connectionWithRegisteredName:@"DolphinCocoaEvent" host:nil];
 | 
						|
        if (!conn) {
 | 
						|
                //printf("error creating cnx event client\n");
 | 
						|
        }
 | 
						|
 | 
						|
        proxy = [conn rootProxy];
 | 
						|
 | 
						|
        if (!proxy) {
 | 
						|
                //printf("error prox client\n");
 | 
						|
        }
 | 
						|
 | 
						|
	long cocoaKey = (long)[proxy keyCode];
 | 
						|
 | 
						|
	int i;
 | 
						|
        if ((long)[proxy type] == 10)
 | 
						|
	{
 | 
						|
		for (i = 0; i < NUMCONTROLS; i++) {
 | 
						|
        		if (cocoaKey == pad[_numPAD].keyForControl[i]) {
 | 
						|
                		KeyStatus[i] = true;
 | 
						|
                		break;
 | 
						|
                	}
 | 
						|
        	}
 | 
						|
	}
 | 
						|
        else
 | 
						|
	{
 | 
						|
		for (i = 0; i < NUMCONTROLS; i++) {
 | 
						|
        		if (cocoaKey == pad[_numPAD].keyForControl[i]) {
 | 
						|
                		KeyStatus[i] = false;
 | 
						|
                		break;
 | 
						|
                	}
 | 
						|
        	}
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
    int stickvalue =   (KeyStatus[CTL_HALFPRESS]) ? 40 : 100;
 | 
						|
    int triggervalue = (KeyStatus[CTL_HALFPRESS]) ? 100 : 255;
 | 
						|
 | 
						|
    if (KeyStatus[CTL_MAINLEFT]){_pPADStatus->stickX -= stickvalue;}
 | 
						|
    if (KeyStatus[CTL_MAINUP]){_pPADStatus->stickY += stickvalue;}
 | 
						|
    if (KeyStatus[CTL_MAINRIGHT]){_pPADStatus->stickX += stickvalue;}
 | 
						|
    if (KeyStatus[CTL_MAINDOWN]){_pPADStatus->stickY -= stickvalue;}
 | 
						|
 | 
						|
    if (KeyStatus[CTL_SUBLEFT]){_pPADStatus->substickX -= stickvalue;}
 | 
						|
    if (KeyStatus[CTL_SUBUP]){_pPADStatus->substickY += stickvalue;}
 | 
						|
    if (KeyStatus[CTL_SUBRIGHT]){_pPADStatus->substickX += stickvalue;}
 | 
						|
    if (KeyStatus[CTL_SUBDOWN]){_pPADStatus->substickY -= stickvalue;}
 | 
						|
 | 
						|
    if (KeyStatus[CTL_DPADLEFT]){_pPADStatus->button |= PAD_BUTTON_LEFT;}
 | 
						|
    if (KeyStatus[CTL_DPADUP]){_pPADStatus->button |= PAD_BUTTON_UP;}
 | 
						|
    if (KeyStatus[CTL_DPADRIGHT]){_pPADStatus->button |= PAD_BUTTON_RIGHT;}
 | 
						|
    if (KeyStatus[CTL_DPADDOWN]){_pPADStatus->button |= PAD_BUTTON_DOWN;}
 | 
						|
 | 
						|
    if (KeyStatus[CTL_A]) {
 | 
						|
        _pPADStatus->button |= PAD_BUTTON_A;
 | 
						|
        _pPADStatus->analogA = 255;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (KeyStatus[CTL_B]) {
 | 
						|
        _pPADStatus->button |= PAD_BUTTON_B;
 | 
						|
        _pPADStatus->analogB = 255;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (KeyStatus[CTL_X]){_pPADStatus->button |= PAD_BUTTON_X;}
 | 
						|
    if (KeyStatus[CTL_Y]){_pPADStatus->button |= PAD_BUTTON_Y;}
 | 
						|
    if (KeyStatus[CTL_Z]){_pPADStatus->button |= PAD_TRIGGER_Z;}
 | 
						|
 | 
						|
    if (KeyStatus[CTL_L]) {
 | 
						|
        _pPADStatus->button |= PAD_TRIGGER_L;
 | 
						|
        _pPADStatus->triggerLeft = triggervalue;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (KeyStatus[CTL_R]) {
 | 
						|
        _pPADStatus->button |= PAD_TRIGGER_R;
 | 
						|
        _pPADStatus->triggerRight = triggervalue;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (KeyStatus[CTL_START]){_pPADStatus->button |= PAD_BUTTON_START;}
 | 
						|
    if (KeyStatus[CTL_MIC])
 | 
						|
    	_pPADStatus->MicButton = true;
 | 
						|
    else
 | 
						|
    	_pPADStatus->MicButton = false;
 | 
						|
 | 
						|
	[pool release];
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
 | 
						|
//******************************************************************************
 | 
						|
// Plugin specification functions
 | 
						|
//******************************************************************************
 | 
						|
 | 
						|
 | 
						|
void GetDllInfo(PLUGIN_INFO* _PluginInfo)
 | 
						|
{
 | 
						|
	_PluginInfo->Version = 0x0100;
 | 
						|
	_PluginInfo->Type = PLUGIN_TYPE_PAD;
 | 
						|
 | 
						|
#ifdef DEBUGFAST
 | 
						|
	sprintf(_PluginInfo->Name, "Dolphin KB/X360pad (DebugFast)");
 | 
						|
#else
 | 
						|
#ifndef _DEBUG
 | 
						|
	sprintf(_PluginInfo->Name, "Dolphin KB/X360pad");
 | 
						|
#else
 | 
						|
	sprintf(_PluginInfo->Name, "Dolphin KB/X360pad (Debug)");
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
void SetDllGlobals(PLUGIN_GLOBALS* _pPluginGlobals)
 | 
						|
{
 | 
						|
	globals = _pPluginGlobals;
 | 
						|
	LogManager::SetInstance((LogManager *)globals->logManager);
 | 
						|
}
 | 
						|
 | 
						|
void DllConfig(HWND _hParent)
 | 
						|
{
 | 
						|
	// Load configuration
 | 
						|
	LoadConfig();
 | 
						|
 | 
						|
	// Show wxDialog
 | 
						|
#if defined(HAVE_WX) && HAVE_WX
 | 
						|
	if (!m_ConfigFrame)
 | 
						|
		m_ConfigFrame = new PADConfigDialogSimple(GetParentedWxWindow(_hParent));
 | 
						|
	else if (!m_ConfigFrame->GetParent()->IsShown())
 | 
						|
		m_ConfigFrame->Close(true);
 | 
						|
 | 
						|
	// Only allow one open at a time
 | 
						|
	if (!m_ConfigFrame->IsShown())
 | 
						|
		m_ConfigFrame->ShowModal();
 | 
						|
	else
 | 
						|
		m_ConfigFrame->Hide();
 | 
						|
#endif
 | 
						|
 | 
						|
	// Save configuration
 | 
						|
	SaveConfig();
 | 
						|
}
 | 
						|
 | 
						|
void DllDebugger(HWND _hParent, bool Show) {}
 | 
						|
 | 
						|
void Initialize(void *init)
 | 
						|
{
 | 
						|
	// We are now running a game
 | 
						|
	g_EmulatorRunning = true;
 | 
						|
 | 
						|
	// Load configuration
 | 
						|
	LoadConfig();
 | 
						|
 | 
						|
#ifdef RERECORDING
 | 
						|
	/* Check if we are starting the pad to record the input, and an old file exists. In that case ask
 | 
						|
	   if we really want to start the recording and eventually overwrite the file */
 | 
						|
	if (pad[0].bRecording && File::Exists("pad-record.bin"))
 | 
						|
	{
 | 
						|
		if (!AskYesNo("An old version of '%s' aleady exists in your Dolphin directory. You can"
 | 
						|
			" now make a copy of it before you start a new recording and overwrite the file."
 | 
						|
			" Select Yes to continue and overwrite the file. Select No to turn off the input"
 | 
						|
			" recording and continue without recording anything.",
 | 
						|
			"pad-record.bin"))
 | 
						|
		{
 | 
						|
			// Turn off recording and continue
 | 
						|
			pad[0].bRecording = false;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Load recorded input if we are to play it back, otherwise begin with a blank recording
 | 
						|
	if (pad[0].bPlayback) LoadRecord();
 | 
						|
#endif
 | 
						|
 | 
						|
	g_PADInitialize = *(SPADInitialize*)init;
 | 
						|
 | 
						|
	#ifdef _WIN32
 | 
						|
		dinput.Init((HWND)g_PADInitialize.hWnd);
 | 
						|
	#elif defined(HAVE_X11) && HAVE_X11
 | 
						|
		GXdsp = (Display*)g_PADInitialize.hWnd;
 | 
						|
	#elif defined(HAVE_COCOA) && HAVE_COCOA
 | 
						|
 | 
						|
	#endif
 | 
						|
}
 | 
						|
 | 
						|
void DoState(unsigned char **ptr, int mode)
 | 
						|
{
 | 
						|
#ifdef RERECORDING
 | 
						|
	// Load or save the counter
 | 
						|
	PointerWrap p(ptr, mode);
 | 
						|
	p.Do(count);
 | 
						|
 | 
						|
	//Console::Print("count: %i\n", count);
 | 
						|
 | 
						|
	// Update the frame counter for the sake of the status bar
 | 
						|
	if (mode == PointerWrap::MODE_READ)
 | 
						|
	{
 | 
						|
		#ifdef _WIN32
 | 
						|
			// This only works when rendering to the main window, I think
 | 
						|
			PostMessage(GetParent(g_PADInitialize.hWnd), WM_USER, INPUT_FRAME_COUNTER, count);
 | 
						|
		#endif
 | 
						|
	}
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
void Shutdown()
 | 
						|
{
 | 
						|
	// Save the recording and reset the counter
 | 
						|
#ifdef RERECORDING
 | 
						|
	// Save recording
 | 
						|
	if (pad[0].bRecording) SaveRecord();
 | 
						|
	// Reset the counter
 | 
						|
	count = 0;
 | 
						|
#endif
 | 
						|
 | 
						|
	// We have stopped the game
 | 
						|
	g_EmulatorRunning = false;
 | 
						|
 | 
						|
#ifdef _WIN32
 | 
						|
	dinput.Free();
 | 
						|
	// Kill xpad rumble
 | 
						|
	XINPUT_VIBRATION vib;
 | 
						|
	vib.wLeftMotorSpeed  = 0;
 | 
						|
	vib.wRightMotorSpeed = 0;
 | 
						|
	for (int i = 0; i < 4; i++)
 | 
						|
		if (pad[i].bRumble)
 | 
						|
			XInputSetState(pad[i].XPadPlayer, &vib);
 | 
						|
#endif
 | 
						|
	SaveConfig();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Set buttons status from wxWidgets in the main application
 | 
						|
void PAD_Input(u16 _Key, u8 _UpDown) {}
 | 
						|
 | 
						|
 | 
						|
void PAD_GetStatus(u8 _numPAD, SPADStatus* _pPADStatus)
 | 
						|
{
 | 
						|
	// Check if all is okay
 | 
						|
	if (_pPADStatus == NULL) return;
 | 
						|
 | 
						|
	// Play back input instead of accepting any user input
 | 
						|
#ifdef RERECORDING
 | 
						|
	if (pad[0].bPlayback)
 | 
						|
	{
 | 
						|
		*_pPADStatus = PlayRecord();
 | 
						|
		return;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	const int base = 0x80;
 | 
						|
	// Clear pad
 | 
						|
	memset(_pPADStatus, 0, sizeof(SPADStatus));
 | 
						|
 | 
						|
	_pPADStatus->stickY = base;
 | 
						|
	_pPADStatus->stickX = base;
 | 
						|
	_pPADStatus->substickX = base;
 | 
						|
	_pPADStatus->substickY = base;
 | 
						|
	_pPADStatus->button |= PAD_USE_ORIGIN;
 | 
						|
#ifdef _WIN32
 | 
						|
	// Only update pad on focus, don't do this when recording
 | 
						|
	if (pad[_numPAD].bDisable && !pad[0].bRecording && !IsFocus()) return;
 | 
						|
 | 
						|
	// Dolphin doesn't really care about the pad error codes anyways...
 | 
						|
	_pPADStatus->err = PAD_ERR_NONE;
 | 
						|
 | 
						|
	// Read XInput
 | 
						|
	if (pad[_numPAD].bEnableXPad) XInput_Read(pad[_numPAD].XPadPlayer, _pPADStatus);
 | 
						|
 | 
						|
	// Read Direct Input
 | 
						|
	DInput_Read(_numPAD, _pPADStatus);
 | 
						|
 | 
						|
#elif defined(HAVE_X11) && HAVE_X11
 | 
						|
	_pPADStatus->err = PAD_ERR_NONE;
 | 
						|
	X11_Read(_numPAD, _pPADStatus);
 | 
						|
#elif defined(HAVE_COCOA) && HAVE_COCOA
 | 
						|
	_pPADStatus->err = PAD_ERR_NONE;
 | 
						|
	cocoa_Read(_numPAD, _pPADStatus);
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef RERECORDING
 | 
						|
	// Record input
 | 
						|
	if (pad[0].bRecording) RecordInput(*_pPADStatus);
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Rough approximation of GC behaviour - needs improvement.
 | 
						|
void PAD_Rumble(u8 _numPAD, unsigned int _uType, unsigned int _uStrength)
 | 
						|
{
 | 
						|
#ifdef _WIN32
 | 
						|
	if (pad[_numPAD].bEnableXPad)
 | 
						|
	{
 | 
						|
		static int a = 0;
 | 
						|
 | 
						|
		if ((_uType == 0) || (_uType == 2))
 | 
						|
		{
 | 
						|
			a = 0;
 | 
						|
		}
 | 
						|
		else if (_uType == 1)
 | 
						|
		{
 | 
						|
			a = _uStrength > 2 ? pad[_numPAD].RumbleStrength : 0;
 | 
						|
		}
 | 
						|
 | 
						|
		a = int ((float)a * 0.96f);
 | 
						|
 | 
						|
		if (!pad[_numPAD].bRumble)
 | 
						|
		{
 | 
						|
			a = 0;
 | 
						|
		}
 | 
						|
 | 
						|
		XINPUT_VIBRATION vib;
 | 
						|
		vib.wLeftMotorSpeed  = a; //_uStrength*100;
 | 
						|
		vib.wRightMotorSpeed = a; //_uStrength*100;
 | 
						|
		XInputSetState(pad[_numPAD].XPadPlayer, &vib);
 | 
						|
	}
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
unsigned int PAD_GetAttachedPads()
 | 
						|
{
 | 
						|
	unsigned int connected = 0;
 | 
						|
 | 
						|
	LoadConfig();
 | 
						|
 | 
						|
	if(pad[0].bAttached)
 | 
						|
		connected |= 1;		
 | 
						|
	if(pad[1].bAttached)
 | 
						|
		connected |= 2;
 | 
						|
	if(pad[2].bAttached)
 | 
						|
		connected |= 4;
 | 
						|
	if(pad[3].bAttached)
 | 
						|
		connected |= 8;
 | 
						|
 | 
						|
	return connected;
 | 
						|
}
 | 
						|
 | 
						|
//******************************************************************************
 | 
						|
// Load and save the configuration
 | 
						|
//******************************************************************************
 | 
						|
 | 
						|
void LoadConfig()
 | 
						|
{
 | 
						|
	// Initialize first pad to standard controls
 | 
						|
#ifdef _WIN32
 | 
						|
	const int defaultKeyForControl[NUMCONTROLS] =
 | 
						|
	{
 | 
						|
		DIK_X,	//A
 | 
						|
		DIK_Z,
 | 
						|
		DIK_C,
 | 
						|
		DIK_S,
 | 
						|
		DIK_D,
 | 
						|
		DIK_RETURN,
 | 
						|
		DIK_Q,
 | 
						|
		DIK_W,
 | 
						|
		DIK_UP,	//mainstick
 | 
						|
		DIK_DOWN,
 | 
						|
		DIK_LEFT,
 | 
						|
		DIK_RIGHT,
 | 
						|
		DIK_I,	//substick
 | 
						|
		DIK_K,
 | 
						|
		DIK_J,
 | 
						|
		DIK_L,
 | 
						|
		DIK_T,	//dpad
 | 
						|
		DIK_G,
 | 
						|
		DIK_F,
 | 
						|
		DIK_H,
 | 
						|
		DIK_LSHIFT, //halfpress
 | 
						|
		DIK_M //Mic
 | 
						|
	};
 | 
						|
#elif defined(HAVE_X11) && HAVE_X11
 | 
						|
	const int defaultKeyForControl[NUMCONTROLS] =
 | 
						|
	{
 | 
						|
          XK_x, //A
 | 
						|
          XK_z,
 | 
						|
          XK_c,
 | 
						|
		  XK_s,
 | 
						|
          XK_d,
 | 
						|
          XK_Return,
 | 
						|
          XK_q,
 | 
						|
          XK_w,
 | 
						|
          XK_Up, //mainstick
 | 
						|
          XK_Down,
 | 
						|
          XK_Left,
 | 
						|
          XK_Right,
 | 
						|
          XK_i, //substick
 | 
						|
          XK_K,
 | 
						|
          XK_j,
 | 
						|
          XK_l,
 | 
						|
          XK_t, //dpad
 | 
						|
          XK_g,
 | 
						|
          XK_f,
 | 
						|
          XK_h,
 | 
						|
		  XK_Shift_L, //halfpress
 | 
						|
		  XK_p //Mic
 | 
						|
	};
 | 
						|
#elif defined(HAVE_COCOA) && HAVE_COCOA
 | 
						|
        const int defaultKeyForControl[NUMCONTROLS] =
 | 
						|
        {
 | 
						|
          7, //A
 | 
						|
          6,
 | 
						|
          8,
 | 
						|
		  1,
 | 
						|
          2,
 | 
						|
          36,
 | 
						|
          12,
 | 
						|
          13,
 | 
						|
          126, //mainstick
 | 
						|
          125,
 | 
						|
          123,
 | 
						|
          124,
 | 
						|
          34, //substick
 | 
						|
          40,
 | 
						|
          38,
 | 
						|
          37,
 | 
						|
          17, //dpad
 | 
						|
          5,
 | 
						|
          3,
 | 
						|
          4,
 | 
						|
          56, //halfpress
 | 
						|
          35 //Mic
 | 
						|
        };
 | 
						|
#endif
 | 
						|
	IniFile file;
 | 
						|
	file.Load(FULL_CONFIG_DIR "pad.ini");
 | 
						|
 | 
						|
	for(int i = 0; i < 4; i++)
 | 
						|
	{
 | 
						|
		char SectionName[32];
 | 
						|
		sprintf(SectionName, "PAD%i", i+1);
 | 
						|
 | 
						|
		file.Get(SectionName, "UseXPad", &pad[i].bEnableXPad, i==0);
 | 
						|
		file.Get(SectionName, "Attached", &pad[i].bAttached, i==0);
 | 
						|
		file.Get(SectionName, "DisableOnBackground", &pad[i].bDisable, false);
 | 
						|
		file.Get(SectionName, "Rumble", &pad[i].bRumble, true);
 | 
						|
		file.Get(SectionName, "RumbleStrength", &pad[i].RumbleStrength, 8000);
 | 
						|
		file.Get(SectionName, "XPad#", &pad[i].XPadPlayer);
 | 
						|
 | 
						|
		#ifdef RERECORDING
 | 
						|
			file.Get(SectionName, "Recording", &pad[0].bRecording, false);
 | 
						|
			file.Get(SectionName, "Playback", &pad[0].bPlayback, false);
 | 
						|
		#endif
 | 
						|
 | 
						|
		for (int x = 0; x < NUMCONTROLS; x++)
 | 
						|
		{
 | 
						|
			file.Get(SectionName, controlNames[x], &pad[i].keyForControl[x],
 | 
						|
                                     (i==0)?defaultKeyForControl[x]:0);
 | 
						|
#if defined(HAVE_X11) && HAVE_X11
 | 
						|
			// In linux we have a problem assigning the upper case of the
 | 
						|
			// keys because they're not being recognized
 | 
						|
			pad[i].keyForControl[x] = tolower(pad[i].keyForControl[x]);
 | 
						|
#endif
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void SaveConfig()
 | 
						|
{
 | 
						|
	IniFile file;
 | 
						|
	file.Load(FULL_CONFIG_DIR "pad.ini");
 | 
						|
 | 
						|
	for(int i = 0; i < 4; i++)
 | 
						|
	{
 | 
						|
		char SectionName[32];
 | 
						|
		sprintf(SectionName, "PAD%i", i+1);
 | 
						|
 | 
						|
		file.Set(SectionName, "UseXPad", pad[i].bEnableXPad);
 | 
						|
		file.Set(SectionName, "Attached", pad[i].bAttached);
 | 
						|
		file.Set(SectionName, "DisableOnBackground", pad[i].bDisable);
 | 
						|
		file.Set(SectionName, "Rumble", pad[i].bRumble);
 | 
						|
		file.Set(SectionName, "RumbleStrength", pad[i].RumbleStrength);
 | 
						|
		file.Set(SectionName, "XPad#", pad[i].XPadPlayer);
 | 
						|
 | 
						|
		#ifdef RERECORDING
 | 
						|
			file.Set(SectionName, "Recording", pad[0].bRecording);
 | 
						|
			file.Set(SectionName, "Playback", pad[0].bPlayback);
 | 
						|
		#endif
 | 
						|
 | 
						|
		for (int x = 0; x < NUMCONTROLS; x++)
 | 
						|
		{
 | 
						|
			file.Set(SectionName, controlNames[x], pad[i].keyForControl[x]);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	file.Save(FULL_CONFIG_DIR "pad.ini");
 | 
						|
}
 |