wx: input configuration

This commit is contained in:
p989 2009-12-15 21:49:39 +00:00
parent 2abb85a05d
commit 2aa985baec
20 changed files with 4173 additions and 85 deletions

View File

@ -0,0 +1,278 @@
// Project description
// -------------------
// Name: Input Configuration and Calibration
// Description: Common SDL Input Functions
//
// Author: Falcon4ever (nJoy@falcon4ever.com, www.multigesture.net), JPeterson etc
// Copyright (C) 2003 Dolphin Project.
//
//
// Licensetype: GNU General Public License (GPL)
//
// 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
// -------------------
#if defined HAVE_WX && HAVE_WX
#include <wx/wx.h>
#endif
#ifdef _WIN32
#define NOMINMAX
#include <Windows.h>
#endif
#include "SDL.h" // Local
namespace InputCommon
{
// Degree to radian and back
// -------------
float Deg2Rad(float Deg)
{
return Deg * (float)M_PI / 180.0f;
}
float Rad2Deg(float Rad)
{
return Rad * 180.0f / (float)M_PI;
}
// Check if the pad is within the dead zone, we assume the range is 0x8000
// ----------------
float CoordinatesToRadius(int x, int y)
{
return sqrt(pow((float)x, 2) + pow((float)y, 2));
}
bool IsDeadZone(float DeadZone, int x, int y)
{
// Get the distance from the center
float Distance = CoordinatesToRadius(x, y) / 32767.0f;
//Console::Print("%f\n", Distance);
// Check if it's within the dead zone
if (Distance <= DeadZone)
return true;
else
return false;
}
// Scale down stick values from 0x8000 to 0x80
/* ----------------
The value returned by SDL_JoystickGetAxis is a signed integer s16
(-32768 to 32767). The value used for the gamecube controller is an unsigned
char u8 (0 to 255) with neutral at 0x80 (128), so that it's equivalent to a signed
-128 to 127.
*/
// ---------------------
int Pad_Convert(int _val)
{
/* If the limits on PadState[].axis[] actually is a u16 then we don't need this
but if it's not actually limited to that we need to apply these limits */
if(_val > 32767) _val = 32767; // upper limit
if(_val < -32768) _val = -32768; // lower limit
// Convert the range (-0x8000 to 0x7fff) to (0 to 0xffff)
_val = 0x8000 +_val;
// Convert the range (0 to 0xffff) to (0 to 0xff)
_val = _val >> 8;
//Console::Print("0x%04x %06i\n\n", _val, _val);
return _val;
}
// Adjust the radius
// ----------------
void RadiusAdjustment(int &_x, int &_y, int _pad, std::string SRadius)
{
// Get the radius setting
int Tmp = atoi (SRadius.substr(0, SRadius.length() - 1).c_str());
float RadiusSetting = Tmp / 100.0f;
// Get current angle
float Deg = Rad2Deg(atan2((float)_y, (float)_x));
// Get the current radius
float Radius = sqrt((float)(_x*_x + _y*_y));
// Adjust radius
Radius = Radius * RadiusSetting;
// Produce new coordinates
float x = Radius * cos(Deg2Rad(Deg));
float y = Radius * sin(Deg2Rad(Deg));
// Update values
_x = (int)x, _y = (int)y;
}
/* Convert the stick raidus from a square or rounded box to a circular radius. I don't know what
input values the actual GC controller produce for the GC, it may be a square, a circle or
something in between. But one thing that is certain is that PC pads differ in their output
(as shown in the list below), so it may be beneficiary to convert whatever radius they
produce to the radius the GC games expect. This is the first implementation of this
that convert a square radius to a circual radius. Use the advanced settings to enable
and calibrate it.
Observed diagonals:
Perfect circle: 71% = sin(45)
Logitech Dual Action: 100%
PS2 Dual Shock 2 (Original) with Super Dual Box Pro: 90%
XBox 360 Wireless: 85%
GameCube Controller (Third Party) with EMS Trio Linker Plus II: 60%
*/
// ---------------------
/* Calculate the distance from the outer edges of the box to the outer edges of the circle inside the box
at any angle from 0 to 360. The returned value is 1 + Distance, for example at most sqrt(2) in the
corners and at least 1.0 at the horizontal and vertical angles. */
float Square2CircleDistance(float deg)
{
// See if we have to adjust the angle
deg = abs(deg);
if( (deg > 45 && deg < 135) ) deg = deg - 90;
// Calculate distance from center
float val = abs(cos(Deg2Rad(deg)));
float Distance = 1 / val;
//m_frame->m_pStatusBar2->SetLabel(wxString::Format("Deg:%f Val:%f Dist:%f", deg, val, dist));
return Distance;
}
// Produce a perfect circle from an original square or rounded box
void Square2Circle(int &_x, int &_y, int _pad, std::string SDiagonal, bool Circle2Square)
{
// Do we need to do this check?
if(_x > 32767) _x = 32767; if(_y > 32767) _y = 32767; // upper limit
if(_x < -32768) _x = -32768; if(_y < -32768) _y = -32768; // lower limit
// ====================================
// Convert to circle
// -----------
// Get the manually configured diagonal distance
int Tmp = atoi (SDiagonal.substr(0, SDiagonal.length() - 1).c_str());
float Diagonal = Tmp / 100.0f;
// First make a perfect square in case we don't have one already
float OrigDist = sqrt( pow((float)_y, 2) + pow((float)_x, 2) ); // Get current distance
float deg = Rad2Deg(atan2((float)_y, (float)_x)); // Get current angle
/* Calculate the actual distance between the maxium diagonal values, and the outer edges of the
square. A diagonal of 85% means a maximum distance of 0.85 * sqrt(2) ~1.2 in the diagonals. */
float corner_circle_dist = ( Diagonal / sin(Deg2Rad(45.0f)) );
float SquareDist = Square2CircleDistance(deg);
// The original-to-square distance adjustment
float adj_ratio1;
// The circle-to-square distance adjustment
float adj_ratio2 = SquareDist;
// The resulting distance
float result_dist;
// Calculate the corner-to-square adjustment ratio
if(corner_circle_dist < SquareDist) adj_ratio1 = SquareDist / corner_circle_dist;
else adj_ratio1 = 1;
// Calculate the resulting distance
if(Circle2Square)
result_dist = OrigDist * adj_ratio1;
else
result_dist = OrigDist * adj_ratio1 / adj_ratio2;
// Calculate x and y and return it
float x = result_dist * cos(Deg2Rad(deg));
float y = result_dist * sin(Deg2Rad(deg));
// Update coordinates
_x = (int)floor(x);
_y = (int)floor(y);
// Boundaries
if (_x < -32768) _x = -32768; if (_x > 32767) _x = 32767;
if (_y < -32768) _y = -32768; if (_y > 32767) _y = 32767;
// Debugging
//Console::Print("%f %f %i", corner_circle_dist, Diagonal, Tmp));
}
// Windows Virtual Key Codes Names
// ---------------------
#ifdef _WIN32
std::string VKToString(int keycode)
{
#ifdef _WIN32
// Default value
char KeyStr[64] = {0};
std::string KeyString;
// TODO: Switch to unicode GetKeyNameText?
if (keycode < 256) // Keyboard
GetKeyNameTextA(MapVirtualKey(keycode, MAPVK_VK_TO_VSC) << 16, KeyStr, 64);
else // Pad
sprintf(KeyStr, "PAD: %d", keycode - 0x1000);
switch(keycode)
{
// Give it some help with a few keys
case VK_END: return "END";
case VK_INSERT: return "INS";
case VK_DELETE: return "DEL";
case VK_PRIOR: return "PGUP";
case VK_NEXT: return "PGDN";
case VK_UP: return "UP";
case VK_DOWN: return "DOWN";
case VK_LEFT: return "LEFT";
case VK_RIGHT: return "RIGHT";
case VK_LSHIFT: return "LEFT SHIFT";
case VK_LCONTROL: return "LEFT CTRL";
case VK_RCONTROL: return "RIGHT CTRL";
case VK_LMENU: return "LEFT ALT";
default: return KeyString = KeyStr;
}
#else
// An equivalent name translation can probably be used on other systems to?
return "";
#endif
}
#endif
}

View File

@ -0,0 +1,195 @@
// 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
// -------------------
#include "DirectInputBase.h"
DInput::DInput()
: g_pDI(NULL),
g_pKeyboard(NULL)
{}
DInput::~DInput()
{
Free();
}
void DInput::DIKToString(unsigned int keycode, char *keyStr)
{
switch(keycode) {
case DIK_RETURN:
sprintf(keyStr, "Enter");
break;
case DIK_UP:
sprintf(keyStr, "Up");
break;
case DIK_DOWN:
sprintf(keyStr, "Down");
break;
case DIK_LEFT:
sprintf(keyStr, "Left");
break;
case DIK_RIGHT:
sprintf(keyStr, "Right");
break;
case DIK_HOME:
strcpy(keyStr, "Home");
break;
case DIK_END:
strcpy(keyStr, "End");
break;
case DIK_INSERT:
strcpy(keyStr, "Ins");
break;
case DIK_DELETE:
strcpy(keyStr, "Del");
break;
case DIK_PGUP:
strcpy(keyStr, "PgUp");
break;
case DIK_PGDN:
strcpy(keyStr, "PgDn");
break;
case DIK_NUMPAD0:
strcpy(keyStr, "Num 0");
break;
case DIK_NUMPAD1:
strcpy(keyStr, "Num 1");
break;
case DIK_NUMPAD2:
strcpy(keyStr, "Num 2");
break;
case DIK_NUMPAD3:
strcpy(keyStr, "Num 3");
break;
case DIK_NUMPAD4:
strcpy(keyStr, "Num 4");
break;
case DIK_NUMPAD5:
strcpy(keyStr, "Num 5");
break;
case DIK_NUMPAD6:
strcpy(keyStr, "Num 6");
break;
case DIK_NUMPAD7:
strcpy(keyStr, "Num 7");
break;
case DIK_NUMPAD8:
strcpy(keyStr, "Num 8");
break;
case DIK_NUMPAD9:
strcpy(keyStr, "Num 9");
break;
case DIK_NUMPADSLASH:
strcpy(keyStr, "Num /");
break;
default:
// TODO: Switch to unicode GetKeyNameText?
GetKeyNameTextA(keycode << 16, keyStr, 64);
break;
}
}
HRESULT DInput::Init(HWND hWnd)
{
HRESULT hr;
DWORD dwCoopFlags;
dwCoopFlags = DISCL_FOREGROUND | DISCL_NOWINKEY;
// Create a DInput object
if (FAILED(hr = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION,
IID_IDirectInput8, (VOID* *)&g_pDI, NULL)))
{
MessageBox(0, "Direct Input Create Failed", 0, MB_ICONERROR);
return(hr);
}
if (FAILED(hr = g_pDI->CreateDevice(GUID_SysKeyboard, &g_pKeyboard, NULL)))
{
MessageBox(0, "Couldn't access keyboard", 0, MB_ICONERROR);
Free();
return(hr);
}
g_pKeyboard->SetDataFormat(&c_dfDIKeyboard);
g_pKeyboard->SetCooperativeLevel(hWnd, dwCoopFlags);
g_pKeyboard->Acquire();
return(S_OK);
}
void DInput::Free()
{
if (g_pKeyboard)
{
g_pKeyboard->Unacquire();
g_pKeyboard->Release();
g_pKeyboard = 0;
}
if (g_pDI)
{
g_pDI->Release();
g_pDI = 0;
}
}
// Desc: Read the input device's state when in immediate mode and display it.
HRESULT DInput::Read()
{
HRESULT hr;
if (NULL == g_pKeyboard)
{
return(S_OK);
}
// Get the input's device state, and put the state in dims
ZeroMemory(diks, sizeof(diks));
hr = g_pKeyboard->GetDeviceState(sizeof(diks), diks);
// for (int i=0; i<256; i++)
// if (diks[i]) MessageBox(0,"DSFJDKSF|",0,0);
if (FAILED(hr))
{
// DirectInput may be telling us that the input stream has been
// interrupted. We aren't tracking any state between polls, so
// we don't have any special reset that needs to be done.
// We just re-acquire and try again.
// If input is lost then acquire and keep trying
hr = g_pKeyboard->Acquire();
while (hr == DIERR_INPUTLOST)
{
hr = g_pKeyboard->Acquire();
}
// hr may be DIERR_OTHERAPPHASPRIO or other errors. This
// may occur when the app is minimized or in the process of
// switching, so just try again later
return(S_OK);
}
return(S_OK);
}

View File

@ -0,0 +1,58 @@
// 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/
#ifndef _DIRECTINPUTBASE_H
#define _DIRECTINPUTBASE_H
// Include
// -------------------
#include <windows.h> // System
#include <stdio.h>
#define DIRECTINPUT_VERSION 0x0800 // DirectInput
#include <dinput.h>
//#include "ConsoleWindow.h" // Common
class DInput
{
public:
DInput();
~DInput();
static void DInput::DIKToString(unsigned int keycode, char *keyStr);
HRESULT Init(HWND hWnd);
void Free();
HRESULT Read();
BYTE diks[256]; // DirectInput keyboard state buffer
private:
LPDIRECTINPUT8 g_pDI; // The DirectInput object
LPDIRECTINPUTDEVICE8 g_pKeyboard; // The keyboard device
};
#endif

View File

@ -0,0 +1,264 @@
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
#ifndef SFML_EVENT_HPP
#define SFML_EVENT_HPP
namespace sf
{
namespace Key
{
enum Code
{
A = 'a',
B = 'b',
C = 'c',
D = 'd',
E = 'e',
F = 'f',
G = 'g',
H = 'h',
I = 'i',
J = 'j',
K = 'k',
L = 'l',
M = 'm',
N = 'n',
O = 'o',
P = 'p',
Q = 'q',
R = 'r',
S = 's',
T = 't',
U = 'u',
V = 'v',
W = 'w',
X = 'x',
Y = 'y',
Z = 'z',
Num0 = '0',
Num1 = '1',
Num2 = '2',
Num3 = '3',
Num4 = '4',
Num5 = '5',
Num6 = '6',
Num7 = '7',
Num8 = '8',
Num9 = '9',
Escape = 256,
LControl,
LShift,
LAlt,
LSystem,
RControl,
RShift,
RAlt,
RSystem,
Menu,
LBracket,
RBracket,
SemiColon,
Comma,
Period,
Quote,
Slash,
BackSlash,
Tilde,
Equal,
Dash,
Space,
Return,
Back,
Tab,
PageUp,
PageDown,
End,
Home,
Insert,
Delete,
Add,
Subtract,
Multiply,
Divide,
Left,
Right,
Up,
Down,
Numpad0,
Numpad1,
Numpad2,
Numpad3,
Numpad4,
Numpad5,
Numpad6,
Numpad7,
Numpad8,
Numpad9,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
F13,
F14,
F15,
Pause,
Count // For internal use
};
}
namespace Mouse
{
enum Button
{
Left,
Right,
Middle,
XButton1,
XButton2,
Count // For internal use
};
}
namespace Joy
{
enum Axis
{
AxisX,
AxisY,
AxisZ,
AxisR,
AxisU,
AxisV,
AxisPOV,
Count // For internal use
};
}
class Event
{
public :
struct KeyEvent
{
Key::Code Code;
bool Alt;
bool Control;
bool Shift;
};
struct TextEvent
{
// I'm not sure we need this...
unsigned short Unicode;
};
struct MouseMoveEvent
{
int X;
int Y;
};
struct MouseButtonEvent
{
Mouse::Button Button;
int X;
int Y;
};
struct MouseWheelEvent
{
int Delta;
};
struct JoyMoveEvent
{
unsigned int JoystickId;
Joy::Axis Axis;
float Position;
};
struct JoyButtonEvent
{
unsigned int JoystickId;
unsigned int Button;
};
struct SizeEvent
{
unsigned int Width;
unsigned int Height;
};
enum EventType
{
Closed,
Resized,
LostFocus,
GainedFocus,
TextEntered,
KeyPressed,
KeyReleased,
MouseWheelMoved,
MouseButtonPressed,
MouseButtonReleased,
MouseMoved,
MouseEntered,
MouseLeft,
JoyButtonPressed,
JoyButtonReleased,
JoyMoved
};
// Member data
EventType Type;
union
{
KeyEvent Key;
TextEvent Text;
MouseMoveEvent MouseMove;
MouseButtonEvent MouseButton;
MouseWheelEvent MouseWheel;
JoyMoveEvent JoyMove;
JoyButtonEvent JoyButton;
SizeEvent Size;
};
};
} // namespace sf
#endif // SFML_EVENT_HPP

