mirror of
				https://github.com/dolphin-emu/dolphin.git
				synced 2025-10-25 09:29:43 +00:00 
			
		
		
		
	git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3656 8ced0084-cf51-0410-be5f-012b33b47a6e
		
			
				
	
	
		
			992 lines
		
	
	
	
		
			26 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			992 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");
 | |
| }
 |