Soren Jorvang 5c335a8c85 Fixed WXKeyToString which had several problems, mostly just to get
hotkey configuration working with wx 2.9, but it turned out to be
too tempting to use it to hack up OS X keyboard support using wx
key events in the "old" input plugins.

It was with some reluctance that I used PAD_Input (and copied it
for Wiimote as well) as that is clearly a deprecated interface,
but this way the hack is contained within the old plugins for when
the switchover to ControllerInterface happens.

The idea is to provide stable keyboard support on OS X for both
GCPad and Wiimote while we debug HID keyboard and real 'mote code.

It works pretty well, although the wx approach does impose a few
limitations like no arrow keys and left/right side modifier keys
are considered equivalent.


git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5622 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-06-05 19:03:37 +00:00

836 lines
32 KiB
C++

// Project description
// -------------------
// Name: nJoy
// Description: A Dolphin Compatible Input Plugin
//
// Author: Falcon4ever (nJoy@falcon4ever.com)
// Site: www.multigesture.net
// Copyright (C) 2003 Dolphin Project.
//
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "math.h" // System
#include "WXInputBase.h"
#include "ConfigBox.h"
#include "Config.h"
#include "GCPad.h"
#if defined(HAVE_X11) && HAVE_X11
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/XKBlib.h>
#include "X11InputBase.h"
#endif
// The wxWidgets class
BEGIN_EVENT_TABLE(GCPadConfigDialog,wxDialog)
EVT_CLOSE(GCPadConfigDialog::OnClose)
EVT_BUTTON(wxID_OK, GCPadConfigDialog::OnCloseClick)
EVT_BUTTON(wxID_CANCEL, GCPadConfigDialog::OnCloseClick)
EVT_NOTEBOOK_PAGE_CHANGED(ID_NOTEBOOK, GCPadConfigDialog::NotebookPageChanged)
EVT_CHOICE(IDC_JOYNAME, GCPadConfigDialog::ChangeSettings)
EVT_CHECKBOX(IDC_RUMBLE, GCPadConfigDialog::ChangeSettings)
EVT_CHOICE(IDC_RUMBLE_STRENGTH, GCPadConfigDialog::ChangeSettings)
EVT_CHOICE(IDC_DEAD_ZONE_LEFT, GCPadConfigDialog::ChangeSettings)
EVT_CHOICE(IDC_DEAD_ZONE_RIGHT, GCPadConfigDialog::ChangeSettings)
EVT_CHOICE(IDC_STICK_DIAGONAL, GCPadConfigDialog::ChangeSettings)
EVT_CHECKBOX(IDC_STICK_S2C, GCPadConfigDialog::ChangeSettings)
EVT_CHOICE(IDC_TRIGGER_TYPE, GCPadConfigDialog::ChangeSettings)
EVT_CHOICE(IDC_STICK_SOURCE, GCPadConfigDialog::ChangeSettings)
EVT_CHOICE(IDC_CSTICK_SOURCE, GCPadConfigDialog::ChangeSettings)
EVT_CHOICE(IDC_TRIGGER_SOURCE, GCPadConfigDialog::ChangeSettings)
EVT_SLIDER(IDS_STICK_PRESS, GCPadConfigDialog::ChangeSettings)
EVT_SLIDER(IDS_CSTICK_PRESS, GCPadConfigDialog::ChangeSettings)
EVT_SLIDER(IDS_TRIGGER_PRESS, GCPadConfigDialog::ChangeSettings)
EVT_BUTTON(IDB_ANALOG_LEFT_X, GCPadConfigDialog::OnAxisClick)
EVT_BUTTON(IDB_ANALOG_LEFT_Y, GCPadConfigDialog::OnAxisClick)
EVT_BUTTON(IDB_ANALOG_RIGHT_X, GCPadConfigDialog::OnAxisClick)
EVT_BUTTON(IDB_ANALOG_RIGHT_Y, GCPadConfigDialog::OnAxisClick)
EVT_BUTTON(IDB_TRIGGER_L, GCPadConfigDialog::OnAxisClick)
EVT_BUTTON(IDB_TRIGGER_R, GCPadConfigDialog::OnAxisClick)
EVT_BUTTON(IDB_BTN_A, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_BTN_B, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_BTN_X, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_BTN_Y, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_BTN_Z, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_BTN_START, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_DPAD_UP, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_DPAD_DOWN, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_DPAD_LEFT, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_DPAD_RIGHT, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_MAIN_UP, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_MAIN_DOWN, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_MAIN_LEFT, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_MAIN_RIGHT, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_MAIN_SEMI, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_SUB_UP, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_SUB_DOWN, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_SUB_LEFT, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_SUB_RIGHT, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_SUB_SEMI, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_SHDR_L, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_SHDR_R, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_SHDR_SEMI_L, GCPadConfigDialog::OnButtonClick)
EVT_BUTTON(IDB_SHDR_SEMI_R, GCPadConfigDialog::OnButtonClick)
#if wxUSE_TIMER
EVT_TIMER(IDTM_UPDATE_PAD, GCPadConfigDialog::UpdatePadInfo)
EVT_TIMER(IDTM_BUTTON, GCPadConfigDialog::OnButtonTimer)
#endif
END_EVENT_TABLE()
GCPadConfigDialog::GCPadConfigDialog(wxWindow *parent, wxWindowID id, const wxString &title,
const wxPoint &position, const wxSize& size, long style)
: wxDialog(parent, id, title, position, size, style)
{
// Define values
m_ControlsCreated = false;
m_Page = 0;
// Create controls
CreateGUIControls();
#if wxUSE_TIMER
m_UpdatePadTimer = new wxTimer(this, IDTM_UPDATE_PAD);
m_ButtonMappingTimer = new wxTimer(this, IDTM_BUTTON);
// Reset values
g_Pressed = 0;
ClickedButton = NULL;
GetButtonWaitingID = 0;
GetButtonWaitingTimer = 0;
if (NumGoodPads)
{
// Start the constant timer
int TimesPerSecond = 10;
m_UpdatePadTimer->Start(1000 / TimesPerSecond);
}
#endif
UpdateGUI();
}
GCPadConfigDialog::~GCPadConfigDialog()
{
if (m_ButtonMappingTimer)
{
delete m_ButtonMappingTimer;
m_ButtonMappingTimer = NULL;
}
if (m_UpdatePadTimer)
{
delete m_UpdatePadTimer;
m_UpdatePadTimer = NULL;
}
}
// Notebook page changed
void GCPadConfigDialog::NotebookPageChanged(wxNotebookEvent& event)
{
// Update the global variable
m_Page = event.GetSelection();
// Update GUI
UpdateGUI();
}
// Close window
void GCPadConfigDialog::OnClose(wxCloseEvent& event)
{
// Allow wxWidgets to close the window
//event.Skip();
// Stop the timer
if (m_UpdatePadTimer)
m_UpdatePadTimer->Stop();
if (m_ButtonMappingTimer)
m_ButtonMappingTimer->Stop();
EndModal(wxID_CLOSE);
}
// Button Click
void GCPadConfigDialog::OnCloseClick(wxCommandEvent& event)
{
switch (event.GetId())
{
case wxID_OK:
g_Config.Save();
Close(); // Call OnClose()
break;
case wxID_CANCEL:
g_Config.Load();
Close(); // Call OnClose()
break;
}
}
void GCPadConfigDialog::SaveButtonMapping(int Id, int Key)
{
if (IDB_ANALOG_LEFT_X <= Id && Id <= IDB_TRIGGER_R)
{
GCMapping[m_Page].AxisMapping.Code[Id - IDB_ANALOG_LEFT_X] = Key;
}
else if (IDB_BTN_A <= Id && Id <= IDB_SHDR_SEMI_R)
{
GCMapping[m_Page].Button[Id - IDB_BTN_A] = Key;
}
}
void GCPadConfigDialog::OnKeyDown(wxKeyEvent& event)
{
//event.Skip();
if(ClickedButton != NULL)
{
// Save the key
g_Pressed = event.GetKeyCode();
// Handle the keyboard key mapping
// Allow the escape key to set a blank key
if (g_Pressed == WXK_ESCAPE)
{
SaveButtonMapping(ClickedButton->GetId(), -1);
SetButtonText(ClickedButton->GetId(), wxString());
}
else
{
#ifdef _WIN32
BYTE keyState[256];
GetKeyboardState(keyState);
for (int i = 1; i < 256; ++i)
{
if ((keyState[i] & 0x80) != 0)
{
// Use the left and right specific keys instead of the common ones
if (i == VK_SHIFT || i == VK_CONTROL || i == VK_MENU) continue;
// Update the button label
SetButtonText(ClickedButton->GetId(),
wxString::FromAscii(InputCommon::VKToString(i).c_str()));
// Save the setting
SaveButtonMapping(ClickedButton->GetId(), i);
break;
}
}
#elif defined(HAVE_X11) && HAVE_X11
char keyStr[128] = {0};
int XKey = InputCommon::wxCharCodeWXToX(g_Pressed);
InputCommon::XKeyToString(XKey, keyStr);
SetButtonText(ClickedButton->GetId(),
wxString::FromAscii(keyStr));
SaveButtonMapping(ClickedButton->GetId(), XKey);
#elif defined(USE_WX) && USE_WX
SetButtonText(ClickedButton->GetId(),
InputCommon::WXKeyToString(g_Pressed));
SaveButtonMapping(ClickedButton->GetId(), g_Pressed);
#endif
}
EndGetButtons();
}
}
// Configure button mapping
void GCPadConfigDialog::OnButtonClick(wxCommandEvent& event)
{
event.Skip();
// Don't allow space to start a new Press Key option, that will interfer with setting a key to space
if (g_Pressed == WXK_SPACE) { g_Pressed = 0; return; }
if (m_ButtonMappingTimer->IsRunning()) return;
wxTheApp->Connect(wxID_ANY, wxEVT_KEY_DOWN, // Keyboard
wxKeyEventHandler(GCPadConfigDialog::OnKeyDown),
(wxObject*)0, this);
// Create the button object
ClickedButton = (wxButton *)event.GetEventObject();
// Save old label so we can revert back
OldLabel = ClickedButton->GetLabel();
ClickedButton->SetWindowStyle(wxWANTS_CHARS);
ClickedButton->SetLabel(wxT("<Press Key>"));
DoGetButtons(ClickedButton->GetId());
}
// Configure axis mapping
void GCPadConfigDialog::OnAxisClick(wxCommandEvent& event)
{
event.Skip();
if (m_ButtonMappingTimer->IsRunning()) return;
ClickedButton = NULL;
wxButton* pButton = (wxButton *)event.GetEventObject();
OldLabel = pButton->GetLabel();
pButton->SetWindowStyle(wxWANTS_CHARS);
pButton->SetLabel(wxT("<Move Axis>"));
DoGetButtons(pButton->GetId());
}
void GCPadConfigDialog::ChangeSettings(wxCommandEvent& event)
{
int id = event.GetId();
switch (id)
{
case IDC_JOYNAME:
GCMapping[m_Page].ID = m_Joyname[m_Page]->GetSelection();
GCMapping[m_Page].joy = joyinfo.at(GCMapping[m_Page].ID).joy;
break;
case IDC_DEAD_ZONE_LEFT:
GCMapping[m_Page].DeadZoneL = m_ComboDeadZoneLeft[m_Page]->GetSelection();
break;
case IDC_DEAD_ZONE_RIGHT:
GCMapping[m_Page].DeadZoneR = m_ComboDeadZoneRight[m_Page]->GetSelection();
break;
case IDC_STICK_DIAGONAL:
GCMapping[m_Page].Diagonal = 100 - m_ComboDiagonal[m_Page]->GetSelection() * 5;
break;
case IDC_STICK_S2C:
GCMapping[m_Page].bSquare2Circle = m_CheckS2C[m_Page]->IsChecked();
break;
case IDC_RUMBLE:
GCMapping[m_Page].Rumble = m_CheckRumble[m_Page]->IsChecked();
break;
case IDC_RUMBLE_STRENGTH:
GCMapping[m_Page].RumbleStrength = m_RumbleStrength[m_Page]->GetSelection() * 10;
break;
case IDC_TRIGGER_TYPE:
GCMapping[m_Page].TriggerType = m_TriggerType[m_Page]->GetSelection();
break;
case IDC_STICK_SOURCE:
GCMapping[m_Page].Stick.Main = m_Combo_StickSrc[m_Page]->GetSelection();
break;
case IDC_CSTICK_SOURCE:
GCMapping[m_Page].Stick.Sub = m_Combo_CStickSrc[m_Page]->GetSelection();
break;
case IDC_TRIGGER_SOURCE:
GCMapping[m_Page].Stick.Shoulder = m_Combo_TriggerSrc[m_Page]->GetSelection();
break;
case IDS_STICK_PRESS:
GCMapping[m_Page].Pressure.Main = m_Slider_Stick[m_Page]->GetValue();
break;
case IDS_CSTICK_PRESS:
GCMapping[m_Page].Pressure.Sub = m_Slider_CStick[m_Page]->GetValue();
break;
case IDS_TRIGGER_PRESS:
GCMapping[m_Page].Pressure.Shoulder = m_Slider_Trigger[m_Page]->GetValue();
break;
}
UpdateGUI();
}
void GCPadConfigDialog::UpdateGUI()
{
if(!m_ControlsCreated)
return;
// Disable all pad items if no pads are detected
bool PadEnabled = NumGoodPads != 0;
m_Joyname[m_Page]->Enable(PadEnabled);
m_ComboDeadZoneLeft[m_Page]->Enable(PadEnabled);
m_ComboDeadZoneRight[m_Page]->Enable(PadEnabled);
m_CheckS2C[m_Page]->Enable(PadEnabled);
m_ComboDiagonal[m_Page]->Enable(PadEnabled);
m_CheckRumble[m_Page]->Enable(PadEnabled);
m_RumbleStrength[m_Page]->Enable(PadEnabled);
m_TriggerType[m_Page]->Enable(PadEnabled);
for(int i = 0; i <= IDB_TRIGGER_R - IDB_ANALOG_LEFT_X; i++)
m_Button_Analog[i][m_Page]->Enable(PadEnabled);
wxString tmp;
m_Joyname[m_Page]->SetSelection(GCMapping[m_Page].ID);
m_ComboDeadZoneLeft[m_Page]->SetSelection(GCMapping[m_Page].DeadZoneL);
m_ComboDeadZoneRight[m_Page]->SetSelection(GCMapping[m_Page].DeadZoneR);
m_ComboDiagonal[m_Page]->SetSelection((100 - GCMapping[m_Page].Diagonal) / 5);
m_CheckS2C[m_Page]->SetValue(GCMapping[m_Page].bSquare2Circle);
m_CheckRumble[m_Page]->SetValue(GCMapping[m_Page].Rumble);
m_RumbleStrength[m_Page]->SetSelection(GCMapping[m_Page].RumbleStrength / 10);
m_TriggerType[m_Page]->SetSelection(GCMapping[m_Page].TriggerType);
m_Combo_StickSrc[m_Page]->SetSelection(GCMapping[m_Page].Stick.Main);
m_Combo_CStickSrc[m_Page]->SetSelection(GCMapping[m_Page].Stick.Sub);
m_Combo_TriggerSrc[m_Page]->SetSelection(GCMapping[m_Page].Stick.Shoulder);
m_Slider_Stick[m_Page]->SetValue(GCMapping[m_Page].Pressure.Main);
m_Slider_CStick[m_Page]->SetValue(GCMapping[m_Page].Pressure.Sub);
m_Slider_Trigger[m_Page]->SetValue(GCMapping[m_Page].Pressure.Shoulder);
for (int i = 0; i <= IDB_TRIGGER_R - IDB_ANALOG_LEFT_X; i++)
{
tmp << GCMapping[m_Page].AxisMapping.Code[i];
m_Button_Analog[i][m_Page]->SetLabel(tmp);
tmp.clear();
}
#ifdef _WIN32
for (int x = 0; x <= IDB_SHDR_SEMI_R - IDB_BTN_A; x++)
{
m_Button_GC[x][m_Page]->SetLabel(wxString::FromAscii(
InputCommon::VKToString(GCMapping[m_Page].Button[x + EGC_A]).c_str()));
}
#elif defined(HAVE_X11) && HAVE_X11
char keyStr[10] = {0};
for (int x = 0; x <= IDB_SHDR_SEMI_R - IDB_BTN_A; x++)
{
InputCommon::XKeyToString(GCMapping[m_Page].Button[x + EGC_A], keyStr);
m_Button_GC[x][m_Page]->SetLabel(wxString::FromAscii(keyStr));
}
#elif defined(USE_WX) && USE_WX
for (int x = 0; x <= IDB_SHDR_SEMI_R - IDB_BTN_A; x++)
{
m_Button_GC[x][m_Page]-> \
SetLabel(InputCommon::WXKeyToString(
GCMapping[m_Page].Button[x + EGC_A]));
}
#endif
DoChangeDeadZone();
}
void GCPadConfigDialog::CreateGUIControls()
{
// Search for devices and add them to the device list
wxArrayString StrJoyname; // The string array
if (NumGoodPads > 0)
{
for (int i = 0; i < NumPads; i++)
StrJoyname.Add(wxString::FromAscii(joyinfo[i].Name.c_str()));
}
else
{
StrJoyname.Add(wxT("<No Gamepad Detected>"));
}
wxArrayString TextDeadZone;
for (int i = 0; i <= 50; i++)
TextDeadZone.Add(wxString::Format(wxT("%i%%"), i));
wxArrayString StrDiagonal;
for (int i = 0; i <= 10; i++)
StrDiagonal.Add(wxString::Format(wxT("%i%%"), 100 - i * 5));
wxArrayString StrRumble;
for (int i = 0; i <= 10; i++)
StrRumble.Add(wxString::Format(wxT("%i%%"), i * 10));
wxArrayString StrSource;
StrSource.Add(wxT("Keyboard"));
StrSource.Add(wxT("Analog 1"));
StrSource.Add(wxT("Analog 2"));
StrSource.Add(wxT("Triggers"));
// The Trigger type list
wxArrayString StrTriggerType;
StrTriggerType.Add(wxT("SDL")); // -0x8000 to 0x7fff
StrTriggerType.Add(wxT("XInput")); // 0x00 to 0xff
static const wxChar* anText[] =
{
wxT("Left X-Axis"),
wxT("Left Y-Axis"),
wxT("Right X-Axis"),
wxT("Right Y-Axis"),
wxT("Left Trigger"),
wxT("Right Trigger"),
};
static const wxChar* padText[] =
{
wxT("A"),
wxT("B"),
wxT("X"),
wxT("Y"),
wxT("Z"),
wxT("Start"),
wxT("Up"), // D-Pad
wxT("Down"),
wxT("Left"),
wxT("Right"),
wxT("Up"), // Main Stick
wxT("Down"),
wxT("Left"),
wxT("Right"),
wxT("Semi"),
wxT("Up"), // C-Stick
wxT("Down"),
wxT("Left"),
wxT("Right"),
wxT("Semi"),
wxT("L"), // Triggers
wxT("R"),
wxT("Semi-L"),
wxT("Semi-R"),
};
// Configuration controls sizes
static const int BtW = 70, BtH = 20;
// A small type font
wxFont m_SmallFont(7, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
m_Notebook = new wxNotebook(this, ID_NOTEBOOK, wxDefaultPosition, wxDefaultSize);
for (int i = 0; i < 4; i++)
{
m_Controller[i] = new wxPanel(m_Notebook, ID_CONTROLLERPAGE1 + i, wxDefaultPosition, wxDefaultSize);
m_Notebook->AddPage(m_Controller[i], wxString::Format(wxT("Gamecube Pad %d"), i+1));
// Controller
m_Joyname[i] = new wxChoice(m_Controller[i], IDC_JOYNAME, wxDefaultPosition, wxSize(400, -1), StrJoyname, 0, wxDefaultValidator, StrJoyname[0]);
// Dead zone
m_ComboDeadZoneLabel[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Dead Zone"));
m_ComboDeadZoneLeft[i] = new wxChoice(m_Controller[i], IDC_DEAD_ZONE_LEFT, wxDefaultPosition, wxSize(50, -1), TextDeadZone, 0, wxDefaultValidator, TextDeadZone[0]);
m_ComboDeadZoneRight[i] = new wxChoice(m_Controller[i], IDC_DEAD_ZONE_RIGHT, wxDefaultPosition, wxSize(50, -1), TextDeadZone, 0, wxDefaultValidator, TextDeadZone[0]);
// Circle to square
m_CheckS2C[i] = new wxCheckBox(m_Controller[i], IDC_STICK_S2C, wxT("Square To Circle"));
m_CheckS2C[i]->SetToolTip(wxT("This will convert a square stick radius to a circle stick radius, which is\n")
wxT("similar to the octagonal area that the original GameCube pad produces."));
// The drop down menu for the circle to square adjustment
m_DiagonalLabel[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Diagonal"));
m_DiagonalLabel[i]->SetToolTip(wxT("To produce a perfect circle in the 'Out' window you have to manually set\n")
wxT("your diagonal values here from what is shown in the 'In' window."));
m_ComboDiagonal[i] = new wxChoice(m_Controller[i], IDC_STICK_DIAGONAL, wxDefaultPosition, wxSize(50, -1), StrDiagonal, 0, wxDefaultValidator, StrDiagonal[0]);
// Rumble
m_CheckRumble[i] = new wxCheckBox(m_Controller[i], IDC_RUMBLE, wxT("Rumble"));
m_RumbleStrengthLabel[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Strength"));
m_RumbleStrength[i] = new wxChoice(m_Controller[i], IDC_RUMBLE_STRENGTH, wxDefaultPosition, wxSize(50, -1), StrRumble, 0, wxDefaultValidator, StrRumble[0]);
// Sizers
m_sDeadZoneHoriz[i] = new wxBoxSizer(wxHORIZONTAL);
m_sDeadZoneHoriz[i]->Add(m_ComboDeadZoneLeft[i], 0, (wxUP), 0);
m_sDeadZoneHoriz[i]->Add(m_ComboDeadZoneRight[i], 0, (wxUP), 0);
m_sDeadZone[i] = new wxBoxSizer(wxVERTICAL);
m_sDeadZone[i]->Add(m_ComboDeadZoneLabel[i], 0, wxALIGN_CENTER | (wxUP), 0);
m_sDeadZone[i]->Add(m_sDeadZoneHoriz[i], 0, wxALIGN_CENTER | (wxUP), 2);
m_sDiagonal[i] = new wxBoxSizer(wxHORIZONTAL);
m_sDiagonal[i]->Add(m_DiagonalLabel[i], 0, (wxUP), 4);
m_sDiagonal[i]->Add(m_ComboDiagonal[i], 0, (wxLEFT), 2);
m_sSquare2Circle[i] = new wxBoxSizer(wxVERTICAL);
m_sSquare2Circle[i]->Add(m_CheckS2C[i], 0, wxALIGN_CENTER | (wxUP), 0);
m_sSquare2Circle[i]->Add(m_sDiagonal[i], 0, wxALIGN_CENTER | (wxUP), 2);
m_sRumbleStrength[i] = new wxBoxSizer(wxHORIZONTAL);
m_sRumbleStrength[i]->Add(m_RumbleStrengthLabel[i], 0, (wxUP), 4);
m_sRumbleStrength[i]->Add(m_RumbleStrength[i], 0, (wxLEFT), 2);
m_sRumble[i] = new wxBoxSizer(wxVERTICAL);
m_sRumble[i]->Add(m_CheckRumble[i], 0, wxALIGN_CENTER | (wxUP), 0);
m_sRumble[i]->Add(m_sRumbleStrength[i], 0, wxALIGN_CENTER | (wxUP), 2);
m_sS2CDeadZone[i] = new wxBoxSizer(wxHORIZONTAL);
m_sS2CDeadZone[i]->Add(m_sDeadZone[i], 0, (wxUP), 0);
m_sS2CDeadZone[i]->Add(m_sSquare2Circle[i], 0, (wxLEFT), 40);
m_sS2CDeadZone[i]->Add(m_sRumble[i], 0, (wxLEFT), 40);
m_gJoyPad[i] = new wxStaticBoxSizer (wxVERTICAL, m_Controller[i], wxT("Gamepad"));
m_gJoyPad[i]->AddStretchSpacer();
m_gJoyPad[i]->Add(m_Joyname[i], 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5);
m_gJoyPad[i]->Add(m_sS2CDeadZone[i], 0, wxALIGN_CENTER | (wxUP | wxDOWN), 4);
m_gJoyPad[i]->AddStretchSpacer();
// Row 1 Sizers: Connected pads, tilt
m_sHorizJoypad[i] = new wxBoxSizer(wxHORIZONTAL);
m_sHorizJoypad[i]->Add(m_gJoyPad[i], 0, wxEXPAND | (wxLEFT), 5);
// Stick Status Panels
m_tStatusLeftIn[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Not connected"));
m_tStatusLeftOut[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Not connected"));
m_tStatusRightIn[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Not connected"));
m_tStatusRightOut[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Not connected"));
m_pLeftInStatus[i] = new wxPanel(m_Controller[i], wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_bmpSquareLeftIn[i] = new wxStaticBitmap(m_pLeftInStatus[i], wxID_ANY, CreateBitmap(), wxDefaultPosition, wxDefaultSize);
m_bmpDeadZoneLeftIn[i] = new wxStaticBitmap(m_pLeftInStatus[i], wxID_ANY, CreateBitmapDeadZone(0), wxDefaultPosition, wxDefaultSize);
m_bmpDotLeftIn[i] = new wxStaticBitmap(m_pLeftInStatus[i], wxID_ANY, CreateBitmapDot(), wxPoint(BoxW / 2, BoxH / 2), wxDefaultSize);
m_pLeftOutStatus[i] = new wxPanel(m_Controller[i], wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_bmpSquareLeftOut[i] = new wxStaticBitmap(m_pLeftOutStatus[i], wxID_ANY, CreateBitmap(), wxDefaultPosition, wxDefaultSize);
m_bmpDotLeftOut[i] = new wxStaticBitmap(m_pLeftOutStatus[i], wxID_ANY, CreateBitmapDot(), wxPoint(BoxW / 2, BoxH / 2), wxDefaultSize);
m_pRightInStatus[i] = new wxPanel(m_Controller[i], wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_bmpSquareRightIn[i] = new wxStaticBitmap(m_pRightInStatus[i], wxID_ANY, CreateBitmap(), wxDefaultPosition, wxDefaultSize);
m_bmpDeadZoneRightIn[i] = new wxStaticBitmap(m_pRightInStatus[i], wxID_ANY, CreateBitmapDeadZone(0), wxDefaultPosition, wxDefaultSize);
m_bmpDotRightIn[i] = new wxStaticBitmap(m_pRightInStatus[i], wxID_ANY, CreateBitmapDot(), wxPoint(BoxW / 2, BoxH / 2), wxDefaultSize);
m_pRightOutStatus[i] = new wxPanel(m_Controller[i], wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_bmpSquareRightOut[i] = new wxStaticBitmap(m_pRightOutStatus[i], wxID_ANY, CreateBitmap(), wxDefaultPosition, wxDefaultSize);
m_bmpDotRightOut[i] = new wxStaticBitmap(m_pRightOutStatus[i], wxID_ANY, CreateBitmapDot(), wxPoint(BoxW / 2, BoxH / 2), wxDefaultSize);
// Sizers
m_sGridStickLeft[i] = new wxGridBagSizer(0, 0);
m_sGridStickLeft[i]->Add(m_pLeftInStatus[i], wxGBPosition(0, 0), wxGBSpan(1, 1), wxALL, 0);
m_sGridStickLeft[i]->Add(m_pLeftOutStatus[i], wxGBPosition(0, 1), wxGBSpan(1, 1), wxLEFT, 10);
m_sGridStickLeft[i]->Add(m_tStatusLeftIn[i], wxGBPosition(1, 0), wxGBSpan(1, 1), wxALL, 0);
m_sGridStickLeft[i]->Add(m_tStatusLeftOut[i], wxGBPosition(1, 1), wxGBSpan(1, 1), wxLEFT, 10);
m_sGridStickRight[i] = new wxGridBagSizer(0, 0);
m_sGridStickRight[i]->Add(m_pRightInStatus[i], wxGBPosition(0, 0), wxGBSpan(1, 1), wxALL, 0);
m_sGridStickRight[i]->Add(m_pRightOutStatus[i], wxGBPosition(0, 1), wxGBSpan(1, 1), wxLEFT, 10);
m_sGridStickRight[i]->Add(m_tStatusRightIn[i], wxGBPosition(1, 0), wxGBSpan(1, 1), wxALL, 0);
m_sGridStickRight[i]->Add(m_tStatusRightOut[i], wxGBPosition(1, 1), wxGBSpan(1, 1), wxLEFT, 10);
m_gStickLeft[i] = new wxStaticBoxSizer (wxHORIZONTAL, m_Controller[i], wxT("Analog 1 Status (In) (Out)"));
m_gStickLeft[i]->Add(m_sGridStickLeft[i], 0, (wxLEFT | wxRIGHT), 5);
m_gStickRight[i] = new wxStaticBoxSizer (wxHORIZONTAL, m_Controller[i], wxT("Analog 2 Status (In) (Out)"));
m_gStickRight[i]->Add(m_sGridStickRight[i], 0, (wxLEFT | wxRIGHT), 5);
// Trigger Status Panels
m_TriggerL[i]= new wxStaticText(m_Controller[i], wxID_ANY, wxT("Left: "));
m_TriggerR[i]= new wxStaticText(m_Controller[i], wxID_ANY, wxT("Right: "));
m_TriggerStatusL[i]= new wxStaticText(m_Controller[i], wxID_ANY, wxT("000"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
m_TriggerStatusR[i]= new wxStaticText(m_Controller[i], wxID_ANY, wxT("000"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
m_tTriggerSource[i]= new wxStaticText(m_Controller[i], wxID_ANY, wxT("Trigger Source"));
m_TriggerType[i] = new wxChoice(m_Controller[i], IDC_TRIGGER_TYPE, wxDefaultPosition, wxSize(70, -1), StrTriggerType, 0, wxDefaultValidator, StrTriggerType[0]);
// Sizers
m_sGridTrigger[i] = new wxGridBagSizer(0, 0);
m_sGridTrigger[i]->Add(m_TriggerL[i], wxGBPosition(0, 0), wxGBSpan(1, 1), (wxTOP), 4);
m_sGridTrigger[i]->Add(m_TriggerStatusL[i], wxGBPosition(0, 1), wxGBSpan(1, 1), (wxLEFT | wxTOP), 4);
m_sGridTrigger[i]->Add(m_TriggerR[i], wxGBPosition(1, 0), wxGBSpan(1, 1), (wxTOP), 4);
m_sGridTrigger[i]->Add(m_TriggerStatusR[i], wxGBPosition(1, 1), wxGBSpan(1, 1), (wxLEFT | wxTOP), 4);
m_gTriggers[i] = new wxStaticBoxSizer (wxVERTICAL, m_Controller[i], wxT("Triggers Status"));
m_gTriggers[i]->AddStretchSpacer();
m_gTriggers[i]->Add(m_sGridTrigger[i], 0, wxEXPAND | (wxLEFT | wxRIGHT), 5);
m_gTriggers[i]->Add(m_tTriggerSource[i], 0, wxEXPAND | (wxUP | wxLEFT | wxRIGHT), 5);
m_gTriggers[i]->Add(m_TriggerType[i], 0, wxEXPAND | (wxUP | wxLEFT | wxRIGHT), 5);
m_gTriggers[i]->AddStretchSpacer();
// Row 2 Sizers: Analog status
m_sHorizStatus[i] = new wxBoxSizer(wxHORIZONTAL);
m_sHorizStatus[i]->Add(m_gStickLeft[i], 0, wxEXPAND | (wxLEFT), 5);
m_sHorizStatus[i]->Add(m_gStickRight[i], 0, wxEXPAND | (wxLEFT), 5);
m_sHorizStatus[i]->Add(m_gTriggers[i], 0, wxEXPAND | (wxLEFT), 5);
// Analog Axes and Triggers Mapping
m_sAnalogLeft[i] = new wxBoxSizer(wxVERTICAL);
m_sAnalogMiddle[i] = new wxBoxSizer(wxVERTICAL);
m_sAnalogRight[i] = new wxBoxSizer(wxVERTICAL);
for (int x = 0; x < 6; x++)
{
m_Text_Analog[x][i] = new wxStaticText(m_Controller[i], wxID_ANY, anText[x]);
m_Button_Analog[x][i] = new wxButton(m_Controller[i], x + IDB_ANALOG_LEFT_X, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
m_Button_Analog[x][i]->SetFont(m_SmallFont);
m_Sizer_Analog[x][i] = new wxBoxSizer(wxHORIZONTAL);
m_Sizer_Analog[x][i]->Add(m_Text_Analog[x][i], 0, (wxUP), 4);
m_Sizer_Analog[x][i]->Add(m_Button_Analog[x][i], 0, (wxLEFT), 2);
if (x < 2) // Make some balance
m_sAnalogLeft[i]->Add(m_Sizer_Analog[x][i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
else if (x < 4)
m_sAnalogMiddle[i]->Add(m_Sizer_Analog[x][i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
else
m_sAnalogRight[i]->Add(m_Sizer_Analog[x][i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
}
m_gAnalog[i] = new wxStaticBoxSizer (wxHORIZONTAL, m_Controller[i], wxT("Analog Axes and Triggers"));
m_gAnalog[i]->Add(m_sAnalogLeft[i], 0, wxALIGN_RIGHT | (wxALL), 0);
m_gAnalog[i]->Add(m_sAnalogMiddle[i], 0, wxALIGN_RIGHT | (wxLEFT), 5);
m_gAnalog[i]->Add(m_sAnalogRight[i], 0, wxALIGN_RIGHT | (wxLEFT), 5);
// Row 3 Sizes: Analog Mapping
m_sHorizAnalog[i] = new wxBoxSizer(wxHORIZONTAL);
m_sHorizAnalog[i]->Add(m_gAnalog[i], 0, (wxLEFT), 5);
// Pad Mapping
m_gButton[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("Buttons"));
m_gDPad[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("D-Pad"));
m_gStick[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("Main Stick"));
m_Text_StickSrc[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Source"));
m_Combo_StickSrc[i] = new wxChoice(m_Controller[i], IDC_STICK_SOURCE, wxDefaultPosition, wxSize(70, -1), StrSource, 0, wxDefaultValidator, StrSource[0]);
m_sStickSrc[i] = new wxBoxSizer(wxHORIZONTAL);
m_sStickSrc[i]->Add(m_Text_StickSrc[i], 0, (wxUP), 4);
m_sStickSrc[i]->Add(m_Combo_StickSrc[i], 0, (wxLEFT), 2);
m_gStick[i]->Add(m_sStickSrc[i], 0, wxALIGN_RIGHT | (wxALL), 2);
m_gStick[i]->AddSpacer(2);
m_gCStick[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("C-Stick"));
m_Text_CStickSrc[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Source"));
m_Combo_CStickSrc[i] = new wxChoice(m_Controller[i], IDC_CSTICK_SOURCE, wxDefaultPosition, wxSize(70, -1), StrSource, 0, wxDefaultValidator, StrSource[0]);
m_sCStickSrc[i] = new wxBoxSizer(wxHORIZONTAL);
m_sCStickSrc[i]->Add(m_Text_CStickSrc[i], 0, (wxUP), 4);
m_sCStickSrc[i]->Add(m_Combo_CStickSrc[i], 0, (wxLEFT), 2);
m_gCStick[i]->Add(m_sCStickSrc[i], 0, wxALIGN_RIGHT | (wxALL), 2);
m_gCStick[i]->AddSpacer(2);
m_gTrigger[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("Triggers"));
m_Text_TriggerSrc[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Source"));
m_Combo_TriggerSrc[i] = new wxChoice(m_Controller[i], IDC_TRIGGER_SOURCE, wxDefaultPosition, wxSize(70, -1), StrSource, 0, wxDefaultValidator, StrSource[0]);
m_sTriggerSrc[i] = new wxBoxSizer(wxHORIZONTAL);
m_sTriggerSrc[i]->Add(m_Text_TriggerSrc[i], 0, (wxUP), 4);
m_sTriggerSrc[i]->Add(m_Combo_TriggerSrc[i], 0, (wxLEFT), 2);
m_gTrigger[i]->Add(m_sTriggerSrc[i], 0, wxALIGN_RIGHT | (wxALL), 2);
m_gTrigger[i]->AddSpacer(2);
for (int x = 0; x <= IDB_SHDR_SEMI_R - IDB_BTN_A; x++)
{
m_Text_Pad[x][i] = new wxStaticText(m_Controller[i], wxID_ANY, padText[x]);
m_Button_GC[x][i] = new wxButton(m_Controller[i], x + IDB_BTN_A, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
m_Button_GC[x][i]->SetFont(m_SmallFont);
m_Sizer_Pad[x][i] = new wxBoxSizer(wxHORIZONTAL);
m_Sizer_Pad[x][i]->Add(m_Text_Pad[x][i], 0, (wxUP), 4);
m_Sizer_Pad[x][i]->Add(m_Button_GC[x][i], 0, (wxLEFT), 2);
if (x <= IDB_BTN_START)
m_gButton[i]->Add(m_Sizer_Pad[x - IDB_BTN_A][i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
else if (x <= IDB_DPAD_RIGHT)
m_gDPad[i]->Add(m_Sizer_Pad[x - IDB_BTN_A][i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
else if (x <= IDB_MAIN_SEMI)
m_gStick[i]->Add(m_Sizer_Pad[x - IDB_BTN_A][i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
else if (x <= IDB_SUB_SEMI)
m_gCStick[i]->Add(m_Sizer_Pad[x - IDB_BTN_A][i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
else
m_gTrigger[i]->Add(m_Sizer_Pad[x - IDB_BTN_A][i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
}
m_Slider_Stick[i] = new wxSlider(m_Controller[i], IDS_STICK_PRESS, DEF_STICK_HALF, 0, DEF_STICK_FULL, wxDefaultPosition, wxSize(100,-1), wxSL_LABELS | wxSL_TOP);
m_gStick[i]->Add(m_Slider_Stick[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
m_Slider_CStick[i] = new wxSlider(m_Controller[i], IDS_CSTICK_PRESS, DEF_STICK_HALF, 0, DEF_STICK_FULL, wxDefaultPosition, wxSize(100,-1), wxSL_LABELS | wxSL_TOP);
m_gCStick[i]->Add(m_Slider_CStick[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
m_Slider_Trigger[i] = new wxSlider(m_Controller[i], IDS_TRIGGER_PRESS, DEF_TRIGGER_HALF, 0, DEF_TRIGGER_FULL, wxDefaultPosition, wxSize(100,-1), wxSL_LABELS | wxSL_TOP);
m_gTrigger[i]->Add(m_Slider_Trigger[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
// Row 4 Sizers: Button Mapping
m_sHorizMapping[i] = new wxBoxSizer(wxHORIZONTAL);
m_sHorizMapping[i]->Add(m_gButton[i], 0, (wxLEFT), 5);
m_sHorizMapping[i]->Add(m_gDPad[i], 0, (wxLEFT), 5);
m_sHorizMapping[i]->Add(m_gStick[i], 0, (wxLEFT), 5);
m_sHorizMapping[i]->Add(m_gCStick[i], 0, (wxLEFT), 5);
m_sHorizMapping[i]->Add(m_gTrigger[i], 0, (wxLEFT), 5);
// Set up sizers and layout
// The sizer m_sMain will be expanded inside m_Controller
m_sMain[i] = new wxBoxSizer(wxVERTICAL);
m_sMain[i]->Add(m_sHorizJoypad[i], 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5);
m_sMain[i]->Add(m_sHorizStatus[i], 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5);
m_sMain[i]->Add(m_sHorizAnalog[i], 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5);
m_sMain[i]->Add(m_sHorizMapping[i], 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5);
// Set the main sizer
m_Controller[i]->SetSizer(m_sMain[i]);
}
m_OK = new wxButton(this, wxID_OK, wxT("OK"));
m_OK->SetToolTip(wxT("Save changes and close"));
m_Cancel = new wxButton(this, wxID_CANCEL, wxT("Cancel"));
m_Cancel->SetToolTip(wxT("Discard changes and close"));
wxBoxSizer* m_DlgButton = new wxBoxSizer(wxHORIZONTAL);
m_DlgButton->AddStretchSpacer();
m_DlgButton->Add(m_OK, 0, (wxLEFT), 5);
m_DlgButton->Add(m_Cancel, 0, (wxLEFT), 5);
m_MainSizer = new wxBoxSizer(wxVERTICAL);
m_MainSizer->Add(m_Notebook, 1, wxEXPAND | wxALL, 5);
m_MainSizer->Add(m_DlgButton, 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5);
SetSizer(m_MainSizer);
Layout();
Fit();
// Center the window if there is room for it
#ifdef _WIN32
if (GetSystemMetrics(SM_CYFULLSCREEN) > 600)
Center();
#endif
m_ControlsCreated = true;
}
// Bitmap box and dot
wxBitmap GCPadConfigDialog::CreateBitmap()
{
BoxW = 70, BoxH = 70;
wxBitmap bitmap(BoxW, BoxH);
wxMemoryDC dc;
dc.SelectObject(bitmap);
// Set outline and fill colors
wxPen LightBluePen(_T("#7f9db9")); // Windows XP color
dc.SetPen(LightBluePen);
dc.SetBrush(*wxWHITE_BRUSH);
dc.Clear();
dc.DrawRectangle(0, 0, BoxW, BoxH);
dc.SelectObject(wxNullBitmap);
return bitmap;
}
wxBitmap GCPadConfigDialog::CreateBitmapDot()
{
int w = 2, h = 2;
wxBitmap bitmap(w, h);
wxMemoryDC dc;
dc.SelectObject(bitmap);
// Set outline and fill colors
dc.SetPen(*wxRED_PEN);
dc.SetBrush(*wxRED_BRUSH);
dc.Clear();
dc.DrawRectangle(0, 0, w, h);
dc.SelectObject(wxNullBitmap);
return bitmap;
}
wxBitmap GCPadConfigDialog::CreateBitmapDeadZone(int Radius)
{
wxBitmap bitmap(Radius*2, Radius*2);
wxMemoryDC dc;
dc.SelectObject(bitmap);
// Set outline and fill colors
dc.SetPen(*wxLIGHT_GREY_PEN);
dc.SetBrush(*wxLIGHT_GREY_BRUSH);
//dc.SetBackground(*wxGREEN_BRUSH);
dc.Clear();
dc.DrawCircle(Radius, Radius, Radius);
dc.SelectObject(wxNullBitmap);
return bitmap;
}
wxBitmap GCPadConfigDialog::CreateBitmapClear()
{
wxBitmap bitmap(BoxW, BoxH);
wxMemoryDC dc;
dc.SelectObject(bitmap);
dc.Clear();
dc.SelectObject(wxNullBitmap);
return bitmap;
}