View File

@ -0,0 +1,316 @@
#include "EventHandler.h"
#include <stdio.h>
#include <ctype.h>
#if defined HAVE_WX && HAVE_WX
#include <wx/wx.h>
#endif
EventHandler *EventHandler::m_Instance = 0;
EventHandler::EventHandler() {
memset(keys, 0, sizeof(keys));
memset(mouse, 0, sizeof(mouse));
memset(joys, 0, sizeof(joys));
}
EventHandler::~EventHandler() {
}
EventHandler *EventHandler::GetInstance() {
// fprintf(stderr, "handler instance %p\n", m_Instance);
if (! m_Instance)
m_Instance = new EventHandler();
return m_Instance;
}
void EventHandler::Destroy() {
if (m_Instance)
delete m_Instance;
// fprintf(stderr, "deleting instance %p\n", m_Instance);
m_Instance = 0;
}
bool EventHandler::RegisterEventListener(listenFuncPtr func, Keys key) {
if (key.inputType == KeyboardInput) {
// fprintf(stderr, "Registering %d:%d %p %p \n", key.keyCode, key.mods, func, this);
if (key.keyCode == sf::Key::Count || key.mods >= NUMMODS ||
key.keyCode >= NUMKEYS)
return false;
if (keys[key.keyCode][key.mods] && keys[key.keyCode][key.mods] != func)
return false
;
keys[key.keyCode][key.mods] = func;
} else if (key.inputType == MouseInput) {
if (mouse[key.mouseButton])
return false;
mouse[key.mouseButton] = func;
}
return true;
}
bool EventHandler::RemoveEventListener(Keys key) {
if (key.inputType == KeyboardInput) {
if ((key.keyCode == sf::Key::Count || key.keyCode >= NUMKEYS
|| key.mods >= NUMMODS) && ! keys[key.keyCode][key.mods])
return false;
keys[key.keyCode][key.mods] = NULL;
} else if (key.inputType == MouseInput) {
if (! mouse[key.mouseButton])
return false;
mouse[key.mouseButton] = NULL;
}
return true;
}
void EventHandler::Update() {
for (unsigned int i = 0; i < eventQueue.size();i++) {
sf::Event ev = eventQueue.front();
eventQueue.pop();
fprintf(stderr, "Updating event type %d code %d mod %d func %p %p\n", ev.Type, ev.Key.Code, ev.Key.Alt+2*ev.Key.Shift+4*ev.Key.Control, keys[ev.Key.Code][ev.Key.Alt+2*ev.Key.Shift+4*ev.Key.Control], this);
if(keys[ev.Key.Code][ev.Key.Alt+2*ev.Key.Shift+4*ev.Key.Control])
keys[ev.Key.Code][ev.Key.Alt+2*ev.Key.Shift+4*ev.Key.Control](ev);
}
}
bool EventHandler::addEvent(sf::Event *ev) {
eventQueue.push(*ev);
fprintf(stderr, "Got event type %d code %d %p\n", ev->Type, ev->Key.Code, this);
return true;
}
bool EventHandler::TestEvent (Keys k, sf::Event e)
{
//Mouse event
if (k.inputType==MouseInput && k.eventType==e.Type && k.mouseButton==e.MouseButton.Button)
{
return (true);
}
//Keyboard event
if (k.inputType==KeyboardInput && k.eventType==e.Type && k.keyCode==e.Key.Code)
{
return (true);
}
return (false);
}
#if defined HAVE_WX && HAVE_WX
// Taken from wxw source code
sf::Key::Code EventHandler::wxCharCodeToSF(int id)
{
sf::Key::Code sfKey;
switch (id) {
// case WXK_CANCEL: sfKey = sf::Key::Cancel; break;
// case WXK_BACK: sfKey = sf::Key::BackSpace; break;
case WXK_TAB: sfKey = sf::Key::Tab; break;
// case WXK_CLEAR: sfKey = sf::Key::Clear; break;
case WXK_RETURN: sfKey = sf::Key::Return; break;
case WXK_SHIFT: sfKey = sf::Key::LShift; break;
case WXK_CONTROL: sfKey = sf::Key::LControl; break;
case WXK_ALT: sfKey = sf::Key::LAlt; break;
// case WXK_CAPITAL: sfKey = sf::Key::Caps_Lock; break;
case WXK_MENU : sfKey = sf::Key::Menu; break;
case WXK_PAUSE: sfKey = sf::Key::Pause; break;
case WXK_ESCAPE: sfKey = sf::Key::Escape; break;
case WXK_SPACE: sfKey = sf::Key::Space; break;
case WXK_PAGEUP: sfKey = sf::Key::PageUp; break;
case WXK_PAGEDOWN: sfKey = sf::Key::PageDown; break;
case WXK_END: sfKey = sf::Key::End; break;
case WXK_HOME : sfKey = sf::Key::Home; break;
case WXK_LEFT : sfKey = sf::Key::Left; break;
case WXK_UP: sfKey = sf::Key::Up; break;
case WXK_RIGHT: sfKey = sf::Key::Right; break;
case WXK_DOWN : sfKey = sf::Key::Down; break;
// case WXK_SELECT: sfKey = sf::Key::Select; break;
// case WXK_PRINT: sfKey = sf::Key::Print; break;
// case WXK_EXECUTE: sfKey = sf::Key::Execute; break;
case WXK_INSERT: sfKey = sf::Key::Insert; break;
case WXK_DELETE: sfKey = sf::Key::Delete; break;
// case WXK_HELP : sfKey = sf::Key::Help; break;
case WXK_NUMPAD0: sfKey = sf::Key::Numpad0; break;
case WXK_NUMPAD_INSERT: sfKey = sf::Key::Insert; break;
case WXK_NUMPAD1: sfKey = sf::Key::Numpad1; break;
case WXK_NUMPAD_END: sfKey = sf::Key::End; break;
case WXK_NUMPAD2: sfKey = sf::Key::Numpad2; break;
case WXK_NUMPAD_DOWN: sfKey = sf::Key::Down; break;
case WXK_NUMPAD3: sfKey = sf::Key::Numpad3; break;
case WXK_NUMPAD_PAGEDOWN: sfKey = sf::Key::PageDown; break;
case WXK_NUMPAD4: sfKey = sf::Key::Numpad4; break;
case WXK_NUMPAD_LEFT: sfKey = sf::Key::Left; break;
case WXK_NUMPAD5: sfKey = sf::Key::Numpad5; break;
case WXK_NUMPAD6: sfKey = sf::Key::Numpad6; break;
case WXK_NUMPAD_RIGHT: sfKey = sf::Key::Right; break;
case WXK_NUMPAD7: sfKey = sf::Key::Numpad7; break;
case WXK_NUMPAD_HOME: sfKey = sf::Key::Home; break;
case WXK_NUMPAD8: sfKey = sf::Key::Numpad8; break;
case WXK_NUMPAD_UP: sfKey = sf::Key::Up; break;
case WXK_NUMPAD9: sfKey = sf::Key::Numpad9; break;
case WXK_NUMPAD_PAGEUP: sfKey = sf::Key::PageUp; break;
// case WXK_NUMPAD_DECIMAL: sfKey = sf::Key::Decimal; break;
case WXK_NUMPAD_DELETE: sfKey = sf::Key::Delete; break;
case WXK_NUMPAD_MULTIPLY: sfKey = sf::Key::Multiply; break;
case WXK_NUMPAD_ADD: sfKey = sf::Key::Add; break;
case WXK_NUMPAD_SUBTRACT: sfKey = sf::Key::Subtract; break;
case WXK_NUMPAD_DIVIDE: sfKey = sf::Key::Divide; break;
case WXK_NUMPAD_ENTER: sfKey = sf::Key::Return; break;
// case WXK_NUMPAD_SEPARATOR:sfKey = sf::Key::Separator; break;
case WXK_F1: sfKey = sf::Key::F1; break;
case WXK_F2: sfKey = sf::Key::F2; break;
case WXK_F3: sfKey = sf::Key::F3; break;
case WXK_F4: sfKey = sf::Key::F4; break;
case WXK_F5: sfKey = sf::Key::F5; break;
case WXK_F6: sfKey = sf::Key::F6; break;
case WXK_F7: sfKey = sf::Key::F7; break;
case WXK_F8: sfKey = sf::Key::F8; break;
case WXK_F9: sfKey = sf::Key::F9; break;
case WXK_F10: sfKey = sf::Key::F10; break;
case WXK_F11: sfKey = sf::Key::F11; break;
case WXK_F12: sfKey = sf::Key::F12; break;
case WXK_F13: sfKey = sf::Key::F13; break;
case WXK_F14: sfKey = sf::Key::F14; break;
case WXK_F15: sfKey = sf::Key::F15; break;
// case WXK_NUMLOCK: sfKey = sf::Key::Num_Lock; break;
// case WXK_SCROLL: sfKey = sf::Key::Scroll_Lock; break;
default:
// To lower (will tolower work on windows?)
if (id >= 'A' && id <= 'Z')
id = id - 'A' + 'a';
if ((id >= 'a' && id <= 'z') ||
(id >= '0' && id <= '9'))
sfKey = (sf::Key::Code)id;
else
sfKey = sf::Key::Count; // Invalid key
}
return sfKey;
}
#endif
void EventHandler::SFKeyToString(sf::Key::Code keycode, char *keyStr) {
switch (keycode) {
/* case sf::Key::A = 'a': sprintf(keyStr, "UP"); break;
case sf::Key::B = 'b': sprintf(keyStr, "UP"); break;
case sf::Key::C = 'c': sprintf(keyStr, "UP"); break;
case sf::Key::D = 'd': sprintf(keyStr, "UP"); break;
case sf::Key::E = 'e': sprintf(keyStr, "UP"); break;
case sf::Key::F = 'f': sprintf(keyStr, "UP"); break;
case sf::Key::G = 'g': sprintf(keyStr, "UP"); break;
case sf::Key::H = 'h': sprintf(keyStr, "UP"); break;
case sf::Key::I = 'i': sprintf(keyStr, "UP"); break;
case sf::Key::J = 'j': sprintf(keyStr, "UP"); break;
case sf::Key::K = 'k': sprintf(keyStr, "UP"); break;
case sf::Key::L = 'l': sprintf(keyStr, "UP"); break;
case sf::Key::M = 'm': sprintf(keyStr, "UP"); break;
case sf::Key::N = 'n': sprintf(keyStr, "UP"); break;
case sf::Key::O = 'o': sprintf(keyStr, "UP"); break;
case sf::Key::P = 'p': sprintf(keyStr, "UP"); break;
case sf::Key::Q = 'q': sprintf(keyStr, "UP"); break;
case sf::Key::R = 'r': sprintf(keyStr, "UP"); break;
case sf::Key::S = 's': sprintf(keyStr, "UP"); break;
case sf::Key::T = 't': sprintf(keyStr, "UP"); break;
case sf::Key::U = 'u': sprintf(keyStr, "UP"); break;
case sf::Key::V = 'v': sprintf(keyStr, "UP"); break;
case sf::Key::W = 'w': sprintf(keyStr, "UP"); break;
case sf::Key::X = 'x': sprintf(keyStr, "UP"); break;
case sf::Key::Y = 'y': sprintf(keyStr, "UP"); break;
case sf::Key::Z = 'z': sprintf(keyStr, "UP"); break;
case sf::Key::Num0 = '0': sprintf(keyStr, "UP"); break;
case sf::Key::Num1 = '1': sprintf(keyStr, "UP"); break;
case sf::Key::Num2 = '2': sprintf(keyStr, "UP"); break;
case sf::Key::Num3 = '3': sprintf(keyStr, "UP"); break;
case sf::Key::Num4 = '4': sprintf(keyStr, "UP"); break;
case sf::Key::Num5 = '5': sprintf(keyStr, "UP"); break;
case sf::Key::Num6 = '6': sprintf(keyStr, "UP"); break;
case sf::Key::Num7 = '7': sprintf(keyStr, "UP"); break;
case sf::Key::Num8 = '8': sprintf(keyStr, "UP"); break;
case sf::Key::Num9 = '9': sprintf(keyStr, "UP"); break;*/
case sf::Key::Escape: sprintf(keyStr, "Escape"); break;
case sf::Key::LControl: sprintf(keyStr, "LControl"); break;
case sf::Key::LShift: sprintf(keyStr, "LShift"); break;
case sf::Key::LAlt: sprintf(keyStr, "LAlt"); break;
case sf::Key::LSystem: sprintf(keyStr, "LSystem"); break;
case sf::Key::RControl: sprintf(keyStr, "RControl"); break;
case sf::Key::RShift: sprintf(keyStr, "RShift"); break;
case sf::Key::RAlt: sprintf(keyStr, "RAlt"); break;
case sf::Key::RSystem: sprintf(keyStr, "RSystem"); break;
case sf::Key::Menu: sprintf(keyStr, "Menu"); break;
case sf::Key::LBracket: sprintf(keyStr, "LBracket"); break;
case sf::Key::RBracket: sprintf(keyStr, "RBracket"); break;
case sf::Key::SemiColon: sprintf(keyStr, ";"); break;
case sf::Key::Comma: sprintf(keyStr, ","); break;
case sf::Key::Period: sprintf(keyStr, "."); break;
case sf::Key::Quote: sprintf(keyStr, "\'"); break;
case sf::Key::Slash: sprintf(keyStr, "/"); break;
case sf::Key::BackSlash: sprintf(keyStr, "\\"); break;
case sf::Key::Tilde: sprintf(keyStr, "~"); break;
case sf::Key::Equal: sprintf(keyStr, "="); break;
case sf::Key::Dash: sprintf(keyStr, "-"); break;
case sf::Key::Space: sprintf(keyStr, "Space"); break;
case sf::Key::Return: sprintf(keyStr, "Return"); break;
case sf::Key::Back: sprintf(keyStr, "Back"); break;
case sf::Key::Tab: sprintf(keyStr, "Tab"); break;
case sf::Key::PageUp: sprintf(keyStr, "Page Up"); break;
case sf::Key::PageDown: sprintf(keyStr, "Page Down"); break;
case sf::Key::End: sprintf(keyStr, "End"); break;
case sf::Key::Home: sprintf(keyStr, "Home"); break;
case sf::Key::Insert: sprintf(keyStr, "Insert"); break;
case sf::Key::Delete: sprintf(keyStr, "Delete"); break;
case sf::Key::Add: sprintf(keyStr, "+"); break;
case sf::Key::Subtract: sprintf(keyStr, "-"); break;
case sf::Key::Multiply: sprintf(keyStr, "*"); break;
case sf::Key::Divide: sprintf(keyStr, "/"); break;
case sf::Key::Left: sprintf(keyStr, "Left"); break;
case sf::Key::Right: sprintf(keyStr, "Right"); break;
case sf::Key::Up: sprintf(keyStr, "Up"); break;
case sf::Key::Down: sprintf(keyStr, "Down"); break;
case sf::Key::Numpad0: sprintf(keyStr, "NP 0"); break;
case sf::Key::Numpad1: sprintf(keyStr, "NP 1"); break;
case sf::Key::Numpad2: sprintf(keyStr, "NP 2"); break;
case sf::Key::Numpad3: sprintf(keyStr, "NP 3"); break;
case sf::Key::Numpad4: sprintf(keyStr, "NP 4"); break;
case sf::Key::Numpad5: sprintf(keyStr, "NP 5"); break;
case sf::Key::Numpad6: sprintf(keyStr, "NP 6"); break;
case sf::Key::Numpad7: sprintf(keyStr, "NP 7"); break;
case sf::Key::Numpad8: sprintf(keyStr, "NP 8"); break;
case sf::Key::Numpad9: sprintf(keyStr, "NP 9"); break;
case sf::Key::F1: sprintf(keyStr, "F1"); break;
case sf::Key::F2: sprintf(keyStr, "F2"); break;
case sf::Key::F3: sprintf(keyStr, "F3"); break;
case sf::Key::F4: sprintf(keyStr, "F4"); break;
case sf::Key::F5: sprintf(keyStr, "F5"); break;
case sf::Key::F6: sprintf(keyStr, "F6"); break;
case sf::Key::F7: sprintf(keyStr, "F7"); break;
case sf::Key::F8: sprintf(keyStr, "F8"); break;
case sf::Key::F9: sprintf(keyStr, "F9"); break;
case sf::Key::F10: sprintf(keyStr, "F10"); break;
case sf::Key::F11: sprintf(keyStr, "F11"); break;
case sf::Key::F12: sprintf(keyStr, "F12"); break;
case sf::Key::F13: sprintf(keyStr, "F13"); break;
case sf::Key::F14: sprintf(keyStr, "F14"); break;
case sf::Key::F15: sprintf(keyStr, "F15"); break;
case sf::Key::Pause: sprintf(keyStr, "Pause"); break;
default:
if (keycode > sf::Key::Escape)
sprintf(keyStr, "Invalid Key");
else
sprintf(keyStr, "%c", toupper(keycode));
break;
}
}
class EventHandlerCleaner
{
public:
~EventHandlerCleaner()
{
//EventHandler::Destroy();
}
} EventHandlerCleanerInst;

View File

@ -0,0 +1,63 @@
#ifndef EVENTHANDER_H
#define EVENTHANDER_H 1
#include "Common.h"
#include <queue>
#include "Event.hpp"
#define NUMKEYS 300
#define NUMMODS 8
typedef bool (*listenFuncPtr) (sf::Event);
enum InputType
{
KeyboardInput,
MouseInput,
JoystickInput
};
enum Modifiers {
UseAlt = 1,
UseShift = 2,
UseCtrl = 4
};
struct Keys {
InputType inputType;
sf::Event::EventType eventType;
sf::Key::Code keyCode;
int mods;
sf::Mouse::Button mouseButton;
};
class EventHandler {
private:
listenFuncPtr keys[NUMKEYS][NUMMODS];
listenFuncPtr mouse[sf::Mouse::Count+1];
listenFuncPtr joys[sf::Joy::Count+1];
std::queue<sf::Event> eventQueue;
static EventHandler *m_Instance;
protected:
EventHandler(const EventHandler&);
EventHandler& operator= (const EventHandler&);
EventHandler();
~EventHandler();
public:
bool RegisterEventListener(listenFuncPtr func, Keys key);
bool RemoveEventListener(Keys key);
void Update();
static EventHandler *GetInstance();
static void Destroy();
bool addEvent(sf::Event *e);
static bool TestEvent (Keys k, sf::Event e);
#if defined HAVE_WX && HAVE_WX
static sf::Key::Code wxCharCodeToSF(int id);
#endif
static void SFKeyToString(sf::Key::Code keycode, char *keyStr);
};
#endif

View File

@ -0,0 +1,16 @@
#include "EventHandler.h"
//EventHandler *eventHandler = NULL;
namespace InputCommon
{
void Init() {
// init the event handler
//EventHandler::GetInstance();
}
void Shutdown() {
//if (eventHandler)
// delete eventHandler;
}
}

View File

@ -0,0 +1,9 @@
#include "EventHandler.h"
//extern EventHandler *eventHandler;
namespace InputCommon
{
void Init();
void Shutdown();
}

View File

@ -0,0 +1,375 @@
// Project description
// -------------------
// Name: SDL Input
// Description: Common SDL Input Functions
//
// Author: Falcon4ever (nJoy@falcon4ever.com, www.multigesture.net), JPeterson etc
// Copyright (C) 2003 Dolphin Project.
//
//
// Licensetype: GNU General Public License (GPL)
//
// 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
// -------------------
#define _SDL_MAIN_ // Avoid certain declarations in SDL.h
#include "SDL.h" // Local
#include "XInput.h"
// Definitions
// -------------------
int g_LastPad = 0;
namespace InputCommon
{
// Definitions
// -------------------
// Search attached devices. Populate joyinfo for all attached physical devices.
// -----------------------
bool SearchDevices(std::vector<CONTROLLER_INFO> &_joyinfo, int &_NumPads, int &_NumGoodPads)
{
if (!SDL_WasInit(0))
#if SDL_VERSION_ATLEAST(1, 3, 0)
if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC) < 0)
#else
if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
#endif
{
PanicAlert("Could not initialize SDL: %s", SDL_GetError());
return false;
}
// Get device status
int numjoy = SDL_NumJoysticks();
for (int i = 0; i < numjoy; i++ )
{
CONTROLLER_INFO Tmp;
Tmp.joy = SDL_JoystickOpen(i);
Tmp.ID = i;
Tmp.NumAxes = SDL_JoystickNumAxes(Tmp.joy);
Tmp.NumButtons = SDL_JoystickNumButtons(Tmp.joy);
Tmp.NumBalls = SDL_JoystickNumBalls(Tmp.joy);
Tmp.NumHats = SDL_JoystickNumHats(Tmp.joy);
Tmp.Name = SDL_JoystickName(i);
// Check if the device is okay
if ( Tmp.NumAxes == 0
&& Tmp.NumBalls == 0
&& Tmp.NumButtons == 0
&& Tmp.NumHats == 0
)
{
Tmp.Good = false;
}
else
{
_NumGoodPads++;
Tmp.Good = true;
}
_joyinfo.push_back(Tmp);
// We have now read the values we need so we close the device
if (SDL_JoystickOpened(i)) SDL_JoystickClose(_joyinfo[i].joy);
}
_NumPads = (int)_joyinfo.size();
return true;
}
// Supporting functions
// ----------------
// Read current joystick status
/* ----------------
The value PadMapping[].buttons[] is the number of the assigned joypad button,
PadState[].buttons[] is the status of the button, it becomes 0 (no pressed) or 1 (pressed) */
// Read buttons status. Called from GetJoyState().
// ----------------------
void ReadButton(CONTROLLER_STATE &_PadState, CONTROLLER_MAPPING _PadMapping, int button, int NumButtons)
{
int ctl_button = _PadMapping.buttons[button];
if (ctl_button < NumButtons)
{
_PadState.buttons[button] = SDL_JoystickGetButton(_PadState.joy, ctl_button);
}
}
// Request joystick state.
// ----------------------
/* Called from: PAD_GetStatus()
Input: The virtual device 0, 1, 2 or 3
Function: Updates the PadState struct with the current pad status. The input value "controller" is
for a virtual controller 0 to 3. */
void GetJoyState(CONTROLLER_STATE &_PadState, CONTROLLER_MAPPING _PadMapping, int Controller, int NumButtons)
{
// Update the gamepad status
SDL_JoystickUpdate();
// Update axis states. It doesn't hurt much if we happen to ask for nonexisting axises here.
_PadState.axis[CTL_MAIN_X] = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.axis[CTL_MAIN_X]);
_PadState.axis[CTL_MAIN_Y] = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.axis[CTL_MAIN_Y]);
_PadState.axis[CTL_SUB_X] = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.axis[CTL_SUB_X]);
_PadState.axis[CTL_SUB_Y] = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.axis[CTL_SUB_Y]);
// Update the analog trigger axis values
#ifdef _WIN32
if (_PadMapping.triggertype == 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
if(_PadMapping.buttons[CTL_L_SHOULDER] >= 1000) _PadState.axis[CTL_L_SHOULDER] = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.buttons[CTL_L_SHOULDER] - 1000); else _PadState.axis[CTL_L_SHOULDER] = 0;
if(_PadMapping.buttons[CTL_R_SHOULDER] >= 1000) _PadState.axis[CTL_R_SHOULDER] = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.buttons[CTL_R_SHOULDER] - 1000); else _PadState.axis[CTL_R_SHOULDER] = 0;
#ifdef _WIN32
}
else
{
// XInput triggers for Xbox360 pads
_PadState.axis[CTL_L_SHOULDER] = XInput::GetXI(0, _PadMapping.buttons[CTL_L_SHOULDER] - 1000);
_PadState.axis[CTL_R_SHOULDER] = XInput::GetXI(0, _PadMapping.buttons[CTL_R_SHOULDER] - 1000);
}
#endif
// Update button states to on or off
ReadButton(_PadState, _PadMapping, CTL_L_SHOULDER, NumButtons);
ReadButton(_PadState, _PadMapping, CTL_R_SHOULDER, NumButtons);
ReadButton(_PadState, _PadMapping, CTL_A_BUTTON, NumButtons);
ReadButton(_PadState, _PadMapping, CTL_B_BUTTON, NumButtons);
ReadButton(_PadState, _PadMapping, CTL_X_BUTTON, NumButtons);
ReadButton(_PadState, _PadMapping, CTL_Y_BUTTON, NumButtons);
ReadButton(_PadState, _PadMapping, CTL_Z_TRIGGER, NumButtons);
ReadButton(_PadState, _PadMapping, CTL_START, NumButtons);
// Update Halfpress state, this one is not in the standard _PadState.buttons array
if (_PadMapping.halfpress < NumButtons && _PadMapping.halfpress >= 0)
_PadState.halfpress = SDL_JoystickGetButton(_PadState.joy, _PadMapping.halfpress);
else
_PadState.halfpress = 0;
// Check if we have an analog or digital joypad
if (_PadMapping.controllertype == CTL_DPAD_HAT)
{
_PadState.dpad = SDL_JoystickGetHat(_PadState.joy, _PadMapping.dpad);
}
else
{
// Only do this if the assigned button is in range (to allow for the current way of saving keyboard
// keys in the same array)
if(_PadMapping.dpad2[CTL_D_PAD_UP] <= NumButtons)
_PadState.dpad2[CTL_D_PAD_UP] = SDL_JoystickGetButton(_PadState.joy, _PadMapping.dpad2[CTL_D_PAD_UP]);
if(_PadMapping.dpad2[CTL_D_PAD_DOWN] <= NumButtons)
_PadState.dpad2[CTL_D_PAD_DOWN] = SDL_JoystickGetButton(_PadState.joy, _PadMapping.dpad2[CTL_D_PAD_DOWN]);
if(_PadMapping.dpad2[CTL_D_PAD_LEFT] <= NumButtons)
_PadState.dpad2[CTL_D_PAD_LEFT] = SDL_JoystickGetButton(_PadState.joy, _PadMapping.dpad2[CTL_D_PAD_LEFT]);
if(_PadMapping.dpad2[CTL_D_PAD_RIGHT] <= NumButtons)
_PadState.dpad2[CTL_D_PAD_RIGHT] = SDL_JoystickGetButton(_PadState.joy, _PadMapping.dpad2[CTL_D_PAD_RIGHT]);
}
#ifdef SHOW_PAD_STATUS
// Show the status of all connected pads
//ConsoleListener* Console = LogManager::GetInstance()->getConsoleListener();
//if ((g_LastPad == 0 && Controller == 0) || Controller < g_LastPad) Console->ClearScreen();
g_LastPad = Controller;
NOTICE_LOG(CONSOLE,
"Pad | Number:%i Enabled:%i Handle:%i\n"
"Main Stick | X:%03i Y:%03i\n"
"C Stick | X:%03i Y:%03i\n"
"Trigger | Type:%s DigitalL:%i DigitalR:%i AnalogL:%03i AnalogR:%03i HalfPress:%i\n"
"Buttons | A:%i X:%i\n"
"D-Pad | Type:%s Hat:%i U:%i D:%i\n"
"======================================================\n",
Controller, _PadMapping.enabled, _PadState.joy,
_PadState.axis[InputCommon::CTL_MAIN_X], _PadState.axis[InputCommon::CTL_MAIN_Y],
_PadState.axis[InputCommon::CTL_SUB_X], _PadState.axis[InputCommon::CTL_SUB_Y],
(_PadMapping.triggertype ? "CTL_TRIGGER_XINPUT" : "CTL_TRIGGER_SDL"),
_PadState.buttons[InputCommon::CTL_L_SHOULDER], _PadState.buttons[InputCommon::CTL_R_SHOULDER],
_PadState.axis[InputCommon::CTL_L_SHOULDER], _PadState.axis[InputCommon::CTL_R_SHOULDER],
_PadState.halfpress,
_PadState.buttons[InputCommon::CTL_A_BUTTON], _PadState.buttons[InputCommon::CTL_X_BUTTON],
(_PadMapping.controllertype ? "CTL_DPAD_CUSTOM" : "CTL_DPAD_HAT"),
_PadState.dpad,
_PadState.dpad2[InputCommon::CTL_D_PAD_UP], _PadState.dpad2[InputCommon::CTL_D_PAD_DOWN]
);
#endif
}
// Configure button mapping
// ----------
// Avoid extreme axis values
// ---------------------
/* Function: We have to avoid very big values to becuse some triggers are -0x8000 in the
unpressed state (and then go from -0x8000 to 0x8000 as they are fully pressed) */
bool AvoidValues(int value, bool NoTriggerFilter)
{
// Avoid detecting very small or very big (for triggers) values
if( (value > -0x2000 && value < 0x2000) // Small values
|| ((value < -0x6000 || value > 0x6000) && !NoTriggerFilter)) // Big values
return true; // Avoid
else
return false; // Keep
}
// Detect a pressed button
// ---------------------
void GetButton(SDL_Joystick *joy, int ControllerID, int buttons, int axes, int hats,
int &KeyboardKey, int &value, int &type, int &pressed, bool &Succeed, bool &Stop,
bool LeftRight, bool Axis, bool XInput, bool Button, bool Hat, bool NoTriggerFilter)
{
// It needs the wxWidgets excape keycode
static const int WXK_ESCAPE = 27;
// Update the internal status
SDL_JoystickUpdate();
// For the triggers we accept both a digital or an analog button
if(Axis)
{
for(int i = 0; i < axes; i++)
{
value = SDL_JoystickGetAxis(joy, i);
if(AvoidValues(value, NoTriggerFilter)) continue; // Avoid values
pressed = i + (LeftRight ? 1000 : 0); // Identify the analog triggers
type = InputCommon::CTL_AXIS;
Succeed = true;
}
}
// Check for a hat
if(Hat)
{
for(int i = 0; i < hats; i++)
{
value = SDL_JoystickGetHat(joy, i);
if(value)
{
pressed = i;
type = InputCommon::CTL_HAT;
Succeed = true;
}
}
}
// Check for a button
if(Button)
{
for(int i = 0; i < buttons; i++)
{
// Some kind of bug in SDL 1.3 would give button 9 and 10 (nonexistent) the value 48 on the 360 pad
if (SDL_JoystickGetButton(joy, i) > 1) continue;
if(SDL_JoystickGetButton(joy, i))
{
pressed = i;
type = InputCommon::CTL_BUTTON;
Succeed = true;
}
}
}
// Check for a XInput trigger
#ifdef _WIN32
if(XInput)
{
for(int i = 0; i <= InputCommon::XI_TRIGGER_R; i++)
{
if(XInput::GetXI(0, i))
{
pressed = i + 1000;
type = InputCommon::CTL_AXIS;
Succeed = true;
}
}
}
#endif
// Check for keyboard action
if (KeyboardKey)
{
if(Button)
{
// Todo: Add a separate keyboard vector to remove this restriction
if(KeyboardKey >= buttons)
{
pressed = KeyboardKey;
type = InputCommon::CTL_BUTTON;
Succeed = true;
KeyboardKey = 0;
if(pressed == WXK_ESCAPE) pressed = -1; // Check for the escape key
}
// Else show the error message
else
{
pressed = KeyboardKey;
KeyboardKey = -1;
Stop = true;
}
}
// Only accept the escape key
else if (KeyboardKey == WXK_ESCAPE)
{
Succeed = true;
KeyboardKey = 0;
pressed = -1;
}
}
}
/////////////////////////////////////////////////////////// Configure button mapping
} // InputCommon

View File

@ -0,0 +1,269 @@
// Project description
// -------------------
// Name: SDL Input
// Description: Common SDL Input Functions
//
// Author: Falcon4ever (nJoy@falcon4ever.com, www.multigesture.net), JPeterson etc
// Copyright (C) 2003 Dolphin Project.
//
//
// Licensetype: GNU General Public License (GPL)
//
// 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/
//
#ifndef _SDL_h
#define _SDL_h
// Include
// -------------------
#include <iostream> // System
#include <vector>
#include <cmath>
#ifdef _WIN32
#include <SDL.h> // Externals
#include <SDL_version.h>
#if SDL_VERSION_ATLEAST(1, 3, 0)
#include <SDL_haptic.h>
#endif
#else
#include <SDL/SDL.h>
#include <SDL/SDL_version.h>
#if SDL_VERSION_ATLEAST(1, 3, 0)
#include <SDL/SDL_haptic.h>
#endif
#endif
#include "Common.h" // Common
namespace InputCommon
{
// Settings
// ----------
// Show a status window with the detected axes, buttons and so on
//#define SHOW_PAD_STATUS
// Structures
/* -------------------
CONTROLLER_STATE buttons (PadState) = 0 or 1
CONTROLLER_MAPPING buttons (joystick) = 0 or 1, 2, 3, 4, a certain joypad button
Please remember: The axis limit is hardcoded here, if you allow more axises (for
example for analog A and B buttons) you must first incrase the size of the axis array
size here
*/
struct CONTROLLER_STATE // GC PAD INFO/STATE
{
int buttons[8]; // Amount of buttons (A B X Y Z, L-Trigger R-Trigger Start) might need to change the triggers buttons
int dpad; // Automatic SDL D-Pad (8 directions + neutral)
int dpad2[4]; // D-pad using buttons
int axis[6]; // 2 x 2 Axes (Main & Sub)
int halfpress; // Halfpress... you know, like not fully pressed ;)...
SDL_Joystick *joy; // SDL joystick device
};
struct CONTROLLER_MAPPING // GC PAD MAPPING
{
int buttons[8]; // (See above)
int dpad; // (See above)
int dpad2[4]; // (See above)
int axis[6]; // (See above)
int halfpress; // (See above)
int deadzone; // Deadzone... what else?
int ID; // SDL joystick device ID
int controllertype; // Hat: Hat or custom buttons
int triggertype; // Triggers range
std::string SRadius, SDiagonal, SRadiusC, SDiagonalC;
bool bRadiusOnOff, bSquareToCircle, bRadiusOnOffC, bSquareToCircleC;
bool rumble;
bool enable;
int eventnum; // Linux Event Number, Can't be found dynamically yet
};
struct CONTROLLER_INFO // CONNECTED WINDOWS DEVICES INFO
{
int NumAxes; // Amount of Axes
int NumButtons; // Amount of Buttons
int NumBalls; // Amount of Balls
int NumHats; // Amount of Hats (POV)
std::string Name; // Joypad/stickname
int ID; // SDL joystick device ID
bool Good; // Pad is good (it has at least one button or axis)
SDL_Joystick *joy; // SDL joystick device
};
enum
{
// CTL_L_SHOULDER and CTL_R_SHOULDER = 0 and 1
CTL_MAIN_X = 2,
CTL_MAIN_Y,
CTL_SUB_X,
CTL_SUB_Y
};
enum
{
CTL_L_SHOULDER = 0,
CTL_R_SHOULDER,
CTL_A_BUTTON,
CTL_B_BUTTON,
CTL_X_BUTTON,
CTL_Y_BUTTON,
CTL_Z_TRIGGER,
CTL_START
};
// DPad Type
enum
{
CTL_DPAD_HAT = 0, // Automatically use the first hat that SDL finds
CTL_DPAD_CUSTOM // Custom directional pad settings
};
// Trigger Type
enum
{
CTL_TRIGGER_SDL = 0, //
CTL_TRIGGER_XINPUT // The XBox 360 pad
};
enum
{
CTL_D_PAD_UP = 0,
CTL_D_PAD_DOWN,
CTL_D_PAD_LEFT,
CTL_D_PAD_RIGHT
};
// Button type for the configuration
enum
{
CTL_AXIS = 0,
CTL_HAT,
CTL_BUTTON,
CTL_KEY
};
// XInput buttons
enum
{
XI_TRIGGER_L = 0,
XI_TRIGGER_R
};
union PadAxis
{
int keyForControls[6];
struct
{
int Lx;
int Ly;
int Rx;
int Ry;
int Tl; // Trigger
int Tr; // Trigger
};
};
struct PadWiimote
{
int keyForControls[16];
// Order is A, B, 1, 2, +, -, Home
// L, R, U, D, RollL, RollR, PitchU, PitchD, Shake
};
struct PadNunchuck
{
int keyForControls[7];
// Order is Z, C, L, R, U, D, Shake
};
struct PadClassicController
{
int keyForControls[23];
// Order is A, B, X, Y, +, -, Home
// Tl, Zl, Zr, Tr, Dl, Dr, Du, Dd
// Ll, Lr, Lu, Ld, Rl, Rr, Ru, Rd
};
struct PadGH3Controller
{
int keyForControls[14];
// Order is Green, Red, Yellow, Blue, Orange,
// +, -, Whammy,
// Al, Ar, Au, Ad,
// StrumUp, StrumDown
};
struct CONTROLLER_STATE_NEW // GC PAD INFO/STATE
{
PadAxis Axis; // 6 Axes (Main, Sub, Triggers)
SDL_Joystick *joy; // SDL joystick device
};
struct CONTROLLER_MAPPING_NEW // GC PAD MAPPING
{
PadAxis Axis; // (See above)
PadWiimote Wm;
PadNunchuck Nc;
PadClassicController Cc;
PadGH3Controller GH3c;
bool enabled; // Pad attached?
bool Rumble;
int RumbleStrength;
int DeadZoneL; // Analog 1 Deadzone
int DeadZoneR; // Analog 2 Deadzone
int ID; // SDL joystick device ID
int controllertype; // D-Pad type: Hat or custom buttons
int triggertype; // SDL or XInput trigger
std::string SDiagonal;
bool bSquareToCircle;
bool bCircle2Square;
};
// Declarations
// ---------
// General functions
bool SearchDevices(std::vector<CONTROLLER_INFO> &_joyinfo, int &NumPads, int &NumGoodPads);
void GetJoyState(CONTROLLER_STATE &_PadState, CONTROLLER_MAPPING _PadMapping, int controller, int NumButtons);
void GetButton(SDL_Joystick*, int,int,int,int, int&,int&,int&,int&,bool&,bool&, bool,bool,bool,bool,bool,bool);
// Value conversion
float Deg2Rad(float Deg);
float Rad2Deg(float Rad);
int Pad_Convert(int _val);
float SquareDistance(float deg);
bool IsDeadZone(float DeadZone, int x, int y);
void Square2Circle(int &_x, int &_y, int _pad, std::string SDiagonal, bool Circle2Square = false);
void RadiusAdjustment(int &_x, int &_y, int _pad, std::string SRadius);
// Input configuration
std::string VKToString(int keycode);
#ifndef _SDL_MAIN_
extern int g_LastPad;
#endif
} // InputCommon
#endif // _SDL_h

View File

@ -0,0 +1,156 @@
// 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 "X11InputBase.h"
#include <string.h>
#include <stdio.h>
#include <ctype.h>
namespace InputCommon
{
#if defined(HAVE_WX) && HAVE_WX
// Taken from wxw source code
KeySym wxCharCodeWXToX(int id)
{
KeySym keySym;
switch (id)
{
case WXK_CANCEL: keySym = XK_Cancel; break;
case WXK_BACK: keySym = XK_BackSpace; break;
case WXK_TAB: keySym = XK_Tab; break;
case WXK_CLEAR: keySym = XK_Clear; break;
case WXK_RETURN: keySym = XK_Return; break;
case WXK_SHIFT: keySym = XK_Shift_L; break;
case WXK_CONTROL: keySym = XK_Control_L; break;
case WXK_ALT: keySym = XK_Meta_L; break;
case WXK_CAPITAL: keySym = XK_Caps_Lock; break;
case WXK_MENU : keySym = XK_Menu; break;
case WXK_PAUSE: keySym = XK_Pause; break;
case WXK_ESCAPE: keySym = XK_Escape; break;
case WXK_SPACE: keySym = ' '; break;
case WXK_PAGEUP: keySym = XK_Prior; break;
case WXK_PAGEDOWN: keySym = XK_Next; break;
case WXK_END: keySym = XK_End; break;
case WXK_HOME : keySym = XK_Home; break;
case WXK_LEFT : keySym = XK_Left; break;
case WXK_UP: keySym = XK_Up; break;
case WXK_RIGHT: keySym = XK_Right; break;
case WXK_DOWN : keySym = XK_Down; break;
case WXK_SELECT: keySym = XK_Select; break;
case WXK_PRINT: keySym = XK_Print; break;
case WXK_EXECUTE: keySym = XK_Execute; break;
case WXK_INSERT: keySym = XK_Insert; break;
case WXK_DELETE: keySym = XK_Delete; break;
case WXK_HELP : keySym = XK_Help; break;
case WXK_NUMPAD0: keySym = XK_KP_0; break; case WXK_NUMPAD_INSERT: keySym = XK_KP_Insert; break;
case WXK_NUMPAD1: keySym = XK_KP_1; break; case WXK_NUMPAD_END: keySym = XK_KP_End; break;
case WXK_NUMPAD2: keySym = XK_KP_2; break; case WXK_NUMPAD_DOWN: keySym = XK_KP_Down; break;
case WXK_NUMPAD3: keySym = XK_KP_3; break; case WXK_NUMPAD_PAGEDOWN: keySym = XK_KP_Page_Down; break;
case WXK_NUMPAD4: keySym = XK_KP_4; break; case WXK_NUMPAD_LEFT: keySym = XK_KP_Left; break;
case WXK_NUMPAD5: keySym = XK_KP_5; break;
case WXK_NUMPAD6: keySym = XK_KP_6; break; case WXK_NUMPAD_RIGHT: keySym = XK_KP_Right; break;
case WXK_NUMPAD7: keySym = XK_KP_7; break; case WXK_NUMPAD_HOME: keySym = XK_KP_Home; break;
case WXK_NUMPAD8: keySym = XK_KP_8; break; case WXK_NUMPAD_UP: keySym = XK_KP_Up; break;
case WXK_NUMPAD9: keySym = XK_KP_9; break; case WXK_NUMPAD_PAGEUP: keySym = XK_KP_Page_Up; break;
case WXK_NUMPAD_DECIMAL: keySym = XK_KP_Decimal; break; case WXK_NUMPAD_DELETE: keySym = XK_KP_Delete; break;
case WXK_NUMPAD_MULTIPLY: keySym = XK_KP_Multiply; break;
case WXK_NUMPAD_ADD: keySym = XK_KP_Add; break;
case WXK_NUMPAD_SUBTRACT: keySym = XK_KP_Subtract; break;
case WXK_NUMPAD_DIVIDE: keySym = XK_KP_Divide; break;
case WXK_NUMPAD_ENTER: keySym = XK_KP_Enter; break;
case WXK_NUMPAD_SEPARATOR: keySym = XK_KP_Separator; break;
case WXK_F1: keySym = XK_F1; break;
case WXK_F2: keySym = XK_F2; break;
case WXK_F3: keySym = XK_F3; break;
case WXK_F4: keySym = XK_F4; break;
case WXK_F5: keySym = XK_F5; break;
case WXK_F6: keySym = XK_F6; break;
case WXK_F7: keySym = XK_F7; break;
case WXK_F8: keySym = XK_F8; break;
case WXK_F9: keySym = XK_F9; break;
case WXK_F10: keySym = XK_F10; break;
case WXK_F11: keySym = XK_F11; break;
case WXK_F12: keySym = XK_F12; break;
case WXK_F13: keySym = XK_F13; break;
case WXK_F14: keySym = XK_F14; break;
case WXK_F15: keySym = XK_F15; break;
case WXK_F16: keySym = XK_F16; break;
case WXK_F17: keySym = XK_F17; break;
case WXK_F18: keySym = XK_F18; break;
case WXK_F19: keySym = XK_F19; break;
case WXK_F20: keySym = XK_F20; break;
case WXK_F21: keySym = XK_F21; break;
case WXK_F22: keySym = XK_F22; break;
case WXK_F23: keySym = XK_F23; break;
case WXK_F24: keySym = XK_F24; break;
case WXK_NUMLOCK: keySym = XK_Num_Lock; break;
case WXK_SCROLL: keySym = XK_Scroll_Lock; break;
default: keySym = id <= 255 ? (KeySym)id : 0;
}
return keySym;
}
#else
KeySym wxCharCodeWXToX(int id)
{
return NULL;
}
#endif
void XKeyToString(unsigned int keycode, char *keyStr) {
switch (keycode) {
case XK_Left:
sprintf(keyStr, "LEFT");
break;
case XK_Up:
sprintf(keyStr, "UP");
break;
case XK_Right:
sprintf(keyStr, "RIGHT");
break;
case XK_Down:
sprintf(keyStr, "DOWN");
break;
case XK_Return:
sprintf(keyStr, "RETURN");
break;
case XK_KP_Enter:
sprintf(keyStr, "KP ENTER");
break;
case XK_KP_Left:
sprintf(keyStr, "KP LEFT");
break;
case XK_KP_Up:
sprintf(keyStr, "KP UP");
break;
case XK_KP_Right:
sprintf(keyStr, "KP RIGHT");
break;
case XK_KP_Down:
sprintf(keyStr, "KP DOWN");
break;
case XK_Shift_L:
sprintf(keyStr, "LShift");
break;
case XK_Control_L:
sprintf(keyStr, "LControl");
break;
default:
sprintf(keyStr, "%c", toupper(keycode));
}
}
}

View File

@ -0,0 +1,32 @@
// 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/
#ifndef XINPUTBASE_H
#define XINPUTBASE_H
#include <X11/X.h>
#include <X11/keysym.h>
#include "Config.h"
#if defined(HAVE_WX) && HAVE_WX
#include <wx/wx.h>
#endif
namespace InputCommon
{
KeySym wxCharCodeWXToX(int id);
void XKeyToString(unsigned int keycode, char *keyStr);
}
#endif

View File

@ -0,0 +1,136 @@
//
// Licensetype: GNU General Public License (GPL)
//
// 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/
//
// File description
/* -------------------
Function: This file will get the status of the analog triggers of any connected XInput device.
This code was made with the help of SimpleController.cpp in the June 2008 Microsoft DirectX SDK
Samples.
///////////////////////////////////////////////////// */
#ifdef _WIN32
// Includes
// -------------------
#include <windows.h>
#include <XInput.h> // XInput API
#include "SDL.h" // Local
namespace XInput
{
// Declarations
// -------------------
#define MAX_CONTROLLERS 4 // XInput handles up to 4 controllers
struct CONTROLER_STATE
{
XINPUT_STATE state;
bool bConnected;
};
CONTROLER_STATE g_Controllers[MAX_CONTROLLERS];
// Init
// -------------------
/* Function: Calculate the number of connected XInput devices
Todo: Implement this to figure out if there are multiple XInput controllers connected,
we currently only try to connect to XInput device 0 */
void Init()
{
// Init state
//ZeroMemory( g_Controllers, sizeof( CONTROLER_STATE ) * MAX_CONTROLLERS );
// Declaration
DWORD dwResult;
// Calculate the number of connected XInput devices
for( DWORD i = 0; i < MAX_CONTROLLERS; i++ )
{
// Simply get the state of the controller from XInput.
dwResult = XInputGetState( i, &g_Controllers[i].state );
if( dwResult == ERROR_SUCCESS )
g_Controllers[i].bConnected = true;
else
g_Controllers[i].bConnected = false;
}
}
// Get the trigger status
// -------------------
int GetXI(int Controller, int Button)
{
// Update the internal status
DWORD dwResult;
dwResult = XInputGetState( Controller, &g_Controllers[Controller].state );
if( dwResult != ERROR_SUCCESS ) return -1;
switch(Button)
{
case InputCommon::XI_TRIGGER_L:
return g_Controllers[0].state.Gamepad.bLeftTrigger;
case InputCommon::XI_TRIGGER_R:
return g_Controllers[0].state.Gamepad.bRightTrigger;
default:
return 0;
}
}
// Check if a certain controller is connected
// -------------------
bool IsConnected(int Controller)
{
DWORD dwResult = XInputGetState( Controller, &g_Controllers[Controller].state );
// Update the connected status
if( dwResult == ERROR_SUCCESS )
return true;
else
return false;
}
} // XInput
#endif

View File

@ -0,0 +1,46 @@
//
// Licensetype: GNU General Public License (GPL)
//
// 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/
//
#ifdef _WIN32
// Includes
// ----------
#include <iostream>
namespace XInput
{
// Declarations
// ----------
void Init();
int GetXI(int Controller, int Button);
bool IsConnected(int Controller);
} // XInput
#endif

View File

@ -0,0 +1,557 @@
// 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 <sstream>
#include "Common.h"
#include "ConfigDlg.h"
#include "../PadSimple.h"
#ifdef _WIN32
#include "XInput.h"
#include "../../InputCommon/DirectInputBase.h" // Core
DInput m_dinput;
#endif
BEGIN_EVENT_TABLE(PADConfigDialogSimple,wxDialog)
EVT_SHOW(PADConfigDialogSimple::OnShow)
EVT_CLOSE(PADConfigDialogSimple::OnClose)
EVT_BUTTON(ID_CLOSE,PADConfigDialogSimple::OnCloseClick)
EVT_BUTTON(ID_PAD_ABOUT,PADConfigDialogSimple::DllAbout)
EVT_CHECKBOX(ID_X360PAD,PADConfigDialogSimple::ControllerSettingsChanged)
EVT_CHOICE(ID_X360PAD_CHOICE,PADConfigDialogSimple::ControllerSettingsChanged)
EVT_CHECKBOX(ID_RUMBLE,PADConfigDialogSimple::ControllerSettingsChanged)
EVT_CHECKBOX(ID_DISABLE,PADConfigDialogSimple::ControllerSettingsChanged)
// Input recording
#ifdef RERECORDING
EVT_CHECKBOX(ID_RECORDING,PADConfigDialogSimple::ControllerSettingsChanged)
EVT_CHECKBOX(ID_PLAYBACK,PADConfigDialogSimple::ControllerSettingsChanged)
EVT_BUTTON(ID_SAVE_RECORDING,PADConfigDialogSimple::ControllerSettingsChanged)
#endif
EVT_BUTTON(CTL_A, PADConfigDialogSimple::OnButtonClick)
EVT_BUTTON(CTL_B, PADConfigDialogSimple::OnButtonClick)
EVT_BUTTON(CTL_X, PADConfigDialogSimple::OnButtonClick)
EVT_BUTTON(CTL_Y, PADConfigDialogSimple::OnButtonClick)
EVT_BUTTON(CTL_Z, PADConfigDialogSimple::OnButtonClick)
EVT_BUTTON(CTL_START, PADConfigDialogSimple::OnButtonClick)
EVT_BUTTON(CTL_L, PADConfigDialogSimple::OnButtonClick)
EVT_BUTTON(CTL_R, PADConfigDialogSimple::OnButtonClick)
EVT_BUTTON(CTL_L_SEMI, PADConfigDialogSimple::OnButtonClick)
EVT_BUTTON(CTL_R_SEMI, PADConfigDialogSimple::OnButtonClick)
EVT_SLIDER(ID_TRIGGER_SEMIVALUE, PADConfigDialogSimple::ControllerSettingsChanged)
EVT_BUTTON(CTL_MAINUP, PADConfigDialogSimple::OnButtonClick)
EVT_BUTTON(CTL_MAINDOWN, PADConfigDialogSimple::OnButtonClick)
EVT_BUTTON(CTL_MAINLEFT, PADConfigDialogSimple::OnButtonClick)
EVT_BUTTON(CTL_MAINRIGHT, PADConfigDialogSimple::OnButtonClick)
EVT_BUTTON(CTL_MAIN_SEMI, PADConfigDialogSimple::OnButtonClick)
EVT_SLIDER(ID_MAIN_SEMIVALUE, PADConfigDialogSimple::ControllerSettingsChanged)
EVT_BUTTON(CTL_SUBUP, PADConfigDialogSimple::OnButtonClick)
EVT_BUTTON(CTL_SUBDOWN, PADConfigDialogSimple::OnButtonClick)
EVT_BUTTON(CTL_SUBLEFT, PADConfigDialogSimple::OnButtonClick)
EVT_SLIDER(ID_SUB_SEMIVALUE, PADConfigDialogSimple::ControllerSettingsChanged)
EVT_BUTTON(CTL_SUBRIGHT, PADConfigDialogSimple::OnButtonClick)
EVT_BUTTON(CTL_SUB_SEMI, PADConfigDialogSimple::OnButtonClick)
EVT_BUTTON(CTL_DPADUP, PADConfigDialogSimple::OnButtonClick)
EVT_BUTTON(CTL_DPADDOWN, PADConfigDialogSimple::OnButtonClick)
EVT_BUTTON(CTL_DPADLEFT, PADConfigDialogSimple::OnButtonClick)
EVT_BUTTON(CTL_DPADRIGHT, PADConfigDialogSimple::OnButtonClick)
END_EVENT_TABLE()
PADConfigDialogSimple::PADConfigDialogSimple(wxWindow *parent, wxWindowID id, const wxString &title, const wxPoint &position, const wxSize& size, long style)
: wxDialog(parent, id, title, position, size, style)
{
ClickedButton = NULL;
CreateGUIControls();
Fit();
// Connect keydown to the window
wxTheApp->Connect(wxID_ANY, wxEVT_KEY_DOWN,
wxKeyEventHandler(PADConfigDialogSimple::OnKeyDown),
(wxObject*)NULL, this);
Show();
}
PADConfigDialogSimple::~PADConfigDialogSimple()
{
}
// Create input button controls
// -------------------
inline void AddControl(wxPanel *pan, wxButton **button,
wxStaticBoxSizer *sizer, const char *name, int ctl, int controller)
{
wxBoxSizer *hButton = new wxBoxSizer(wxHORIZONTAL);
char keyStr[10] = {0};
// Add the label
hButton->Add(new wxStaticText(pan, 0, wxString::FromAscii(name),
wxDefaultPosition, wxDefaultSize), 0,
wxALIGN_CENTER_VERTICAL|wxALL);
// Give it the mapped key name
#ifdef _WIN32
DInput::DIKToString(pad[controller].keyForControl[ctl], keyStr);
#elif defined(HAVE_X11) && HAVE_X11
InputCommon::XKeyToString(pad[controller].keyForControl[ctl], keyStr);
#endif
// Add the button to its sizer
*button = new wxButton(pan, ctl, wxString::FromAscii(keyStr),
wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS);
hButton->Add(*button, 0, wxALIGN_RIGHT|wxALL);
sizer->Add(hButton, 0, wxALIGN_RIGHT|wxALL);
}
// Create input slider controls
// -------------------
inline void PADConfigDialogSimple::AddSlider(wxPanel *pan, wxSlider **slider,
wxStaticBoxSizer *sizer, const char *name, int ctl, int controller)
{
wxBoxSizer *hSlider = new wxBoxSizer(wxHORIZONTAL);
int semivalue, maxvalue;
std::stringstream ss;
// Add the label
hSlider->Add(new wxStaticText(pan, 0, wxString::FromAscii(name),
wxDefaultPosition, wxDefaultSize), 0,
wxALIGN_CENTER_VERTICAL|wxALL);
// Do everything else
switch (ctl)
{
case ID_TRIGGER_SEMIVALUE:
semivalue = pad[controller].Trigger_semivalue;
maxvalue = TRIGGER_FULL;
// Add the slider to its sizer
*slider = new wxSlider(pan, ctl, semivalue, 0, maxvalue, wxDefaultPosition, wxSize(100,-1));
(**slider).SetPageSize(32);
hSlider->Add(*slider, 0, wxALIGN_RIGHT|wxALL);
sizer->Add(hSlider, 0, wxALIGN_RIGHT|wxALL);
// Add numeric value label to sizer
ss << pad[controller].Trigger_semivalue;
m_Trigger_SemiValue_Label[controller] = new wxStaticText(pan, 0,
wxString::FromAscii( ss.str().c_str() ), wxDefaultPosition, wxSize(25, -1));
hSlider->Add(m_Trigger_SemiValue_Label[controller],
0, wxALIGN_CENTER_VERTICAL|wxALL);
break;
case ID_MAIN_SEMIVALUE:
semivalue = pad[controller].Main_stick_semivalue;
maxvalue = STICK_FULL;
// Add the slider to its sizer
*slider = new wxSlider(pan, ctl, semivalue, 0, maxvalue, wxDefaultPosition, wxSize(100, -1));
(**slider).SetPageSize(10);
hSlider->Add(*slider, 0, wxALIGN_RIGHT|wxALL);
sizer->Add(hSlider, 0, wxALIGN_RIGHT|wxALL);
// Add numeric value label to sizer
ss << pad[controller].Main_stick_semivalue;
m_Stick_SemiValue_Label[controller] = new wxStaticText(pan, 0,
wxString::FromAscii( ss.str().c_str() ), wxDefaultPosition, wxSize(25, -1));
hSlider->Add(m_Stick_SemiValue_Label[controller],
0, wxALIGN_CENTER_VERTICAL|wxALL);
break;
case ID_SUB_SEMIVALUE:
semivalue = pad[controller].Sub_stick_semivalue;
maxvalue = STICK_FULL;
// Add the slider to its sizer
*slider = new wxSlider(pan, ctl, semivalue, 0, maxvalue, wxDefaultPosition, wxSize(100,-1));
(**slider).SetPageSize(10);
hSlider->Add(*slider, 0, wxALIGN_RIGHT|wxALL);
sizer->Add(hSlider, 0, wxALIGN_RIGHT|wxALL);
// Add numeric value label to sizer
ss << pad[controller].Sub_stick_semivalue;
m_CStick_SemiValue_Label[controller] = new wxStaticText(pan, 0,
wxString::FromAscii( ss.str().c_str() ), wxDefaultPosition, wxSize(25, -1));
hSlider->Add(m_CStick_SemiValue_Label[controller],
0, wxALIGN_CENTER_VERTICAL|wxALL);
break;
}
}
void PADConfigDialogSimple::CreateGUIControls()
{
// Notebook
m_Notebook = new wxNotebook(this, ID_NOTEBOOK, wxDefaultPosition, wxDefaultSize);
// Controller pages
m_Controller[0] = new wxPanel(m_Notebook, ID_CONTROLLERPAGE1, wxDefaultPosition, wxDefaultSize);
m_Notebook->AddPage(m_Controller[0], wxT("Controller 1"));
m_Controller[1] = new wxPanel(m_Notebook, ID_CONTROLLERPAGE2, wxDefaultPosition, wxDefaultSize);
m_Notebook->AddPage(m_Controller[1], wxT("Controller 2"));
m_Controller[2] = new wxPanel(m_Notebook, ID_CONTROLLERPAGE3, wxDefaultPosition, wxDefaultSize);
m_Notebook->AddPage(m_Controller[2], wxT("Controller 3"));
m_Controller[3] = new wxPanel(m_Notebook, ID_CONTROLLERPAGE4, wxDefaultPosition, wxDefaultSize);
m_Notebook->AddPage(m_Controller[3], wxT("Controller 4"));
// Standard buttons
m_Close = new wxButton(this, ID_CLOSE, wxT("Close"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
m_About = new wxButton(this, ID_PAD_ABOUT, wxT("About"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
// Put notebook and standard buttons in sizers
wxBoxSizer* sSButtons;
sSButtons = new wxBoxSizer(wxHORIZONTAL);
sSButtons->Add(m_About,0,wxALL, 5);
sSButtons->Add(0, 0, 1, wxEXPAND, 5);
sSButtons->Add(m_Close, 0, wxALL, 5);
wxBoxSizer* sMain;
sMain = new wxBoxSizer(wxVERTICAL);
sMain->Add(m_Notebook, 1, wxEXPAND|wxALL, 5);
sMain->Add(sSButtons, 0, wxEXPAND, 5);
this->SetSizer(sMain);
this->Layout();
#ifdef _WIN32
// Add connected XPads
for (int x = 0; x < 4; x++)
{
XINPUT_STATE xstate;
DWORD xresult = XInputGetState(x, &xstate);
if (xresult == ERROR_SUCCESS)
{
arrayStringFor_X360Pad.Add(wxString::Format(wxT("%i"), x+1));
}
}
#endif
for(int i = 0; i < 4; i++)
{
// --------------------------------------------------------------------
// Settings
// -----------------------------
// Main horizontal container
sDevice[i] = new wxBoxSizer(wxHORIZONTAL);
sbDevice[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("Controller Settings"));
m_Disable[i] = new wxCheckBox(m_Controller[i], ID_DISABLE, wxT("Disable when Dolphin is not in focus"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
sbDevice[i]->Add(m_Disable[i], 0, wxEXPAND|wxALL, 1);
#ifdef _WIN32
m_SizeXInput[i] = new wxStaticBoxSizer(wxHORIZONTAL, m_Controller[i], wxT("XInput Pad"));
m_X360Pad[i] = new wxCheckBox(m_Controller[i], ID_X360PAD, wxT("Enable X360Pad"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
m_X360PadC[i] = new wxChoice(m_Controller[i], ID_X360PAD_CHOICE, wxDefaultPosition, wxDefaultSize, arrayStringFor_X360Pad, 0, wxDefaultValidator);
m_Rumble[i] = new wxCheckBox(m_Controller[i], ID_RUMBLE, wxT("Enable rumble"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
m_SizeXInput[i]->Add(m_X360Pad[i], 0, wxEXPAND | wxALL, 1);
m_SizeXInput[i]->Add(m_X360PadC[i], 0, wxEXPAND | wxALL, 1);
m_SizeXInput[i]->Add(m_Rumble[i], 0, wxEXPAND | wxALL, 1);
#endif
// Set values
m_Disable[i]->SetValue(pad[i].bDisable);
#ifdef _WIN32
// Check if any XInput pad was found
if (arrayStringFor_X360Pad.IsEmpty())
{
m_X360Pad[i]->SetLabel(wxT("Enable X360Pad - No pad connected"));
m_X360Pad[i]->SetValue(false);
m_X360Pad[i]->Enable(false);
pad[i].bEnableXPad = false;
m_X360PadC[i]->Hide();
m_Rumble[i]->Hide();
}
else
{
m_X360Pad[i]->SetValue(pad[i].bEnableXPad);
m_X360PadC[i]->SetSelection(pad[i].XPadPlayer);
m_X360PadC[i]->Enable(m_X360Pad[i]->IsChecked());
m_Rumble[i]->SetValue(pad[i].bRumble);
m_Rumble[i]->Enable(m_X360Pad[i]->IsChecked());
}
#endif
// Sizers
sDevice[i]->Add(sbDevice[i], 0, wxEXPAND | wxALL, 1);
//sDevice[i]->AddStretchSpacer();
#ifdef _WIN32
sDevice[i]->Add(m_SizeXInput[i], 0, wxEXPAND | wxALL, 1);
#endif
// -----------------------------------
// Rerecording
// ---------
#ifdef RERECORDING
// Create controls
m_SizeRecording[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("Input Recording"));
m_CheckRecording[i] = new wxCheckBox(m_Controller[i], ID_RECORDING, wxT("Record input"));
m_CheckPlayback[i] = new wxCheckBox(m_Controller[i], ID_PLAYBACK, wxT("Play back input"));
m_BtnSaveRecording[i] = new wxButton(m_Controller[i], ID_SAVE_RECORDING, wxT("Save recording"), wxDefaultPosition, wxDefaultSize);
// Tool tips
m_CheckRecording[i]->SetToolTip(wxT("Your recording will be saved to pad-record.bin in the Dolphin dir when you stop the game"));
m_CheckPlayback[i]->SetToolTip(wxT("Play back the pad-record.bin file from the Dolphin dir"));
m_BtnSaveRecording[i]->SetToolTip(wxT(
"This will save the current recording to pad-record.bin. Your recording will\n"
"also be automatically saved every 60 * 10 frames. And when you shut down the\n"
"game."));
// Sizers
m_SizeRecording[i]->Add(m_CheckRecording[i], 0, wxEXPAND | wxALL, 1);
m_SizeRecording[i]->Add(m_CheckPlayback[i], 0, wxEXPAND | wxALL, 1);
m_SizeRecording[i]->Add(m_BtnSaveRecording[i], 0, wxEXPAND | wxALL, 1);
// Only enable these options for pad 0
m_CheckRecording[i]->Enable(false); m_CheckRecording[0]->Enable(true);
m_CheckPlayback[i]->Enable(false); m_CheckPlayback[0]->Enable(true);
m_BtnSaveRecording[i]->Enable(false); m_BtnSaveRecording[0]->Enable(true);
// Don't allow saving when we are not recording
m_BtnSaveRecording[i]->Enable(g_EmulatorRunning && pad[0].bRecording);
sDevice[i]->Add(m_SizeRecording[i], 0, wxEXPAND | wxALL, 1);
// Set values
m_CheckRecording[0]->SetValue(pad[0].bRecording);
m_CheckPlayback[0]->SetValue(pad[0].bPlayback);
//DEBUG_LOG(CONSOLE, "m_CheckRecording: %i\n", pad[0].bRecording, pad[0].bPlayback);
#endif
// --------------------------------------------------------------------
// Buttons
// -----------------------------
sButtons[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("Buttons"));
AddControl(m_Controller[i], &(m_ButtonA[i]), sButtons[i], "A: ", CTL_A, i);
AddControl(m_Controller[i], &(m_ButtonB[i]), sButtons[i], "B: ", CTL_B, i);
AddControl(m_Controller[i], &(m_ButtonX[i]), sButtons[i], "X: ", CTL_X, i);
AddControl(m_Controller[i], &(m_ButtonY[i]), sButtons[i], "Y: ", CTL_Y, i);
AddControl(m_Controller[i], &(m_ButtonZ[i]), sButtons[i], "Z: ", CTL_Z, i);
AddControl(m_Controller[i], &(m_ButtonStart[i]), sButtons[i], "Start: ", CTL_START, i);
sTriggers[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("Triggers"));
AddControl(m_Controller[i], &(m_ButtonL[i]), sTriggers[i], "L: ", CTL_L, i);
AddControl(m_Controller[i], &(m_ButtonR[i]), sTriggers[i], "R: ", CTL_R, i);
AddControl(m_Controller[i], &(m_ButtonL_Semi[i]), sTriggers[i], "Semi-L: ", CTL_L_SEMI, i);
AddControl(m_Controller[i], &(m_ButtonR_Semi[i]), sTriggers[i], "Semi-R: ", CTL_R_SEMI, i);
AddSlider(m_Controller[i], &(m_Trigger_SemiValue[i]), sTriggers[i], "Semi: ", ID_TRIGGER_SEMIVALUE, i);
sStick[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("Main Stick"));
AddControl(m_Controller[i], &(m_StickUp[i]), sStick[i], "Up: ", CTL_MAINUP, i);
AddControl(m_Controller[i], &(m_StickDown[i]), sStick[i], "Down: ", CTL_MAINDOWN, i);
AddControl(m_Controller[i], &(m_StickLeft[i]), sStick[i], "Left: ", CTL_MAINLEFT, i);
AddControl(m_Controller[i], &(m_StickRight[i]), sStick[i], "Right: ", CTL_MAINRIGHT, i);
AddControl(m_Controller[i], &(m_Stick_Semi[i]), sStick[i], "Semi-press: ", CTL_MAIN_SEMI, i);
AddSlider(m_Controller[i], &(m_Stick_SemiValue[i]), sStick[i], "Semi: ", ID_MAIN_SEMIVALUE, i);
sDPad[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("D-Pad"));
AddControl(m_Controller[i], &(m_DPadUp[i]), sDPad[i], "Up: ", CTL_DPADUP, i);
AddControl(m_Controller[i], &(m_DPadDown[i]), sDPad[i], "Down: ", CTL_DPADDOWN, i);
AddControl(m_Controller[i], &(m_DPadLeft[i]), sDPad[i], "Left: ", CTL_DPADLEFT, i);
AddControl(m_Controller[i], &(m_DPadRight[i]), sDPad[i], "Right: ", CTL_DPADRIGHT, i);
sCStick[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("C-Stick"));
AddControl(m_Controller[i], &(m_CStickUp[i]), sCStick[i], "Up: ", CTL_SUBUP, i);
AddControl(m_Controller[i], &(m_CStickDown[i]), sCStick[i], "Down: ", CTL_SUBDOWN, i);
AddControl(m_Controller[i], &(m_CStickLeft[i]), sCStick[i], "Left: ", CTL_SUBLEFT, i);
AddControl(m_Controller[i], &(m_CStickRight[i]), sCStick[i], "Right: ", CTL_SUBRIGHT, i);
AddControl(m_Controller[i], &(m_CStick_Semi[i]), sCStick[i], "Semi-press: ", CTL_SUB_SEMI, i);
AddSlider(m_Controller[i], &(m_CStick_SemiValue[i]), sCStick[i], "Semi: ", ID_SUB_SEMIVALUE, i);
// --------------------------------------------------------------------
// Sizers
// -----------------------------
sPage[i] = new wxGridBagSizer(0, 0);
sPage[i]->SetFlexibleDirection(wxBOTH);
sPage[i]->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
sPage[i]->Add(sDevice[i], wxGBPosition(0, 0), wxGBSpan(1, 5), wxEXPAND|wxALL, 1);
sPage[i]->Add(sButtons[i], wxGBPosition(1, 0), wxGBSpan(2, 1), wxALL, 1);
sPage[i]->Add(sTriggers[i], wxGBPosition(1, 1), wxGBSpan(1, 1), wxEXPAND|wxALL, 1);
sPage[i]->Add(sStick[i], wxGBPosition(1, 2), wxGBSpan(2, 1), wxALL, 1);
sPage[i]->Add(sDPad[i], wxGBPosition(1, 3), wxGBSpan(2, 1), wxALL, 1);
sPage[i]->Add(sCStick[i], wxGBPosition(1, 4), wxGBSpan(2, 1), wxALL, 1);
m_Controller[i]->SetSizer(sPage[i]);
sPage[i]->Layout();
}
}
void PADConfigDialogSimple::OnClose(wxCloseEvent& event)
{
#ifdef _WIN32
m_dinput.Free();
#endif
EndModal(0);
}
void PADConfigDialogSimple::OnCloseClick(wxCommandEvent& event)
{
Close();
}
void PADConfigDialogSimple::OnShow(wxShowEvent& event)
{
#ifdef _WIN32
m_dinput.Init((HWND)this->GetParent());
#endif
}
void PADConfigDialogSimple::OnKeyDown(wxKeyEvent& event)
{
char keyStr[10] = {0};
if(ClickedButton)
{
// Get the selected notebook page
int page = m_Notebook->GetSelection();
#ifdef _WIN32
m_dinput.Read();
if (m_dinput.diks[DIK_ESCAPE])
{
pad[page].keyForControl[ClickedButton->GetId()] = 0x00;
ClickedButton->SetLabel(wxString::FromAscii(""));
}
else
{
for(int i = 0; i < 255; i++)
{
if(m_dinput.diks[i])
{
// Save the mapped key
pad[page].keyForControl[ClickedButton->GetId()] = i;
// Get the key name
DInput::DIKToString(i, keyStr);
ClickedButton->SetLabel(wxString::FromAscii(keyStr));
break;
}
}
}
#elif defined(HAVE_X11) && HAVE_X11
if (event.GetKeyCode() == (XK_Escape & 0xFF))
{
pad[page].keyForControl[ClickedButton->GetId()] = InputCommon::wxCharCodeWXToX(0x00);
ClickedButton->SetLabel(wxString::FromAscii(""));
}
else
{
pad[page].keyForControl[ClickedButton->GetId()] = InputCommon::wxCharCodeWXToX(event.GetKeyCode());
InputCommon::XKeyToString(pad[page].keyForControl[ClickedButton->GetId()], keyStr);
ClickedButton->SetLabel(wxString::FromAscii(keyStr));
}
#endif
ClickedButton->Disconnect();
}
// Reset
ClickedButton = NULL;
//event.Skip();
}
// We have clicked a button
void PADConfigDialogSimple::OnButtonClick(wxCommandEvent& event)
{
// Check if the Space key was set, to solve the problem that the Space key calls this function
#ifdef _WIN32
if (m_dinput.diks[DIK_SPACE]) { m_dinput.diks[DIK_SPACE] = 0; return; }
#endif
// If we come here again before any key was set
if(ClickedButton) ClickedButton->SetLabel(oldLabel);
// Save the old button label so we can reapply it if necessary
ClickedButton = (wxButton *)event.GetEventObject();
oldLabel = ClickedButton->GetLabel();
ClickedButton->SetLabel(_("Press Key/Esc"));
ClickedButton->SetWindowStyle(wxWANTS_CHARS);
}
void PADConfigDialogSimple::ControllerSettingsChanged(wxCommandEvent& event)
{
int page = m_Notebook->GetSelection();
std::stringstream ss;
switch (event.GetId())
{
// General settings
case ID_DISABLE:
pad[page].bDisable = m_Disable[page]->GetValue();
break;
// XInput
case ID_X360PAD:
pad[page].bEnableXPad = event.IsChecked();
m_Rumble[page]->Enable(event.IsChecked());
m_X360PadC[page]->Enable(event.IsChecked());
break;
case ID_X360PAD_CHOICE:
pad[page].XPadPlayer = event.GetSelection();
break;
case ID_RUMBLE:
pad[page].bRumble = m_Rumble[page]->GetValue();
break;
// Semi-press adjustment
case ID_TRIGGER_SEMIVALUE:
pad[page].Trigger_semivalue = m_Trigger_SemiValue[page]->GetValue();
ss << pad[page].Trigger_semivalue;
(*m_Trigger_SemiValue_Label[page]).SetLabel(wxString::FromAscii( ss.str().c_str() ));
break;
case ID_MAIN_SEMIVALUE:
pad[page].Main_stick_semivalue = m_Stick_SemiValue[page]->GetValue();
ss << pad[page].Main_stick_semivalue;
(*m_Stick_SemiValue_Label[page]).SetLabel(wxString::FromAscii( ss.str().c_str() ));
break;
case ID_SUB_SEMIVALUE:
pad[page].Sub_stick_semivalue = m_CStick_SemiValue[page]->GetValue();
ss << pad[page].Sub_stick_semivalue;
(*m_CStick_SemiValue_Label[page]).SetLabel(wxString::FromAscii( ss.str().c_str() ));
break;
// Input recording
#ifdef RERECORDING
case ID_RECORDING:
pad[page].bRecording = m_CheckRecording[page]->GetValue();
// Turn off the other option
pad[page].bPlayback = false; m_CheckPlayback[page]->SetValue(false);
break;
case ID_PLAYBACK:
pad[page].bPlayback = m_CheckPlayback[page]->GetValue();
// Turn off the other option
pad[page].bRecording = false; m_CheckRecording[page]->SetValue(false);
break;
case ID_SAVE_RECORDING:
// Double check again that we are still running a game
if (g_EmulatorRunning) SaveRecord();
break;
#endif
}
}
void PADConfigDialogSimple::DllAbout(wxCommandEvent& event)
{
wxString message;
#ifdef _WIN32
message = _("A simple keyboard and XInput plugin for dolphin.");
#else
message = _("A simple keyboard plugin for dolphin.");
#endif
wxMessageBox(_T("Dolphin PadSimple Plugin\nBy ector and F|RES\n\n" + message),
_T("Dolphin PadSimple"), wxOK, this);
}

View File

@ -0,0 +1,149 @@
// 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/
#ifndef __CONFIGDLG_H__
#define __CONFIGDLG_H__
#include <wx/wx.h>
#include <wx/dialog.h>
#include <wx/textctrl.h>
#include <wx/button.h>
#include <wx/stattext.h>
#include <wx/choice.h>
#include <wx/checkbox.h>
#include <wx/notebook.h>
#include <wx/panel.h>
#include <wx/gbsizer.h>
#if defined(HAVE_X11) && HAVE_X11
#include "X11InputBase.h"
#endif
class PADConfigDialogSimple : public wxDialog
{
public:
PADConfigDialogSimple(wxWindow *parent, wxWindowID id = 1, const wxString &title = wxT("Pad Configuration"),
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE);
virtual ~PADConfigDialogSimple();
private:
DECLARE_EVENT_TABLE();
wxNotebook *m_Notebook;
wxPanel *m_Controller[4];
wxButton *m_About;
wxButton *m_Close;
wxStaticBoxSizer *sbDevice[4], *m_SizeXInput[4], *m_SizeRecording[4];
wxBoxSizer *sDevice[4];
wxGridBagSizer *sPage[4];
wxStaticBoxSizer *sButtons[4];
wxStaticBoxSizer *sTriggers[4];
wxStaticBoxSizer *sStick[4];
wxStaticBoxSizer *sCStick[4];
wxStaticBoxSizer *sDPad[4];
wxArrayString arrayStringFor_X360Pad;
wxCheckBox *m_X360Pad[4];
wxChoice *m_X360PadC[4];
wxCheckBox *m_Disable[4];
wxCheckBox *m_Rumble[4];
// Recording
wxCheckBox *m_CheckRecording[4];
wxCheckBox *m_CheckPlayback[4];
wxButton *m_BtnSaveRecording[4];
wxButton *m_ButtonA[4];
wxButton *m_ButtonB[4];
wxButton *m_ButtonX[4];
wxButton *m_ButtonY[4];
wxButton *m_ButtonZ[4];
wxButton *m_ButtonStart[4];
wxButton *m_ButtonL[4];
wxButton *m_ButtonR[4];
wxButton *m_ButtonL_Semi[4];
wxButton *m_ButtonR_Semi[4];
wxSlider *m_Trigger_SemiValue[4];
wxStaticText *m_Trigger_SemiValue_Label[4];
wxButton *m_StickUp[4];
wxButton *m_StickDown[4];
wxButton *m_StickLeft[4];
wxButton *m_StickRight[4];
wxButton *m_Stick_Semi[4];
wxSlider *m_Stick_SemiValue[4];
wxStaticText *m_Stick_SemiValue_Label[4];
wxButton *m_CStickUp[4];
wxButton *m_CStickDown[4];
wxButton *m_CStickLeft[4];
wxButton *m_CStickRight[4];
wxButton *m_CStick_Semi[4];
wxSlider *m_CStick_SemiValue[4];
wxStaticText *m_CStick_SemiValue_Label[4];
wxButton *m_DPadUp[4];
wxButton *m_DPadDown[4];
wxButton *m_DPadLeft[4];
wxButton *m_DPadRight[4];
enum
{
////GUI Enum Control ID Start
ID_CLOSE = 1000,
ID_NOTEBOOK,
ID_CONTROLLERPAGE1,
ID_CONTROLLERPAGE2,
ID_CONTROLLERPAGE3,
ID_CONTROLLERPAGE4,
// XInput pad
ID_X360PAD_CHOICE,
ID_X360PAD,
ID_RUMBLE,
// Semi-press values
ID_TRIGGER_SEMIVALUE,
ID_MAIN_SEMIVALUE,
ID_SUB_SEMIVALUE,
// Input recording
ID_RECORDING,
ID_PLAYBACK,
ID_SAVE_RECORDING,
// General settings
ID_DISABLE,
ID_PAD_ABOUT,
};
void OnClose(wxCloseEvent& event);
void CreateGUIControls();
void OnCloseClick(wxCommandEvent& event);
void OnKeyDown(wxKeyEvent& event);
void ControllerSettingsChanged(wxCommandEvent& event);
void OnButtonClick(wxCommandEvent& event);
void DllAbout(wxCommandEvent& event);
void OnShow(wxShowEvent& event);
void AddSlider(wxPanel *pan, wxSlider **slider,
wxStaticBoxSizer *sizer, const char *name, int ctl, int controller);
wxButton *ClickedButton;
wxString oldLabel;
};
#endif

View File

@ -0,0 +1,994 @@
// 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
#include <stdio.h>
#include <math.h>
#include "Common.h"
//#include "LogManager.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 "../InputCommon/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 aMain(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
#if 0
// 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()");
}
#endif
// 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;
}
// 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 mainY = 0;
int mainX = 0;
if (buttonUp)
mainY = magnitude;
else if (buttonDown)
mainY = -magnitude;
if (buttonLeft)
mainX = -magnitude;
else if (buttonRight)
mainX = magnitude;
// only update if there is some action
// this allows analog stick to still work
// disable for now, enable later if any platform supports both methods of input
//if ((mainX != 0) && (mainY != 0)) {
if (true) {
if ((mainX == 0) || (mainY == 0))
{
*stickX += mainX;
*stickY += mainY;
}
else
{
*stickX += mainX*DIAGONAL_SCALE;
*stickY += mainY*DIAGONAL_SCALE;
}
}
}
//******************************************************************************
// Input
//******************************************************************************
#ifdef _WIN32
void DInput_Read(int _numPAD, SPADStatus* _pPADStatus)
{
dinput.Read();
// for (int i = 0; i < 200; i++)
// if(dinput.diks[i])
// printf("DInput_Read");
// Analog stick values based on semi-press keys
int mainstickvalue = (dinput.diks[pad[_numPAD].keyForControl[CTL_MAIN_SEMI]] & 0xFF) ? pad[_numPAD].Main_stick_semivalue : STICK_FULL;
int substickvalue = (dinput.diks[pad[_numPAD].keyForControl[CTL_SUB_SEMI]] & 0xFF) ? pad[_numPAD].Sub_stick_semivalue : STICK_FULL;
// Buttons (A/B/X/Y/Z/Start)
if (dinput.diks[pad[_numPAD].keyForControl[CTL_A]] & 0xFF)
{
_pPADStatus->button |= PAD_BUTTON_A;
_pPADStatus->analogA = BUTTON_FULL;
}
if (dinput.diks[pad[_numPAD].keyForControl[CTL_B]] & 0xFF)
{
_pPADStatus->button |= PAD_BUTTON_B;
_pPADStatus->analogB = BUTTON_FULL;
}
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_START]] & 0xFF){_pPADStatus->button |= PAD_BUTTON_START;}
// Triggers (L/R)
if (dinput.diks[pad[_numPAD].keyForControl[CTL_L]] & 0xFF)
{
_pPADStatus->button |= PAD_TRIGGER_L;
_pPADStatus->triggerLeft = TRIGGER_FULL;
}
if (dinput.diks[pad[_numPAD].keyForControl[CTL_R]] & 0xFF)
{
_pPADStatus->button |= PAD_TRIGGER_R;
_pPADStatus->triggerRight = TRIGGER_FULL;
}
if (dinput.diks[pad[_numPAD].keyForControl[CTL_L_SEMI]] & 0xFF)
{
_pPADStatus->triggerLeft = pad[_numPAD].Trigger_semivalue;
if (pad[_numPAD].Trigger_semivalue > TRIGGER_THRESHOLD)
_pPADStatus->button |= PAD_TRIGGER_L;
}
if (dinput.diks[pad[_numPAD].keyForControl[CTL_R_SEMI]] & 0xFF)
{
_pPADStatus->triggerRight = pad[_numPAD].Trigger_semivalue;
if (pad[_numPAD].Trigger_semivalue > TRIGGER_THRESHOLD)
_pPADStatus->button |= PAD_TRIGGER_R;
}
// Main stick
EmulateAnalogStick(
&_pPADStatus->stickX,
&_pPADStatus->stickY,
!!dinput.diks[pad[_numPAD].keyForControl[CTL_MAINUP]],
!!dinput.diks[pad[_numPAD].keyForControl[CTL_MAINDOWN]],
!!dinput.diks[pad[_numPAD].keyForControl[CTL_MAINLEFT]],
!!dinput.diks[pad[_numPAD].keyForControl[CTL_MAINRIGHT]],
mainstickvalue );
// Sub-stick (C-stick)
EmulateAnalogStick(
&_pPADStatus->substickX,
&_pPADStatus->substickY,
!!dinput.diks[pad[_numPAD].keyForControl[CTL_SUBUP]],
!!dinput.diks[pad[_numPAD].keyForControl[CTL_SUBDOWN]],
!!dinput.diks[pad[_numPAD].keyForControl[CTL_SUBLEFT]],
!!dinput.diks[pad[_numPAD].keyForControl[CTL_SUBRIGHT]],
substickvalue );
// D-pad
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;}
// Mic key
_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);
}
if (xpad.wButtons & XINPUT_GAMEPAD_DPAD_UP) {_pPADStatus->button |= PAD_BUTTON_UP;}
if (xpad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) {_pPADStatus->button |= PAD_BUTTON_DOWN;}
if (xpad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) {_pPADStatus->button |= PAD_BUTTON_LEFT;}
if (xpad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) {_pPADStatus->button |= PAD_BUTTON_RIGHT;}
_pPADStatus->triggerLeft = xpad.bLeftTrigger;
_pPADStatus->triggerRight = xpad.bRightTrigger;
if (xpad.bLeftTrigger > TRIGGER_THRESHOLD) {_pPADStatus->button |= PAD_TRIGGER_L;}
if (xpad.bRightTrigger > TRIGGER_THRESHOLD) {_pPADStatus->button |= PAD_TRIGGER_R;}
if (xpad.wButtons & XINPUT_GAMEPAD_START) {_pPADStatus->button |= PAD_BUTTON_START;}
if (xpad.wButtons & XINPUT_GAMEPAD_A) {_pPADStatus->button |= PAD_BUTTON_A;}
if (xpad.wButtons & XINPUT_GAMEPAD_B) {_pPADStatus->button |= PAD_BUTTON_X;}
if (xpad.wButtons & XINPUT_GAMEPAD_X) {_pPADStatus->button |= PAD_BUTTON_B;}
if (xpad.wButtons & XINPUT_GAMEPAD_Y) {_pPADStatus->button |= PAD_BUTTON_Y;}
if (xpad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER){_pPADStatus->button |= PAD_TRIGGER_Z;}
//_pPADStatus->MicButton = (xpad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) ? true : false;
return true;
}
else
{
return false;
}
}
#endif
#if (defined(HAVE_X11) && HAVE_X11) || (defined(HAVE_COCOA) && HAVE_COCOA)
#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;
}
}
#elif 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;
}
}
}
#endif
// Analog stick values based on semi-press keys
int mainstickvalue = (KeyStatus[CTL_MAIN_SEMI]) ? pad[_numPAD].Main_stick_semivalue : STICK_FULL;
int substickvalue = (KeyStatus[CTL_SUB_SEMI]) ? pad[_numPAD].Sub_stick_semivalue : STICK_FULL;
// Buttons (A/B/X/Y/Z/Start)
if (KeyStatus[CTL_A])
{
_pPADStatus->button |= PAD_BUTTON_A;
_pPADStatus->analogA = BUTTON_FULL;
}
if (KeyStatus[CTL_B])
{
_pPADStatus->button |= PAD_BUTTON_B;
_pPADStatus->analogB = BUTTON_FULL;
}
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_START]){_pPADStatus->button |= PAD_BUTTON_START;}
// Triggers (L/R)
if (KeyStatus[CTL_L]){_pPADStatus->triggerLeft = TRIGGER_FULL;}
if (KeyStatus[CTL_R]){_pPADStatus->triggerRight = TRIGGER_FULL;}
if (KeyStatus[CTL_L_SEMI]){_pPADStatus->triggerLeft = pad[_numPAD].Trigger_semivalue;}
if (KeyStatus[CTL_R_SEMI]){_pPADStatus->triggerRight = pad[_numPAD].Trigger_semivalue;}
// Main stick
EmulateAnalogStick(
&_pPADStatus->stickX,
&_pPADStatus->stickY,
KeyStatus[CTL_MAINUP],
KeyStatus[CTL_MAINDOWN],
KeyStatus[CTL_MAINLEFT],
KeyStatus[CTL_MAINRIGHT],
mainstickvalue );
EmulateAnalogStick(
&_pPADStatus->substickX,
&_pPADStatus->substickY,
KeyStatus[CTL_SUBUP],
KeyStatus[CTL_SUBDOWN],
KeyStatus[CTL_SUBLEFT],
KeyStatus[CTL_SUBRIGHT],
substickvalue );
// D-pad
if (KeyStatus[CTL_DPADUP]) {_pPADStatus->button |= PAD_BUTTON_UP;}
if (KeyStatus[CTL_DPADDOWN]) {_pPADStatus->button |= PAD_BUTTON_DOWN;}
if (KeyStatus[CTL_DPADLEFT]) {_pPADStatus->button |= PAD_BUTTON_LEFT;}
if (KeyStatus[CTL_DPADRIGHT]){_pPADStatus->button |= PAD_BUTTON_RIGHT;}
// Mic key
_pPADStatus->MicButton = KeyStatus[CTL_MIC];
#if defined(HAVE_X11) && HAVE_X11
}
#elif defined(HAVE_COCOA) && HAVE_COCOA
[pool release];
}
#endif
#endif
//******************************************************************************
// Plugin specification functions
//******************************************************************************
#if 0
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) {}
#endif
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
}
//******************************************************************************
// Load and save the configuration
//******************************************************************************
void LoadConfig()
{
// Initialize first pad to standard controls
#ifdef _WIN32
const int defaultKeyForControl[NUMCONTROLS] =
{
DIK_X, // A
DIK_Z, // B
DIK_C, // X
DIK_S, // Y
DIK_D, // Z
DIK_RETURN, // Start
DIK_Q, // L
DIK_W, // R
0x00, // L semi-press
0x00, // R semi-press
DIK_UP, // Main stick up
DIK_DOWN, // Main stick down
DIK_LEFT, // Main stick left
DIK_RIGHT, // Main stick right
DIK_LSHIFT, // Main stick semi-press
DIK_I, // C-stick up
DIK_K, // C-stick down
DIK_J, // C-stick left
DIK_L, // C-stick right
DIK_LCONTROL, // C-stick semi-press
DIK_T, // D-pad up
DIK_G, // D-pad down
DIK_F, // D-pad left
DIK_H, // D-pad right
DIK_M, // Mic
};
#elif defined(HAVE_X11) && HAVE_X11
const int defaultKeyForControl[NUMCONTROLS] =
{
XK_x, // A
XK_z, // B
XK_c, // X
XK_s, // Y
XK_d, // Z
XK_Return, // Start
XK_q, // L
XK_w, // R
0x00, // L semi-press
0x00, // R semi-press
XK_Up, // Main stick up
XK_Down, // Main stick down
XK_Left, // Main stick left
XK_Right, // Main stick right
XK_Shift_L, // Main stick semi-press
XK_i, // C-stick up
XK_k, // C-stick down
XK_j, // C-stick left
XK_l, // C-stick right
XK_Control_L, // C-stick semi-press
XK_t, // D-pad up
XK_g, // D-pad down
XK_f, // D-pad left
XK_h, // D-pad right
XK_m, // Mic
};
#elif defined(HAVE_COCOA) && HAVE_COCOA
// Reference for Cocoa key codes:
// http://boredzo.org/blog/archives/2007-05-22/virtual-key-codes
const int defaultKeyForControl[NUMCONTROLS] =
{
7, // A (x)
6, // B (z)
8, // X (c)
1, // Y (s)
2, // Z (d)
36, // Start (return)
12, // L (q)
13, // R (w)
-1, // L semi-press (none)
-1, // R semi-press (none)
126, // Main stick up (up)
125, // Main stick down (down)
123, // Main stick left (left)
124, // Main stick right (right)
56, // Main stick semi-press (left shift)
34, // C-stick up (i)
40, // C-stick down (k)
38, // C-stick left (j)
37, // C-stick right (l)
59, // C-stick semi-press (left control)
17, // D-pad up (t)
5, // D-pad down (g)
3, // D-pad left (f)
4, // D-pad right (h)
46, // Mic (m)
};
#endif
//TODO
#if 0
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, "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);
file.Get(SectionName, "Trigger_semivalue", &pad[i].Trigger_semivalue, TRIGGER_HALF_DEFAULT);
file.Get(SectionName, "Main_stick_semivalue", &pad[i].Main_stick_semivalue, STICK_HALF_DEFAULT);
file.Get(SectionName, "Sub_stick_semivalue", &pad[i].Sub_stick_semivalue, STICK_HALF_DEFAULT);
#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
}
}
#endif
}
void SaveConfig()
{
//TODO
#if 0
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, "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);
file.Set(SectionName, "Trigger_semivalue", pad[i].Trigger_semivalue);
file.Set(SectionName, "Main_stick_semivalue", pad[i].Main_stick_semivalue);
file.Set(SectionName, "Sub_stick_semivalue", pad[i].Sub_stick_semivalue);
#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");
#endif
}

View File

@ -0,0 +1,117 @@
// 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/
#ifndef __PADSIMPLE_H__
#define __PADSIMPLE_H__
//#include "Setup.h" // Common
// Constants for full-press sticks and triggers
const int BUTTON_FULL = 255;
const int STICK_FULL = 100;
const int STICK_HALF_DEFAULT = 50;
const int TRIGGER_FULL = 255;
const int TRIGGER_HALF_DEFAULT = 128;
const int TRIGGER_THRESHOLD = 230;
// Controls
enum
{
CTL_A = 0,
CTL_B,
CTL_X,
CTL_Y,
CTL_Z,
CTL_START,
CTL_L,
CTL_R,
CTL_L_SEMI,
CTL_R_SEMI,
CTL_MAINUP,
CTL_MAINDOWN,
CTL_MAINLEFT,
CTL_MAINRIGHT,
CTL_MAIN_SEMI,
CTL_SUBUP,
CTL_SUBDOWN,
CTL_SUBLEFT,
CTL_SUBRIGHT,
CTL_SUB_SEMI,
CTL_DPADUP,
CTL_DPADDOWN,
CTL_DPADLEFT,
CTL_DPADRIGHT,
CTL_MIC,
NUMCONTROLS,
};
// Control names
static const char* controlNames[] =
{
"A_button",
"B_button",
"X_button",
"Y_button",
"Z_trigger",
"Start",
"L_button",
"R_button",
"L_button_semi",
"R_button_semi",
"Main_stick_up",
"Main_stick_down",
"Main_stick_left",
"Main_stick_right",
"Main_stick_semi",
"Sub_stick_up",
"Sub_stick_down",
"Sub_stick_left",
"Sub_stick_right",
"Sub_stick_semi",
"D-Pad_up",
"D-Pad_down",
"D-Pad_left",
"D-Pad_right",
"Mic-button",
};
struct SPads
{
bool bEnableXPad; // Use an XPad in addition to the keyboard?
bool bDisable; // Disabled when dolphin isn't in focus
bool bRumble; // Rumble for xpad
u32 RumbleStrength; // Rumble strength
bool bRecording; // Record input?
bool bPlayback; // Playback input?
s32 XPadPlayer; // Player# of the xpad
u32 keyForControl[NUMCONTROLS]; // Keyboard mapping
u32 Trigger_semivalue; // Semi-press value for triggers
u32 Main_stick_semivalue; // Semi-press value for main stick
u32 Sub_stick_semivalue; // Semi-press value for sub-stick
};
extern SPads pad[];
//extern bool g_EmulatorRunning;
void LoadConfig();
void SaveConfig();
bool IsFocus();
// Input Recording
void SaveRecord();
#endif

View File

@ -0,0 +1,86 @@
//__________________________________________________________________________________________________
// Common pad plugin spec, version #1.0 maintained by F|RES
//
#ifndef _PAD_H_INCLUDED__
#define _PAD_H_INCLUDED__
//#include "PluginSpecs.h"
//#include "ExportProlog.h"
#define PAD_ERR_NONE 0
#define PAD_ERR_NO_CONTROLLER -1
#define PAD_ERR_NOT_READY -2
#define PAD_ERR_TRANSFER -3
#define PAD_USE_ORIGIN 0x0080
#define PAD_BUTTON_LEFT 0x0001
#define PAD_BUTTON_RIGHT 0x0002
#define PAD_BUTTON_DOWN 0x0004
#define PAD_BUTTON_UP 0x0008
#define PAD_TRIGGER_Z 0x0010
#define PAD_TRIGGER_R 0x0020
#define PAD_TRIGGER_L 0x0040
#define PAD_BUTTON_A 0x0100
#define PAD_BUTTON_B 0x0200
#define PAD_BUTTON_X 0x0400
#define PAD_BUTTON_Y 0x0800
#define PAD_BUTTON_START 0x1000
typedef void (*TLog)(const char* _pMessage);
typedef struct
{
HWND hWnd;
TLog pLog;
int padNumber;
} SPADInitialize;
typedef struct
{
unsigned short button; // Or-ed PAD_BUTTON_* and PAD_TRIGGER_* bits
unsigned char stickX; // 0 <= stickX <= 255
unsigned char stickY; // 0 <= stickY <= 255
unsigned char substickX; // 0 <= substickX <= 255
unsigned char substickY; // 0 <= substickY <= 255
unsigned char triggerLeft; // 0 <= triggerLeft <= 255
unsigned char triggerRight; // 0 <= triggerRight <= 255
unsigned char analogA; // 0 <= analogA <= 255
unsigned char analogB; // 0 <= analogB <= 255
bool MicButton; // HAX
signed char err; // one of PAD_ERR_* number
} SPADStatus;
#define EXPORT
#define CALL
// I N T E R F A C E
// __________________________________________________________________________________________________
// Function:
// Purpose:
// input:
// output:
//
EXPORT void CALL PAD_GetStatus(u8 _numPAD, SPADStatus* _pPADStatus);
// __________________________________________________________________________________________________
// Function: Send keyboard input to the plugin
// Purpose:
// input: The key and if it's pressed or released
// output: None
//
EXPORT void CALL PAD_Input(u16 _Key, u8 _UpDown);
// __________________________________________________________________________________________________
// Function: PAD_Rumble
// Purpose: Pad rumble!
// input: PAD number, Command type (Stop=0, Rumble=1, Stop Hard=2) and strength of Rumble
// output: none
//
EXPORT void CALL PAD_Rumble(u8 _numPAD, unsigned int _uType, unsigned int _uStrength);
//#include "ExportEpilog.h"
#endif

View File

@ -16,6 +16,8 @@
#include "wx/stdpaths.h"
#include "LuaWindow.h"
#include "PadSimple/GUI/ConfigDlg.h"
#include "PadSimple/pluginspecs_pad.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
@ -45,13 +47,40 @@ public:
this);
}
bool up,down,left,right,x,y,a,b,l,r,start,select;
void applyInput(){
//TODO
return;
u16 pad = (0 |
bool up,down,left,right,x,y,a,b,l,r,start,select;
up = down = left = right = x = y = a = b = l = r = start = select = false;
SPADStatus s;
memset(&s,0,sizeof(s));
PAD_GetStatus(0, &s);
if(s.button & PAD_BUTTON_LEFT)
left = true;
if(s.button & PAD_BUTTON_RIGHT)
right = true;
if(s.button & PAD_BUTTON_UP)
up = true;
if(s.button & PAD_BUTTON_DOWN)
down = true;
if(s.button & PAD_BUTTON_A)
a = true;
if(s.button & PAD_BUTTON_B)
b = true;
if(s.button & PAD_BUTTON_X)
x = true;
if(s.button & PAD_BUTTON_Y)
y = true;
if(s.button & PAD_TRIGGER_L)
l = true;
if(s.button & PAD_TRIGGER_R)
r = true;
if(s.button & PAD_BUTTON_START)
start = true;
u16 pad1 = (0 |
((a ? 0 : 0x80) >> 7) |
((b ? 0 : 0x80) >> 6) |
((select? 0 : 0x80) >> 5) |
@ -63,8 +92,8 @@ public:
((r ? 0 : 0x80) << 1) |
((l ? 0 : 0x80) << 2)) ;
((u16 *)MMU.ARM9_REG)[0x130>>1] = (u16)pad;
((u16 *)MMU.ARM7_REG)[0x130>>1] = (u16)pad;
((u16 *)MMU.ARM9_REG)[0x130>>1] = (u16)pad1;
((u16 *)MMU.ARM7_REG)[0x130>>1] = (u16)pad1;
bool debug = false;
bool lidClosed = false;
@ -79,79 +108,6 @@ public:
((u16 *)MMU.ARM7_REG)[0x136>>1] = (u16)padExt;
}
void OnKeyDown(wxKeyEvent &event){
switch(event.m_keyCode) {
case WXK_UP:
up = true;
break;
case WXK_DOWN:
down = true;
break;
case WXK_LEFT:
left = true;
break;
case WXK_RIGHT:
right = true;
break;
case WXK_RETURN:
start = true;
break;
case WXK_SHIFT:
select = true;
break;
case 65://a
y = true;
break;
case 83://s
x = true;
break;
case 90://z
b = true;
break;
case 88://x
a = true;
break;
}
// printf("%d",event.m_keyCode);
}
void OnKeyUp(wxKeyEvent &event){
switch(event.m_keyCode) {
case WXK_UP:
up = false;
break;
case WXK_DOWN:
down = false;
break;
case WXK_LEFT:
left = false;
break;
case WXK_RIGHT:
right = false;
break;
case WXK_RETURN:
start = false;
break;
case WXK_SHIFT:
select = false;
break;
case 65://a
y = false;
break;
case 83://s
x = false;
break;
case 90://z
b = false;
break;
case 88://x
a = false;
break;
}
}
//TODO integrate paths system?
void LoadRom(wxCommandEvent& event){
wxFileDialog dialog(this,"Load Rom",wxGetHomeDir(),"","*.nds",wxFD_OPEN, wxDefaultPosition, wxDefaultSize);
@ -313,6 +269,11 @@ case 88://x
new wxLuaWindow(this, wxDefaultPosition, wxSize(600, 390));
}
void OnOpenControllerConfiguration(wxCommandEvent& WXUNUSED (event))
{
new PADConfigDialogSimple(this);
}
wxMenu* MakeStatesSubMenu( int baseid ) const
{
wxMenu* mnuSubstates = new wxMenu();
@ -369,7 +330,8 @@ enum
wQuickScreenshot,
wLuaWindow,
wLoadState01,
wSaveState01 = wLoadState01+20
wSaveState01 = wLoadState01+20,
wConfigureControls
};
void DesmumeFrame::Menu_SaveStates(wxCommandEvent &event){savestate_slot(event.GetId() - wSaveState01 - 1);}
@ -389,8 +351,6 @@ EVT_MENU(wDisplayInput,DesmumeFrame::displayInput)
EVT_MENU(wDisplayGraphicalInput,DesmumeFrame::displayGraphicalInput)
EVT_MENU(wDisplayLagCounter,DesmumeFrame::displayLagCounter)
EVT_MENU(wDisplayMicrophone,DesmumeFrame::displayMicrophone)
EVT_KEY_DOWN(DesmumeFrame::OnKeyDown)
EVT_KEY_UP(DesmumeFrame::OnKeyUp)
EVT_MENU(wMainGPU,DesmumeFrame::mainGPU)
EVT_MENU(wMainBG0,DesmumeFrame::mainBG0)
@ -425,6 +385,8 @@ EVT_MENU(w3dView,DesmumeFrame::_3dView)
EVT_MENU(wLuaWindow,DesmumeFrame::OnOpenLuaWindow)
EVT_MENU(wConfigureControls,DesmumeFrame::OnOpenControllerConfiguration)
END_EVENT_TABLE()
IMPLEMENT_APP(Desmume)
@ -447,9 +409,15 @@ bool Desmume::OnInit()
DesmumeFrame *frame = new DesmumeFrame((char*)EMU_DESMUME_NAME_AND_VERSION());
frame->Show(true);
SPADInitialize PADInitialize;
PADInitialize.padNumber = 1;
extern void Initialize(void *init);
Initialize(&PADInitialize);
//TODO
addon_type = NDS_ADDON_NONE;
addonsChangePak(addon_type);
return true;
}
@ -478,8 +446,9 @@ DesmumeFrame::DesmumeFrame(const wxString& title)
fileMenu->AppendSubMenu(loads,"Load State");
#define ConnectMenuRange( id_start, inc, handler ) \
Connect( id_start, id_start + inc, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(DesmumeFrame::handler) )
ConnectMenuRange(wLoadState01+1, 10, Menu_LoadStates);
ConnectMenuRange(wSaveState01+1, 10, Menu_SaveStates);
//TODO something is wrong here
// ConnectMenuRange(wLoadState01+1, 10, Menu_LoadStates);
// ConnectMenuRange(wSaveState01+1, 10, Menu_SaveStates);
}
fileMenu->AppendSeparator();
fileMenu->Append(wImportBackupMemory, "Import Backup Memory...");
@ -522,6 +491,9 @@ DesmumeFrame::DesmumeFrame(const wxString& title)
layersMenu->Append(wSubBG2,"Sub BG 2");
layersMenu->Append(wSubBG3,"Sub BG 3");
}
configMenu->Append(wConfigureControls,"Controls");
toolsMenu->AppendSeparator();
toolsMenu->AppendSubMenu(layersMenu,"View Layers");